Init
This commit is contained in:
28
usr.etc/in.ftpd/Makefile
Normal file
28
usr.etc/in.ftpd/Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# @(#)Makefile 1.1 94/10/31 SMI; from UCB 4.2 06/12/83
|
||||
#
|
||||
BINS= in.ftpd
|
||||
OBJS= ftpd.o ftpcmd.o glob.o popen.o logwtmp.o vers.o
|
||||
SRCS= ftpd.c ftpcmd.y ../../ucb/ftp/glob.c popen.c logwtmp.c vers.c
|
||||
|
||||
CFLAGS= -O
|
||||
|
||||
.KEEP_STATE:
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
$(BINS) : $(OBJS)
|
||||
$(LINK.c) -o $@ $(OBJS)
|
||||
|
||||
glob.o : ../../ucb/ftp/glob.c
|
||||
$(COMPILE.c) ../../ucb/ftp/glob.c
|
||||
|
||||
install: $(BINS)
|
||||
install -d $(DESTDIR)/usr/etc
|
||||
install -s $(BINS) $(DESTDIR)/usr/etc
|
||||
|
||||
clean:
|
||||
$(RM) $(BINS) $(OBJS)
|
||||
|
||||
tags: $(SRCS)
|
||||
ctags $(SRCS)
|
||||
882
usr.etc/in.ftpd/ftpcmd.y
Normal file
882
usr.etc/in.ftpd/ftpcmd.y
Normal file
@@ -0,0 +1,882 @@
|
||||
/*
|
||||
* Copyright (c) 1985, 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted
|
||||
* provided that the above copyright notice and this paragraph are
|
||||
* duplicated in all such forms and that any documentation,
|
||||
* advertising materials, and other materials related to such
|
||||
* distribution and use acknowledge that the software was developed
|
||||
* by the University of California, Berkeley. The name of the
|
||||
* University may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grammar for FTP commands.
|
||||
* See RFC 765.
|
||||
*/
|
||||
|
||||
%{
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)ftpcmd.y 1.1 94/10/31 SMI"; /* from UCB 5.16 12/8/88 */
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <arpa/ftp.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <setjmp.h>
|
||||
#include <syslog.h>
|
||||
|
||||
extern struct sockaddr_in data_dest;
|
||||
extern int logged_in;
|
||||
extern struct passwd *pw;
|
||||
extern int guest;
|
||||
extern int logging;
|
||||
extern int type;
|
||||
extern int form;
|
||||
extern int debug;
|
||||
extern int timeout;
|
||||
extern int pdata;
|
||||
extern char hostname[];
|
||||
extern char *globerr;
|
||||
extern int usedefault;
|
||||
extern int transflag;
|
||||
extern char tmpline[];
|
||||
char **glob();
|
||||
|
||||
static int cmd_type;
|
||||
static int cmd_form;
|
||||
static int cmd_bytesz;
|
||||
char cbuf[512];
|
||||
char *fromname;
|
||||
|
||||
char *index();
|
||||
%}
|
||||
|
||||
%token
|
||||
A B C E F I
|
||||
L N P R S T
|
||||
|
||||
SP CRLF COMMA STRING NUMBER
|
||||
|
||||
USER PASS ACCT REIN QUIT PORT
|
||||
PASV TYPE STRU MODE RETR STOR
|
||||
APPE MLFL MAIL MSND MSOM MSAM
|
||||
MRSQ MRCP ALLO REST RNFR RNTO
|
||||
ABOR DELE CWD LIST NLST SITE
|
||||
STAT HELP NOOP XMKD XRMD XPWD
|
||||
XCUP STOU
|
||||
|
||||
LEXERR
|
||||
|
||||
%start cmd_list
|
||||
|
||||
%%
|
||||
|
||||
cmd_list: /* empty */
|
||||
| cmd_list cmd
|
||||
= {
|
||||
fromname = (char *) 0;
|
||||
}
|
||||
| cmd_list rcmd
|
||||
;
|
||||
|
||||
cmd: USER SP username CRLF
|
||||
= {
|
||||
user((char *) $3);
|
||||
free((char *) $3);
|
||||
}
|
||||
| PASS SP password CRLF
|
||||
= {
|
||||
pass((char *) $3);
|
||||
free((char *) $3);
|
||||
}
|
||||
| PORT SP host_port CRLF
|
||||
= {
|
||||
usedefault = 0;
|
||||
if (pdata >= 0) {
|
||||
(void) close(pdata);
|
||||
pdata = -1;
|
||||
}
|
||||
reply(200, "PORT command successful.");
|
||||
}
|
||||
| PASV CRLF
|
||||
= {
|
||||
passive();
|
||||
}
|
||||
| TYPE SP type_code CRLF
|
||||
= {
|
||||
switch (cmd_type) {
|
||||
|
||||
case TYPE_A:
|
||||
if (cmd_form == FORM_N) {
|
||||
reply(200, "Type set to A.");
|
||||
type = cmd_type;
|
||||
form = cmd_form;
|
||||
} else
|
||||
reply(504, "Form must be N.");
|
||||
break;
|
||||
|
||||
case TYPE_E:
|
||||
reply(504, "Type E not implemented.");
|
||||
break;
|
||||
|
||||
case TYPE_I:
|
||||
reply(200, "Type set to I.");
|
||||
type = cmd_type;
|
||||
break;
|
||||
|
||||
case TYPE_L:
|
||||
if (cmd_bytesz == 8) {
|
||||
reply(200,
|
||||
"Type set to L (byte size 8).");
|
||||
type = cmd_type;
|
||||
} else
|
||||
reply(504, "Byte size must be 8.");
|
||||
}
|
||||
}
|
||||
| STRU SP struct_code CRLF
|
||||
= {
|
||||
switch ($3) {
|
||||
|
||||
case STRU_F:
|
||||
reply(200, "STRU F ok.");
|
||||
break;
|
||||
|
||||
default:
|
||||
reply(504, "Unimplemented STRU type.");
|
||||
}
|
||||
}
|
||||
| MODE SP mode_code CRLF
|
||||
= {
|
||||
switch ($3) {
|
||||
|
||||
case MODE_S:
|
||||
reply(200, "MODE S ok.");
|
||||
break;
|
||||
|
||||
default:
|
||||
reply(502, "Unimplemented MODE type.");
|
||||
}
|
||||
}
|
||||
| ALLO SP NUMBER CRLF
|
||||
= {
|
||||
reply(202, "ALLO command ignored.");
|
||||
}
|
||||
| RETR check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
retrieve((char *) 0, (char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| STOR check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
store((char *) $4, "w", 0);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| APPE check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
store((char *) $4, "a", 0);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| NLST check_login CRLF
|
||||
= {
|
||||
if ($2)
|
||||
retrieve("/bin/ls", "");
|
||||
}
|
||||
| NLST check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
retrieve("/bin/ls %s", (char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| LIST check_login CRLF
|
||||
= {
|
||||
if ($2)
|
||||
retrieve("/bin/ls -lg", "");
|
||||
}
|
||||
| LIST check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
retrieve("/bin/ls -lg %s", (char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| DELE check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
delete((char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| RNTO SP pathname CRLF
|
||||
= {
|
||||
if (fromname) {
|
||||
renamecmd(fromname, (char *) $3);
|
||||
free(fromname);
|
||||
fromname = (char *) 0;
|
||||
} else {
|
||||
reply(503, "Bad sequence of commands.");
|
||||
}
|
||||
free((char *) $3);
|
||||
}
|
||||
| ABOR CRLF
|
||||
= {
|
||||
reply(225, "ABOR command successful.");
|
||||
}
|
||||
| CWD check_login CRLF
|
||||
= {
|
||||
if ($2)
|
||||
cwd(pw->pw_dir);
|
||||
}
|
||||
| CWD check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
cwd((char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| HELP CRLF
|
||||
= {
|
||||
help((char *) 0);
|
||||
}
|
||||
| HELP SP STRING CRLF
|
||||
= {
|
||||
help((char *) $3);
|
||||
}
|
||||
| NOOP CRLF
|
||||
= {
|
||||
reply(200, "NOOP command successful.");
|
||||
}
|
||||
| XMKD check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
makedir((char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| XRMD check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
removedir((char *) $4);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| XPWD check_login CRLF
|
||||
= {
|
||||
if ($2)
|
||||
pwd();
|
||||
}
|
||||
| XCUP check_login CRLF
|
||||
= {
|
||||
if ($2)
|
||||
cwd("..");
|
||||
}
|
||||
| STOU check_login SP pathname CRLF
|
||||
= {
|
||||
if ($2 && $4 != NULL)
|
||||
store((char *) $4, "w", 1);
|
||||
if ($4 != NULL)
|
||||
free((char *) $4);
|
||||
}
|
||||
| QUIT CRLF
|
||||
= {
|
||||
reply(221, "Goodbye.");
|
||||
dologout(0);
|
||||
}
|
||||
| error CRLF
|
||||
= {
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
|
||||
rcmd: RNFR check_login SP pathname CRLF
|
||||
= {
|
||||
char *renamefrom();
|
||||
|
||||
if ($2 && $4) {
|
||||
fromname = renamefrom((char *) $4);
|
||||
if (fromname == (char *) 0 && $4) {
|
||||
free((char *) $4);
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
username: STRING
|
||||
;
|
||||
|
||||
password: /* empty */
|
||||
= {
|
||||
$$ = (int) "";
|
||||
}
|
||||
| STRING
|
||||
;
|
||||
|
||||
byte_size: NUMBER
|
||||
;
|
||||
|
||||
host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
|
||||
NUMBER COMMA NUMBER
|
||||
= {
|
||||
register char *a, *p;
|
||||
|
||||
a = (char *)&data_dest.sin_addr;
|
||||
a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
|
||||
p = (char *)&data_dest.sin_port;
|
||||
p[0] = $9; p[1] = $11;
|
||||
data_dest.sin_family = AF_INET;
|
||||
}
|
||||
;
|
||||
|
||||
form_code: N
|
||||
= {
|
||||
$$ = FORM_N;
|
||||
}
|
||||
| T
|
||||
= {
|
||||
$$ = FORM_T;
|
||||
}
|
||||
| C
|
||||
= {
|
||||
$$ = FORM_C;
|
||||
}
|
||||
;
|
||||
|
||||
type_code: A
|
||||
= {
|
||||
cmd_type = TYPE_A;
|
||||
cmd_form = FORM_N;
|
||||
}
|
||||
| A SP form_code
|
||||
= {
|
||||
cmd_type = TYPE_A;
|
||||
cmd_form = $3;
|
||||
}
|
||||
| E
|
||||
= {
|
||||
cmd_type = TYPE_E;
|
||||
cmd_form = FORM_N;
|
||||
}
|
||||
| E SP form_code
|
||||
= {
|
||||
cmd_type = TYPE_E;
|
||||
cmd_form = $3;
|
||||
}
|
||||
| I
|
||||
= {
|
||||
cmd_type = TYPE_I;
|
||||
}
|
||||
| L
|
||||
= {
|
||||
cmd_type = TYPE_L;
|
||||
cmd_bytesz = 8;
|
||||
}
|
||||
| L SP byte_size
|
||||
= {
|
||||
cmd_type = TYPE_L;
|
||||
cmd_bytesz = $3;
|
||||
}
|
||||
/* this is for a bug in the BBN ftp */
|
||||
| L byte_size
|
||||
= {
|
||||
cmd_type = TYPE_L;
|
||||
cmd_bytesz = $2;
|
||||
}
|
||||
;
|
||||
|
||||
struct_code: F
|
||||
= {
|
||||
$$ = STRU_F;
|
||||
}
|
||||
| R
|
||||
= {
|
||||
$$ = STRU_R;
|
||||
}
|
||||
| P
|
||||
= {
|
||||
$$ = STRU_P;
|
||||
}
|
||||
;
|
||||
|
||||
mode_code: S
|
||||
= {
|
||||
$$ = MODE_S;
|
||||
}
|
||||
| B
|
||||
= {
|
||||
$$ = MODE_B;
|
||||
}
|
||||
| C
|
||||
= {
|
||||
$$ = MODE_C;
|
||||
}
|
||||
;
|
||||
|
||||
pathname: pathstring
|
||||
= {
|
||||
/*
|
||||
* Problem: this production is used for all pathname
|
||||
* processing, but only gives a 550 error reply.
|
||||
* This is a valid reply in some cases but not in others.
|
||||
*/
|
||||
if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) {
|
||||
$$ = (int)*glob((char *) $1);
|
||||
if (globerr != NULL) {
|
||||
reply(550, globerr);
|
||||
$$ = NULL;
|
||||
}
|
||||
free((char *) $1);
|
||||
} else
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
pathstring: STRING
|
||||
;
|
||||
|
||||
check_login: /* empty */
|
||||
= {
|
||||
if (logged_in)
|
||||
$$ = 1;
|
||||
else {
|
||||
reply(530, "Please login with USER and PASS.");
|
||||
$$ = 0;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
extern jmp_buf errcatch;
|
||||
|
||||
#define CMD 0 /* beginning of command */
|
||||
#define ARGS 1 /* expect miscellaneous arguments */
|
||||
#define STR1 2 /* expect SP followed by STRING */
|
||||
#define STR2 3 /* expect STRING */
|
||||
#define OSTR 4 /* optional SP then STRING */
|
||||
#define ZSTR1 5 /* SP then optional STRING */
|
||||
#define ZSTR2 6 /* optional STRING after SP */
|
||||
|
||||
struct tab {
|
||||
char *name;
|
||||
short token;
|
||||
short state;
|
||||
short implemented; /* 1 if command is implemented */
|
||||
char *help;
|
||||
};
|
||||
|
||||
struct tab cmdtab[] = { /* In order defined in RFC 765 */
|
||||
{ "USER", USER, STR1, 1, "<sp> username" },
|
||||
{ "PASS", PASS, ZSTR1, 1, "<sp> password" },
|
||||
{ "ACCT", ACCT, STR1, 0, "(specify account)" },
|
||||
{ "REIN", REIN, ARGS, 0, "(reinitialize server state)" },
|
||||
{ "QUIT", QUIT, ARGS, 1, "(terminate service)", },
|
||||
{ "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
|
||||
{ "PASV", PASV, ARGS, 1, "(set server in passive mode)" },
|
||||
{ "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
|
||||
{ "STRU", STRU, ARGS, 1, "(specify file structure)" },
|
||||
{ "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
|
||||
{ "RETR", RETR, STR1, 1, "<sp> file-name" },
|
||||
{ "STOR", STOR, STR1, 1, "<sp> file-name" },
|
||||
{ "APPE", APPE, STR1, 1, "<sp> file-name" },
|
||||
{ "MLFL", MLFL, OSTR, 0, "(mail file)" },
|
||||
{ "MAIL", MAIL, OSTR, 0, "(mail to user)" },
|
||||
{ "MSND", MSND, OSTR, 0, "(mail send to terminal)" },
|
||||
{ "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" },
|
||||
{ "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" },
|
||||
{ "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" },
|
||||
{ "MRCP", MRCP, STR1, 0, "(mail recipient)" },
|
||||
{ "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" },
|
||||
{ "REST", REST, STR1, 0, "(restart command)" },
|
||||
{ "RNFR", RNFR, STR1, 1, "<sp> file-name" },
|
||||
{ "RNTO", RNTO, STR1, 1, "<sp> file-name" },
|
||||
{ "ABOR", ABOR, ARGS, 1, "(abort operation)" },
|
||||
{ "DELE", DELE, STR1, 1, "<sp> file-name" },
|
||||
{ "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
|
||||
{ "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
|
||||
{ "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" },
|
||||
{ "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" },
|
||||
{ "SITE", SITE, STR1, 0, "(get site parameters)" },
|
||||
{ "STAT", STAT, OSTR, 0, "(get server status)" },
|
||||
{ "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
|
||||
{ "NOOP", NOOP, ARGS, 1, "" },
|
||||
{ "MKD", XMKD, STR1, 1, "<sp> path-name" },
|
||||
{ "XMKD", XMKD, STR1, 1, "<sp> path-name" },
|
||||
{ "RMD", XRMD, STR1, 1, "<sp> path-name" },
|
||||
{ "XRMD", XRMD, STR1, 1, "<sp> path-name" },
|
||||
{ "PWD", XPWD, ARGS, 1, "(return current directory)" },
|
||||
{ "XPWD", XPWD, ARGS, 1, "(return current directory)" },
|
||||
{ "CDUP", XCUP, ARGS, 1, "(change to parent directory)" },
|
||||
{ "XCUP", XCUP, ARGS, 1, "(change to parent directory)" },
|
||||
{ "STOU", STOU, STR1, 1, "<sp> file-name" },
|
||||
{ NULL, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct tab *
|
||||
lookup(cmd)
|
||||
char *cmd;
|
||||
{
|
||||
register struct tab *p;
|
||||
|
||||
for (p = cmdtab; p->name != NULL; p++)
|
||||
if (strcmp(cmd, p->name) == 0)
|
||||
return (p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#include <arpa/telnet.h>
|
||||
|
||||
/*
|
||||
* getline - a hacked up version of fgets to ignore TELNET escape codes.
|
||||
*/
|
||||
char *
|
||||
getline(s, n, iop)
|
||||
char *s;
|
||||
register FILE *iop;
|
||||
{
|
||||
register c;
|
||||
register char *cs;
|
||||
|
||||
cs = s;
|
||||
/* tmpline may contain saved command from urgent mode interruption */
|
||||
for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
|
||||
*cs++ = tmpline[c];
|
||||
if (tmpline[c] == '\n') {
|
||||
*cs++ = '\0';
|
||||
if (debug)
|
||||
{
|
||||
if (strncasecmp(s, "PASS", 4) || guest)
|
||||
syslog(LOG_DEBUG, "command: %s", s);
|
||||
else
|
||||
syslog(LOG_DEBUG, "command: PASS <password>");
|
||||
}
|
||||
tmpline[0] = '\0';
|
||||
return(s);
|
||||
}
|
||||
if (c == 0)
|
||||
tmpline[0] = '\0';
|
||||
}
|
||||
while ((c = getc(iop)) != EOF) {
|
||||
c &= 0377;
|
||||
if (c == IAC) {
|
||||
if ((c = getc(iop)) != EOF) {
|
||||
c &= 0377;
|
||||
switch (c) {
|
||||
case WILL:
|
||||
case WONT:
|
||||
c = getc(iop);
|
||||
printf("%c%c%c", IAC, DONT, 0377&c);
|
||||
(void) fflush(stdout);
|
||||
continue;
|
||||
case DO:
|
||||
case DONT:
|
||||
c = getc(iop);
|
||||
printf("%c%c%c", IAC, WONT, 0377&c);
|
||||
(void) fflush(stdout);
|
||||
continue;
|
||||
case IAC:
|
||||
break;
|
||||
default:
|
||||
continue; /* ignore command */
|
||||
}
|
||||
}
|
||||
}
|
||||
*cs++ = c;
|
||||
if (--n <= 0 || c == '\n')
|
||||
break;
|
||||
}
|
||||
if (c == EOF && cs == s)
|
||||
return (NULL);
|
||||
*cs++ = '\0';
|
||||
if (debug)
|
||||
{
|
||||
/* Don't print passwords */
|
||||
if (strncasecmp(s, "PASS", 4) || guest)
|
||||
syslog(LOG_DEBUG, "command: %s", s);
|
||||
else
|
||||
syslog(LOG_DEBUG, "command: PASS <password>");
|
||||
}
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
static int
|
||||
toolong()
|
||||
{
|
||||
time_t now;
|
||||
extern char *ctime();
|
||||
extern time_t time();
|
||||
|
||||
reply(421,
|
||||
"Timeout (%d seconds): closing control connection.", timeout);
|
||||
(void) time(&now);
|
||||
if (logging) {
|
||||
syslog(LOG_INFO,
|
||||
"User %s timed out after %d seconds at %s",
|
||||
(pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
|
||||
}
|
||||
dologout(1);
|
||||
}
|
||||
|
||||
yylex()
|
||||
{
|
||||
static int cpos, state;
|
||||
register char *cp;
|
||||
register struct tab *p;
|
||||
int n;
|
||||
char c, *strpbrk();
|
||||
|
||||
for (;;) {
|
||||
switch (state) {
|
||||
|
||||
case CMD:
|
||||
(void) signal(SIGALRM, toolong);
|
||||
(void) alarm((unsigned) timeout);
|
||||
if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
|
||||
reply(221, "You could at least say goodbye.");
|
||||
dologout(0);
|
||||
}
|
||||
(void) alarm(0);
|
||||
if ((cp = index(cbuf, '\r'))) {
|
||||
*cp++ = '\n';
|
||||
*cp = '\0';
|
||||
}
|
||||
if ((cp = strpbrk(cbuf, " \n")))
|
||||
cpos = cp - cbuf;
|
||||
if (cpos == 0)
|
||||
cpos = 4;
|
||||
c = cbuf[cpos];
|
||||
cbuf[cpos] = '\0';
|
||||
upper(cbuf);
|
||||
p = lookup(cbuf);
|
||||
cbuf[cpos] = c;
|
||||
if (p != 0) {
|
||||
if (p->implemented == 0) {
|
||||
nack(p->name);
|
||||
longjmp(errcatch,0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
state = p->state;
|
||||
yylval = (int) p->name;
|
||||
return (p->token);
|
||||
}
|
||||
break;
|
||||
|
||||
case OSTR:
|
||||
if (cbuf[cpos] == '\n') {
|
||||
state = CMD;
|
||||
return (CRLF);
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case STR1:
|
||||
case ZSTR1:
|
||||
if (cbuf[cpos] == ' ') {
|
||||
cpos++;
|
||||
state = state == OSTR ? STR2 : ++state;
|
||||
return (SP);
|
||||
}
|
||||
break;
|
||||
|
||||
case ZSTR2:
|
||||
if (cbuf[cpos] == '\n') {
|
||||
state = CMD;
|
||||
return (CRLF);
|
||||
}
|
||||
/* FALL THRU */
|
||||
|
||||
case STR2:
|
||||
cp = &cbuf[cpos];
|
||||
n = strlen(cp);
|
||||
cpos += n - 1;
|
||||
/*
|
||||
* Make sure the string is nonempty and \n terminated.
|
||||
*/
|
||||
if (n > 1 && cbuf[cpos] == '\n') {
|
||||
cbuf[cpos] = '\0';
|
||||
yylval = copy(cp);
|
||||
cbuf[cpos] = '\n';
|
||||
state = ARGS;
|
||||
return (STRING);
|
||||
}
|
||||
break;
|
||||
|
||||
case ARGS:
|
||||
if (isdigit(cbuf[cpos])) {
|
||||
cp = &cbuf[cpos];
|
||||
while (isdigit(cbuf[++cpos]))
|
||||
;
|
||||
c = cbuf[cpos];
|
||||
cbuf[cpos] = '\0';
|
||||
yylval = atoi(cp);
|
||||
cbuf[cpos] = c;
|
||||
return (NUMBER);
|
||||
}
|
||||
switch (cbuf[cpos++]) {
|
||||
|
||||
case '\n':
|
||||
state = CMD;
|
||||
return (CRLF);
|
||||
|
||||
case ' ':
|
||||
return (SP);
|
||||
|
||||
case ',':
|
||||
return (COMMA);
|
||||
|
||||
case 'A':
|
||||
case 'a':
|
||||
return (A);
|
||||
|
||||
case 'B':
|
||||
case 'b':
|
||||
return (B);
|
||||
|
||||
case 'C':
|
||||
case 'c':
|
||||
return (C);
|
||||
|
||||
case 'E':
|
||||
case 'e':
|
||||
return (E);
|
||||
|
||||
case 'F':
|
||||
case 'f':
|
||||
return (F);
|
||||
|
||||
case 'I':
|
||||
case 'i':
|
||||
return (I);
|
||||
|
||||
case 'L':
|
||||
case 'l':
|
||||
return (L);
|
||||
|
||||
case 'N':
|
||||
case 'n':
|
||||
return (N);
|
||||
|
||||
case 'P':
|
||||
case 'p':
|
||||
return (P);
|
||||
|
||||
case 'R':
|
||||
case 'r':
|
||||
return (R);
|
||||
|
||||
case 'S':
|
||||
case 's':
|
||||
return (S);
|
||||
|
||||
case 'T':
|
||||
case 't':
|
||||
return (T);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unknown state in scanner.");
|
||||
}
|
||||
yyerror((char *) 0);
|
||||
state = CMD;
|
||||
longjmp(errcatch,0);
|
||||
}
|
||||
}
|
||||
|
||||
upper(s)
|
||||
register char *s;
|
||||
{
|
||||
while (*s != '\0') {
|
||||
if (islower(*s))
|
||||
*s = toupper(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
copy(s)
|
||||
char *s;
|
||||
{
|
||||
char *p;
|
||||
extern char *malloc(), *strcpy();
|
||||
|
||||
p = malloc((unsigned) strlen(s) + 1);
|
||||
if (p == NULL)
|
||||
fatal("Ran out of memory.");
|
||||
(void) strcpy(p, s);
|
||||
return ((int)p);
|
||||
}
|
||||
|
||||
help(s)
|
||||
char *s;
|
||||
{
|
||||
register struct tab *c;
|
||||
register int width, NCMDS;
|
||||
|
||||
width = 0, NCMDS = 0;
|
||||
for (c = cmdtab; c->name != NULL; c++) {
|
||||
int len = strlen(c->name) + 1;
|
||||
|
||||
if (len > width)
|
||||
width = len;
|
||||
NCMDS++;
|
||||
}
|
||||
width = (width + 8) &~ 7;
|
||||
if (s == 0) {
|
||||
register int i, j, w;
|
||||
int columns, lines;
|
||||
|
||||
lreply(214,
|
||||
"The following commands are recognized (* =>'s unimplemented).");
|
||||
columns = 76 / width;
|
||||
if (columns == 0)
|
||||
columns = 1;
|
||||
lines = (NCMDS + columns - 1) / columns;
|
||||
for (i = 0; i < lines; i++) {
|
||||
printf(" ");
|
||||
for (j = 0; j < columns; j++) {
|
||||
c = cmdtab + j * lines + i;
|
||||
printf("%s%c", c->name,
|
||||
c->implemented ? ' ' : '*');
|
||||
if (c + lines >= &cmdtab[NCMDS])
|
||||
break;
|
||||
w = strlen(c->name) + 1;
|
||||
while (w < width) {
|
||||
putchar(' ');
|
||||
w++;
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
(void) fflush(stdout);
|
||||
reply(214, "Direct comments to bugs@Sun.COM.");
|
||||
return;
|
||||
}
|
||||
upper(s);
|
||||
c = lookup(s);
|
||||
if (c == (struct tab *)0) {
|
||||
reply(502, "Unknown command %s.", s);
|
||||
return;
|
||||
}
|
||||
if (c->implemented)
|
||||
reply(214, "Syntax: %s %s", c->name, c->help);
|
||||
else
|
||||
reply(214, "%-*s\t%s; unimplemented.", width, c->name, c->help);
|
||||
}
|
||||
1065
usr.etc/in.ftpd/ftpd.c
Normal file
1065
usr.etc/in.ftpd/ftpd.c
Normal file
File diff suppressed because it is too large
Load Diff
1
usr.etc/in.ftpd/glob.c
Symbolic link
1
usr.etc/in.ftpd/glob.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../ucb/ftp/glob.c
|
||||
53
usr.etc/in.ftpd/logwtmp.c
Normal file
53
usr.etc/in.ftpd/logwtmp.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 1988 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted
|
||||
* provided that the above copyright notice and this paragraph are
|
||||
* duplicated in all such forms and that any documentation,
|
||||
* advertising materials, and other materials related to such
|
||||
* distribution and use acknowledge that the software was developed
|
||||
* by the University of California, Berkeley. The name of the
|
||||
* University may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)logwtmp.c 1.1 94/10/31 SMI"; /* from UCB 5.3 12/7/88 */
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#define WTMPFILE "/var/adm/wtmp"
|
||||
|
||||
static int fd = -1;
|
||||
|
||||
/*
|
||||
* Modified version of logwtmp that holds wtmp file open
|
||||
* after first call, for use with ftp (which may chroot
|
||||
* after login, but before logout).
|
||||
*/
|
||||
logwtmp(line, name, host)
|
||||
char *line, *name, *host;
|
||||
{
|
||||
struct utmp ut;
|
||||
struct stat buf;
|
||||
time_t time();
|
||||
char *strncpy();
|
||||
|
||||
if (fd < 0 && (fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
|
||||
return;
|
||||
if (fstat(fd, &buf) == 0) {
|
||||
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
|
||||
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
|
||||
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
|
||||
(void)time(&ut.ut_time);
|
||||
if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
|
||||
sizeof(struct utmp))
|
||||
(void)ftruncate(fd, buf.st_size);
|
||||
}
|
||||
}
|
||||
140
usr.etc/in.ftpd/popen.c
Normal file
140
usr.etc/in.ftpd/popen.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 1988 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software written by Ken Arnold and
|
||||
* published in UNIX Review, Vol. 6, No. 8.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted
|
||||
* provided that the above copyright notice and this paragraph are
|
||||
* duplicated in all such forms and that any documentation,
|
||||
* advertising materials, and other materials related to such
|
||||
* distribution and use acknowledge that the software was developed
|
||||
* by the University of California, Berkeley. The name of the
|
||||
* University may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)popen.c 1.1 94/10/31 SMI"; /* from UCB 5.4 12/7/88 */
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* Special version of popen which avoids call to shell. This insures noone
|
||||
* may create a pipe to a hidden program as a side effect of a list or dir
|
||||
* command.
|
||||
*/
|
||||
static int *pids;
|
||||
static int fds;
|
||||
|
||||
FILE *
|
||||
ftpd_popen(program, type)
|
||||
char *program, *type;
|
||||
{
|
||||
register char *cp;
|
||||
FILE *iop;
|
||||
int argc, gargc, pdes[2], pid;
|
||||
char **pop, *argv[100], *gargv[1000], *vv[2];
|
||||
extern char **glob(), **copyblk(), *strtok(), *malloc();
|
||||
|
||||
if (*type != 'r' && *type != 'w' || type[1])
|
||||
return(NULL);
|
||||
|
||||
if (!pids) {
|
||||
if ((fds = getdtablesize()) <= 0)
|
||||
return(NULL);
|
||||
if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
|
||||
return(NULL);
|
||||
bzero((char *)pids, fds * sizeof(int));
|
||||
}
|
||||
if (pipe(pdes) < 0)
|
||||
return(NULL);
|
||||
|
||||
/* break up string into pieces */
|
||||
for (argc = 0, cp = program;; cp = NULL)
|
||||
if (!(argv[argc++] = strtok(cp, " \t\n")))
|
||||
break;
|
||||
|
||||
/* glob each piece */
|
||||
gargv[0] = argv[0];
|
||||
for (gargc = argc = 1; argv[argc]; argc++) {
|
||||
if (!(pop = glob(argv[argc]))) { /* globbing failed */
|
||||
vv[0] = argv[argc];
|
||||
vv[1] = NULL;
|
||||
pop = copyblk(vv);
|
||||
}
|
||||
argv[argc] = (char *)pop; /* save to free later */
|
||||
while (*pop && gargc < 1000)
|
||||
gargv[gargc++] = *pop++;
|
||||
}
|
||||
gargv[gargc] = NULL;
|
||||
|
||||
iop = NULL;
|
||||
switch(pid = vfork()) {
|
||||
case -1: /* error */
|
||||
(void)close(pdes[0]);
|
||||
(void)close(pdes[1]);
|
||||
goto free;
|
||||
/* NOTREACHED */
|
||||
case 0: /* child */
|
||||
if (*type == 'r') {
|
||||
if (pdes[1] != 1) {
|
||||
/*
|
||||
* Need to grab stderr too for new ls
|
||||
*/
|
||||
dup2(pdes[1], 2);
|
||||
dup2(pdes[1], 1);
|
||||
(void)close(pdes[1]);
|
||||
}
|
||||
(void)close(pdes[0]);
|
||||
} else {
|
||||
if (pdes[0] != 0) {
|
||||
dup2(pdes[0], 0);
|
||||
(void)close(pdes[0]);
|
||||
}
|
||||
(void)close(pdes[1]);
|
||||
}
|
||||
execv(gargv[0], gargv);
|
||||
_exit(1);
|
||||
}
|
||||
/* parent; assume fdopen can't fail... */
|
||||
if (*type == 'r') {
|
||||
iop = fdopen(pdes[0], type);
|
||||
(void)close(pdes[1]);
|
||||
} else {
|
||||
iop = fdopen(pdes[1], type);
|
||||
(void)close(pdes[0]);
|
||||
}
|
||||
pids[fileno(iop)] = pid;
|
||||
|
||||
free: for (argc = 1; argv[argc] != NULL; argc++)
|
||||
blkfree((char **)argv[argc]);
|
||||
return(iop);
|
||||
}
|
||||
|
||||
ftpd_pclose(iop)
|
||||
FILE *iop;
|
||||
{
|
||||
register int fdes;
|
||||
int omask;
|
||||
union wait stat_loc;
|
||||
int pid;
|
||||
|
||||
/*
|
||||
* pclose returns -1 if stream is not associated with a
|
||||
* `popened' command, or, if already `pclosed'.
|
||||
*/
|
||||
if (pids == 0 || pids[fdes = fileno(iop)] == 0)
|
||||
return(-1);
|
||||
(void)fclose(iop);
|
||||
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
|
||||
while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
|
||||
(void)sigsetmask(omask);
|
||||
pids[fdes] = 0;
|
||||
return(pid == -1 ? -1 : stat_loc.w_status);
|
||||
}
|
||||
2
usr.etc/in.ftpd/vers.c
Normal file
2
usr.etc/in.ftpd/vers.c
Normal file
@@ -0,0 +1,2 @@
|
||||
/* @(#)vers.c 1.1 94/10/31 SMI */
|
||||
char version[] = "SunOS 4.1";
|
||||
Reference in New Issue
Block a user