Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
Synchronet
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Main
Synchronet
Commits
adacfd7a
Commit
adacfd7a
authored
22 years ago
by
deuce
Browse files
Options
Downloads
Patches
Plain Diff
Added ftp routines to allow future version to fetch release files via FTP.
parent
79af8796
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/sbbs3/install/ftpio.c
+1118
-0
1118 additions, 0 deletions
src/sbbs3/install/ftpio.c
src/sbbs3/install/objects.mk
+2
-1
2 additions, 1 deletion
src/sbbs3/install/objects.mk
with
1120 additions
and
1 deletion
src/sbbs3/install/ftpio.c
0 → 100644
+
1118
−
0
View file @
adacfd7a
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* Major Changelog:
*
* Jordan K. Hubbard
* 17 Jan 1996
*
* Turned inside out. Now returns xfers as new file ids, not as a special
* `state' of FTP_t
*
* $FreeBSD: src/lib/libftpio/ftpio.c,v 1.33.2.4 2002/07/25 15:25:32 ume Exp $
*
*/
#include
<sys/types.h>
#include
<sys/socket.h>
#include
<netinet/in.h>
#include
<arpa/inet.h>
#include
<ctype.h>
#include
<errno.h>
#include
<ftpio.h>
#include
<netdb.h>
#include
<signal.h>
#include
<stdarg.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<unistd.h>
#define SUCCESS 0
#define FAILURE -1
#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
#endif
/* How to see by a given code whether or not the connection has timed out */
#define FTP_TIMEOUT(code) (FtpTimedOut || code == FTP_TIMED_OUT)
/* Internal routines - deal only with internal FTP_t type */
static
FTP_t
ftp_new
(
void
);
static
void
check_passive
(
FILE
*
fp
);
static
int
ftp_read_method
(
void
*
n
,
char
*
buf
,
int
nbytes
);
static
int
ftp_write_method
(
void
*
n
,
const
char
*
buf
,
int
nbytes
);
static
int
ftp_close_method
(
void
*
n
);
static
int
writes
(
int
fd
,
char
*
s
);
static
__inline
char
*
get_a_line
(
FTP_t
ftp
);
static
int
get_a_number
(
FTP_t
ftp
,
char
**
q
);
static
int
botch
(
char
*
func
,
char
*
botch_state
);
static
int
cmd
(
FTP_t
ftp
,
const
char
*
fmt
,
...);
static
int
ftp_login_session
(
FTP_t
ftp
,
char
*
host
,
int
af
,
char
*
user
,
char
*
passwd
,
int
port
,
int
verbose
);
static
int
ftp_file_op
(
FTP_t
ftp
,
char
*
operation
,
char
*
file
,
FILE
**
fp
,
char
*
mode
,
off_t
*
seekto
);
static
int
ftp_close
(
FTP_t
ftp
);
static
int
get_url_info
(
char
*
url_in
,
char
*
host_ret
,
int
*
port_ret
,
char
*
name_ret
);
static
void
ftp_timeout
(
int
sig
);
static
void
ftp_set_timeout
(
void
);
static
void
ftp_clear_timeout
(
void
);
static
void
ai_unmapped
(
struct
addrinfo
*
);
/* Global status variable - ick */
int
FtpTimedOut
;
/* FTP happy status codes */
#define FTP_GENERALLY_HAPPY 200
#define FTP_ASCII_HAPPY FTP_GENERALLY_HAPPY
#define FTP_BINARY_HAPPY FTP_GENERALLY_HAPPY
#define FTP_PORT_HAPPY FTP_GENERALLY_HAPPY
#define FTP_HAPPY_COMMENT 220
#define FTP_QUIT_HAPPY 221
#define FTP_TRANSFER_HAPPY 226
#define FTP_PASSIVE_HAPPY 227
#define FTP_LPASSIVE_HAPPY 228
#define FTP_EPASSIVE_HAPPY 229
#define FTP_CHDIR_HAPPY 250
/* FTP unhappy status codes */
#define FTP_TIMED_OUT 421
/*
* XXX
* gross! evil! bad! We really need an access primitive for cookie in stdio itself.
* it's too convenient a hook to bury and it's already exported through funopen as it is, so...
* XXX
*/
#define fcookie(fp) ((fp)->_cookie)
/* Placeholder in case we want to do any pre-init stuff at some point */
int
networkInit
()
{
return
SUCCESS
;
/* XXX dummy function for now XXX */
}
/* Check a return code with some lenience for back-dated garbage that might be in the buffer */
static
int
check_code
(
FTP_t
ftp
,
int
var
,
int
preferred
)
{
ftp
->
error
=
0
;
while
(
1
)
{
if
(
var
==
preferred
)
return
0
;
else
if
(
var
==
FTP_TRANSFER_HAPPY
)
/* last operation succeeded */
var
=
get_a_number
(
ftp
,
NULL
);
else
if
(
var
==
FTP_HAPPY_COMMENT
)
/* chit-chat */
var
=
get_a_number
(
ftp
,
NULL
);
else
if
(
var
==
FTP_GENERALLY_HAPPY
)
/* general success code */
var
=
get_a_number
(
ftp
,
NULL
);
else
{
ftp
->
error
=
var
;
return
1
;
}
}
}
int
ftpAscii
(
FILE
*
fp
)
{
FTP_t
ftp
=
fcookie
(
fp
);
int
i
;
if
(
!
ftp
->
is_binary
)
return
SUCCESS
;
i
=
cmd
(
ftp
,
"TYPE A"
);
if
(
i
<
0
||
check_code
(
ftp
,
i
,
FTP_ASCII_HAPPY
))
return
i
;
ftp
->
is_binary
=
FALSE
;
return
SUCCESS
;
}
int
ftpBinary
(
FILE
*
fp
)
{
FTP_t
ftp
=
fcookie
(
fp
);
int
i
;
if
(
ftp
->
is_binary
)
return
SUCCESS
;
i
=
cmd
(
ftp
,
"TYPE I"
);
if
(
i
<
0
||
check_code
(
ftp
,
i
,
FTP_BINARY_HAPPY
))
return
i
;
ftp
->
is_binary
=
TRUE
;
return
SUCCESS
;
}
void
ftpVerbose
(
FILE
*
fp
,
int
status
)
{
FTP_t
ftp
=
fcookie
(
fp
);
ftp
->
is_verbose
=
status
;
}
int
ftpChdir
(
FILE
*
fp
,
char
*
dir
)
{
int
i
;
FTP_t
ftp
=
fcookie
(
fp
);
i
=
cmd
(
ftp
,
"CWD %s"
,
dir
);
if
(
i
<
0
||
check_code
(
ftp
,
i
,
FTP_CHDIR_HAPPY
))
return
i
;
return
SUCCESS
;
}
int
ftpErrno
(
FILE
*
fp
)
{
FTP_t
ftp
=
fcookie
(
fp
);
return
ftp
->
error
;
}
const
char
*
ftpErrString
(
int
error
)
{
int
k
;
if
(
error
==
-
1
)
return
(
"connection in wrong state"
);
if
(
error
<
100
)
/* XXX soon UNIX errnos will catch up with FTP protocol errnos */
return
strerror
(
error
);
for
(
k
=
0
;
k
<
ftpErrListLength
;
k
++
)
if
(
ftpErrList
[
k
].
num
==
error
)
return
(
ftpErrList
[
k
].
string
);
return
(
"Unknown error"
);
}
off_t
ftpGetSize
(
FILE
*
fp
,
char
*
name
)
{
int
i
;
char
p
[
BUFSIZ
],
*
cp
,
*
ep
;
FTP_t
ftp
=
fcookie
(
fp
);
off_t
size
;
check_passive
(
fp
);
sprintf
(
p
,
"SIZE %s
\r\n
"
,
name
);
if
(
ftp
->
is_verbose
)
fprintf
(
stderr
,
"Sending %s"
,
p
);
if
(
writes
(
ftp
->
fd_ctrl
,
p
))
return
(
off_t
)
-
1
;
i
=
get_a_number
(
ftp
,
&
cp
);
if
(
check_code
(
ftp
,
i
,
213
))
return
(
off_t
)
-
1
;
errno
=
0
;
/* to check for ERANGE */
size
=
(
off_t
)
strtoq
(
cp
,
&
ep
,
10
);
if
(
*
ep
!=
'\0'
||
errno
==
ERANGE
)
return
(
off_t
)
-
1
;
return
size
;
}
time_t
ftpGetModtime
(
FILE
*
fp
,
char
*
name
)
{
char
p
[
BUFSIZ
],
*
cp
;
struct
tm
t
;
time_t
t0
=
time
(
0
);
FTP_t
ftp
=
fcookie
(
fp
);
int
i
;
check_passive
(
fp
);
sprintf
(
p
,
"MDTM %s
\r\n
"
,
name
);
if
(
ftp
->
is_verbose
)
fprintf
(
stderr
,
"Sending %s"
,
p
);
if
(
writes
(
ftp
->
fd_ctrl
,
p
))
return
(
time_t
)
0
;
i
=
get_a_number
(
ftp
,
&
cp
);
if
(
check_code
(
ftp
,
i
,
213
))
return
(
time_t
)
0
;
while
(
*
cp
&&
!
isdigit
(
*
cp
))
cp
++
;
if
(
!*
cp
)
return
(
time_t
)
0
;
t0
=
localtime
(
&
t0
)
->
tm_gmtoff
;
sscanf
(
cp
,
"%04d%02d%02d%02d%02d%02d"
,
&
t
.
tm_year
,
&
t
.
tm_mon
,
&
t
.
tm_mday
,
&
t
.
tm_hour
,
&
t
.
tm_min
,
&
t
.
tm_sec
);
t
.
tm_mon
--
;
t
.
tm_year
-=
1900
;
t
.
tm_isdst
=-
1
;
t
.
tm_gmtoff
=
0
;
t0
+=
mktime
(
&
t
);
return
t0
;
}
FILE
*
ftpGet
(
FILE
*
fp
,
char
*
file
,
off_t
*
seekto
)
{
FILE
*
fp2
;
FTP_t
ftp
=
fcookie
(
fp
);
check_passive
(
fp
);
if
(
ftpBinary
(
fp
)
!=
SUCCESS
)
return
NULL
;
if
(
ftp_file_op
(
ftp
,
"RETR"
,
file
,
&
fp2
,
"r"
,
seekto
)
==
SUCCESS
)
return
fp2
;
return
NULL
;
}
/* Returns a standard FILE pointer type representing an open control connection */
FILE
*
ftpLogin
(
char
*
host
,
char
*
user
,
char
*
passwd
,
int
port
,
int
verbose
,
int
*
retcode
)
{
#ifdef INET6
return
ftpLoginAf
(
host
,
AF_UNSPEC
,
user
,
passwd
,
port
,
verbose
,
retcode
);
#else
return
ftpLoginAf
(
host
,
AF_INET
,
user
,
passwd
,
port
,
verbose
,
retcode
);
#endif
}
FILE
*
ftpLoginAf
(
char
*
host
,
int
af
,
char
*
user
,
char
*
passwd
,
int
port
,
int
verbose
,
int
*
retcode
)
{
FTP_t
n
;
FILE
*
fp
;
if
(
retcode
)
*
retcode
=
0
;
if
(
networkInit
()
!=
SUCCESS
)
return
NULL
;
n
=
ftp_new
();
fp
=
NULL
;
if
(
n
&&
ftp_login_session
(
n
,
host
,
af
,
user
,
passwd
,
port
,
verbose
)
==
SUCCESS
)
{
fp
=
funopen
(
n
,
ftp_read_method
,
ftp_write_method
,
NULL
,
ftp_close_method
);
/* BSD 4.4 function! */
fp
->
_file
=
n
->
fd_ctrl
;
}
if
(
retcode
)
{
if
(
!
n
)
*
retcode
=
(
FtpTimedOut
?
FTP_TIMED_OUT
:
-
1
);
/* Poor attempt at mapping real errnos to FTP error codes */
else
switch
(
n
->
error
)
{
case
EADDRNOTAVAIL
:
*
retcode
=
FTP_TIMED_OUT
;
/* Actually no such host, but we have no way of saying that. :-( */
break
;
case
ETIMEDOUT
:
*
retcode
=
FTP_TIMED_OUT
;
break
;
default:
*
retcode
=
n
->
error
;
break
;
}
}
return
fp
;
}
FILE
*
ftpPut
(
FILE
*
fp
,
char
*
file
)
{
FILE
*
fp2
;
FTP_t
ftp
=
fcookie
(
fp
);
check_passive
(
fp
);
if
(
ftp_file_op
(
ftp
,
"STOR"
,
file
,
&
fp2
,
"w"
,
NULL
)
==
SUCCESS
)
return
fp2
;
return
NULL
;
}
int
ftpPassive
(
FILE
*
fp
,
int
st
)
{
FTP_t
ftp
=
fcookie
(
fp
);
ftp
->
is_passive
=
!!
st
;
/* normalize "st" to zero or one */
return
SUCCESS
;
}
FILE
*
ftpGetURL
(
char
*
url
,
char
*
user
,
char
*
passwd
,
int
*
retcode
)
{
#ifdef INET6
return
ftpGetURLAf
(
url
,
AF_UNSPEC
,
user
,
passwd
,
retcode
);
#else
return
ftpGetURLAf
(
url
,
AF_INET
,
user
,
passwd
,
retcode
);
#endif
}
FILE
*
ftpGetURLAf
(
char
*
url
,
int
af
,
char
*
user
,
char
*
passwd
,
int
*
retcode
)
{
char
host
[
255
],
name
[
255
];
int
port
;
FILE
*
fp2
;
static
FILE
*
fp
=
NULL
;
static
char
*
prev_host
;
if
(
retcode
)
*
retcode
=
0
;
if
(
get_url_info
(
url
,
host
,
&
port
,
name
)
==
SUCCESS
)
{
if
(
fp
&&
prev_host
)
{
if
(
!
strcmp
(
prev_host
,
host
))
{
/* Try to use cached connection */
fp2
=
ftpGet
(
fp
,
name
,
NULL
);
if
(
!
fp2
)
{
/* Connection timed out or was no longer valid */
fclose
(
fp
);
free
(
prev_host
);
prev_host
=
NULL
;
}
else
return
fp2
;
}
else
{
/* It's a different host now, flush old */
fclose
(
fp
);
free
(
prev_host
);
prev_host
=
NULL
;
}
}
fp
=
ftpLoginAf
(
host
,
af
,
user
,
passwd
,
port
,
0
,
retcode
);
if
(
fp
)
{
fp2
=
ftpGet
(
fp
,
name
,
NULL
);
if
(
!
fp2
)
{
/* Connection timed out or was no longer valid */
if
(
retcode
)
*
retcode
=
ftpErrno
(
fp
);
fclose
(
fp
);
fp
=
NULL
;
}
else
prev_host
=
strdup
(
host
);
return
fp2
;
}
}
return
NULL
;
}
FILE
*
ftpPutURL
(
char
*
url
,
char
*
user
,
char
*
passwd
,
int
*
retcode
)
{
#ifdef INET6
return
ftpPutURLAf
(
url
,
AF_UNSPEC
,
user
,
passwd
,
retcode
);
#else
return
ftpPutURLAf
(
url
,
AF_INET
,
user
,
passwd
,
retcode
);
#endif
}
FILE
*
ftpPutURLAf
(
char
*
url
,
int
af
,
char
*
user
,
char
*
passwd
,
int
*
retcode
)
{
char
host
[
255
],
name
[
255
];
int
port
;
static
FILE
*
fp
=
NULL
;
FILE
*
fp2
;
if
(
retcode
)
*
retcode
=
0
;
if
(
fp
)
{
/* Close previous managed connection */
fclose
(
fp
);
fp
=
NULL
;
}
if
(
get_url_info
(
url
,
host
,
&
port
,
name
)
==
SUCCESS
)
{
fp
=
ftpLoginAf
(
host
,
af
,
user
,
passwd
,
port
,
0
,
retcode
);
if
(
fp
)
{
fp2
=
ftpPut
(
fp
,
name
);
if
(
!
fp2
)
{
if
(
retcode
)
*
retcode
=
ftpErrno
(
fp
);
fclose
(
fp
);
fp
=
NULL
;
}
return
fp2
;
}
}
return
NULL
;
}
/* Internal workhorse function for dissecting URLs. Takes a URL as the first argument and returns the
result of such disection in the host, user, passwd, port and name variables. */
static
int
get_url_info
(
char
*
url_in
,
char
*
host_ret
,
int
*
port_ret
,
char
*
name_ret
)
{
char
*
name
,
*
host
,
*
cp
,
url
[
BUFSIZ
];
int
port
;
name
=
host
=
NULL
;
/* XXX add http:// here or somewhere reasonable at some point XXX */
if
(
strncmp
(
"ftp://"
,
url_in
,
6
)
!=
0
)
return
FAILURE
;
/* We like to stomp a lot on the URL string in dissecting it, so copy it first */
strncpy
(
url
,
url_in
,
BUFSIZ
);
host
=
url
+
6
;
if
((
cp
=
index
(
host
,
':'
))
!=
NULL
)
{
*
(
cp
++
)
=
'\0'
;
port
=
strtol
(
cp
,
0
,
0
);
}
else
port
=
0
;
/* use default */
if
(
port_ret
)
*
port_ret
=
port
;
if
((
name
=
index
(
cp
?
cp
:
host
,
'/'
))
!=
NULL
)
*
(
name
++
)
=
'\0'
;
if
(
host_ret
)
strcpy
(
host_ret
,
host
);
if
(
name
&&
name_ret
)
strcpy
(
name_ret
,
name
);
return
SUCCESS
;
}
static
FTP_t
ftp_new
(
void
)
{
FTP_t
ftp
;
ftp
=
(
FTP_t
)
malloc
(
sizeof
*
ftp
);
if
(
!
ftp
)
return
NULL
;
memset
(
ftp
,
0
,
sizeof
*
ftp
);
ftp
->
fd_ctrl
=
-
1
;
ftp
->
con_state
=
init
;
ftp
->
is_binary
=
FALSE
;
ftp
->
is_passive
=
FALSE
;
ftp
->
is_verbose
=
FALSE
;
ftp
->
error
=
0
;
return
ftp
;
}
static
int
ftp_read_method
(
void
*
vp
,
char
*
buf
,
int
nbytes
)
{
int
i
,
fd
;
FTP_t
n
=
(
FTP_t
)
vp
;
fd
=
n
->
fd_ctrl
;
i
=
(
fd
>=
0
)
?
read
(
fd
,
buf
,
nbytes
)
:
EOF
;
return
i
;
}
static
int
ftp_write_method
(
void
*
vp
,
const
char
*
buf
,
int
nbytes
)
{
int
i
,
fd
;
FTP_t
n
=
(
FTP_t
)
vp
;
fd
=
n
->
fd_ctrl
;
i
=
(
fd
>=
0
)
?
write
(
fd
,
buf
,
nbytes
)
:
EOF
;
return
i
;
}
static
int
ftp_close_method
(
void
*
n
)
{
int
i
;
i
=
ftp_close
((
FTP_t
)
n
);
free
(
n
);
return
i
;
}
/*
* This function checks whether the FTP_PASSIVE_MODE environment
* variable is set, and, if so, enforces the desired mode.
*/
static
void
check_passive
(
FILE
*
fp
)
{
/* const char *cp = getenv("FTP_PASSIVE_MODE");
if (cp != NULL)
ftpPassive(fp, strncasecmp(cp, "no", 2));
*/
/* Force passive mode always */
ftpPassive
(
fp
,
TRUE
);
}
static
void
ftp_timeout
(
int
sig
)
{
FtpTimedOut
=
TRUE
;
/* Debug("ftp_pkg: ftp_timeout called - operation timed out"); */
}
static
void
ftp_set_timeout
(
void
)
{
struct
sigaction
new
;
char
*
cp
;
int
ival
;
FtpTimedOut
=
FALSE
;
sigemptyset
(
&
new
.
sa_mask
);
new
.
sa_flags
=
0
;
new
.
sa_handler
=
ftp_timeout
;
sigaction
(
SIGALRM
,
&
new
,
NULL
);
cp
=
getenv
(
"FTP_TIMEOUT"
);
if
(
!
cp
||
!
(
ival
=
atoi
(
cp
)))
ival
=
120
;
alarm
(
ival
);
}
static
void
ftp_clear_timeout
(
void
)
{
struct
sigaction
new
;
alarm
(
0
);
sigemptyset
(
&
new
.
sa_mask
);
new
.
sa_flags
=
0
;
new
.
sa_handler
=
SIG_DFL
;
sigaction
(
SIGALRM
,
&
new
,
NULL
);
}
static
int
writes
(
int
fd
,
char
*
s
)
{
int
n
,
i
=
strlen
(
s
);
ftp_set_timeout
();
n
=
write
(
fd
,
s
,
i
);
ftp_clear_timeout
();
if
(
FtpTimedOut
||
i
!=
n
)
return
TRUE
;
return
FALSE
;
}
static
__inline
char
*
get_a_line
(
FTP_t
ftp
)
{
static
char
buf
[
BUFSIZ
];
int
i
,
j
;
/* Debug("ftp_pkg: trying to read a line from %d", ftp->fd_ctrl); */
for
(
i
=
0
;
i
<
BUFSIZ
;)
{
ftp_set_timeout
();
j
=
read
(
ftp
->
fd_ctrl
,
buf
+
i
,
1
);
ftp_clear_timeout
();
if
(
FtpTimedOut
||
j
!=
1
)
return
NULL
;
if
(
buf
[
i
]
==
'\r'
||
buf
[
i
]
==
'\n'
)
{
if
(
!
i
)
continue
;
buf
[
i
]
=
'\0'
;
if
(
ftp
->
is_verbose
==
TRUE
)
fprintf
(
stderr
,
"%s
\n
"
,
buf
+
4
);
return
buf
;
}
i
++
;
}
/* Debug("ftp_pkg: read string \"%s\" from %d", buf, ftp->fd_ctrl); */
return
buf
;
}
static
int
get_a_number
(
FTP_t
ftp
,
char
**
q
)
{
char
*
p
;
int
i
=
-
1
,
j
;
while
(
1
)
{
p
=
get_a_line
(
ftp
);
if
(
!
p
)
{
ftp_close
(
ftp
);
if
(
FtpTimedOut
)
return
FTP_TIMED_OUT
;
return
FAILURE
;
}
if
(
!
(
isdigit
(
p
[
0
])
&&
isdigit
(
p
[
1
])
&&
isdigit
(
p
[
2
])))
continue
;
if
(
i
==
-
1
&&
p
[
3
]
==
'-'
)
{
i
=
strtol
(
p
,
0
,
0
);
continue
;
}
if
(
p
[
3
]
!=
' '
&&
p
[
3
]
!=
'\t'
)
continue
;
j
=
strtol
(
p
,
0
,
0
);
if
(
i
==
-
1
)
{
if
(
q
)
*
q
=
p
+
4
;
/* Debug("ftp_pkg: read reply %d from server (%s)", j, p); */
return
j
;
}
else
if
(
j
==
i
)
{
if
(
q
)
*
q
=
p
+
4
;
/* Debug("ftp_pkg: read reply %d from server (%s)", j, p); */
return
j
;
}
}
}
static
int
ftp_close
(
FTP_t
ftp
)
{
int
i
,
rcode
;
rcode
=
FAILURE
;
if
(
ftp
->
con_state
==
isopen
)
{
ftp
->
con_state
=
quit
;
/* If last operation timed out, don't try to quit - just close */
if
(
ftp
->
error
!=
FTP_TIMED_OUT
)
i
=
cmd
(
ftp
,
"QUIT"
);
else
i
=
FTP_QUIT_HAPPY
;
if
(
!
check_code
(
ftp
,
i
,
FTP_QUIT_HAPPY
))
rcode
=
SUCCESS
;
close
(
ftp
->
fd_ctrl
);
ftp
->
fd_ctrl
=
-
1
;
}
else
if
(
ftp
->
con_state
==
quit
)
rcode
=
SUCCESS
;
return
rcode
;
}
static
int
botch
(
char
*
func
,
char
*
botch_state
)
{
/* Debug("ftp_pkg: botch: %s(%s)", func, botch_state); */
return
FAILURE
;
}
static
int
cmd
(
FTP_t
ftp
,
const
char
*
fmt
,
...)
{
char
p
[
BUFSIZ
];
int
i
;
va_list
ap
;
va_start
(
ap
,
fmt
);
(
void
)
vsnprintf
(
p
,
sizeof
p
,
fmt
,
ap
);
va_end
(
ap
);
if
(
ftp
->
con_state
==
init
)
return
botch
(
"cmd"
,
"open"
);
strcat
(
p
,
"
\r\n
"
);
if
(
ftp
->
is_verbose
)
fprintf
(
stderr
,
"Sending: %s"
,
p
);
if
(
writes
(
ftp
->
fd_ctrl
,
p
))
{
if
(
FtpTimedOut
)
return
FTP_TIMED_OUT
;
return
FAILURE
;
}
while
((
i
=
get_a_number
(
ftp
,
NULL
))
==
FTP_HAPPY_COMMENT
);
return
i
;
}
static
int
ftp_login_session
(
FTP_t
ftp
,
char
*
host
,
int
af
,
char
*
user
,
char
*
passwd
,
int
port
,
int
verbose
)
{
char
pbuf
[
10
];
struct
addrinfo
hints
,
*
res
,
*
res0
;
int
err
;
int
s
;
int
i
;
if
(
networkInit
()
!=
SUCCESS
)
return
FAILURE
;
if
(
ftp
->
con_state
!=
init
)
{
ftp_close
(
ftp
);
ftp
->
error
=
-
1
;
return
FAILURE
;
}
if
(
!
user
)
user
=
"ftp"
;
if
(
!
passwd
)
passwd
=
"setup@"
;
if
(
!
port
)
port
=
21
;
snprintf
(
pbuf
,
sizeof
(
pbuf
),
"%d"
,
port
);
memset
(
&
hints
,
0
,
sizeof
(
hints
));
hints
.
ai_family
=
af
;
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_protocol
=
0
;
err
=
getaddrinfo
(
host
,
pbuf
,
&
hints
,
&
res0
);
if
(
err
)
{
ftp
->
error
=
0
;
return
FAILURE
;
}
s
=
-
1
;
for
(
res
=
res0
;
res
;
res
=
res
->
ai_next
)
{
ai_unmapped
(
res
);
ftp
->
addrtype
=
res
->
ai_family
;
if
((
s
=
socket
(
res
->
ai_family
,
res
->
ai_socktype
,
res
->
ai_protocol
))
<
0
)
continue
;
if
(
connect
(
s
,
res
->
ai_addr
,
res
->
ai_addrlen
)
<
0
)
{
(
void
)
close
(
s
);
s
=
-
1
;
continue
;
}
break
;
}
freeaddrinfo
(
res0
);
if
(
s
<
0
)
{
ftp
->
error
=
errno
;
return
FAILURE
;
}
ftp
->
fd_ctrl
=
s
;
ftp
->
con_state
=
isopen
;
ftp
->
is_verbose
=
verbose
;
i
=
cmd
(
ftp
,
"USER %s"
,
user
);
if
(
i
>=
300
&&
i
<
400
)
i
=
cmd
(
ftp
,
"PASS %s"
,
passwd
);
if
(
i
>=
299
||
i
<
0
)
{
ftp_close
(
ftp
);
if
(
i
>
0
)
ftp
->
error
=
i
;
return
FAILURE
;
}
return
SUCCESS
;
}
static
int
ftp_file_op
(
FTP_t
ftp
,
char
*
operation
,
char
*
file
,
FILE
**
fp
,
char
*
mode
,
off_t
*
seekto
)
{
int
i
,
l
,
s
;
char
*
q
;
unsigned
char
addr
[
64
];
union
sockaddr_cmn
{
struct
sockaddr_in
sin4
;
struct
sockaddr_in6
sin6
;
}
sin
;
char
*
cmdstr
;
if
(
!
fp
)
return
FAILURE
;
*
fp
=
NULL
;
if
(
ftp
->
con_state
!=
isopen
)
return
botch
(
"ftp_file_op"
,
"open"
);
if
((
s
=
socket
(
ftp
->
addrtype
,
SOCK_STREAM
,
0
))
<
0
)
{
ftp
->
error
=
errno
;
return
FAILURE
;
}
if
(
ftp
->
is_passive
)
{
if
(
ftp
->
addrtype
==
AF_INET
)
{
if
(
ftp
->
is_verbose
)
fprintf
(
stderr
,
"Sending PASV
\n
"
);
if
(
writes
(
ftp
->
fd_ctrl
,
"PASV
\r\n
"
))
{
ftp_close
(
ftp
);
if
(
FtpTimedOut
)
ftp
->
error
=
FTP_TIMED_OUT
;
return
FTP_TIMED_OUT
;
}
i
=
get_a_number
(
ftp
,
&
q
);
if
(
check_code
(
ftp
,
i
,
FTP_PASSIVE_HAPPY
))
{
ftp_close
(
ftp
);
return
i
;
}
cmdstr
=
"PASV"
;
}
else
{
if
(
ftp
->
is_verbose
)
fprintf
(
stderr
,
"Sending EPSV
\n
"
);
if
(
writes
(
ftp
->
fd_ctrl
,
"EPSV
\r\n
"
))
{
ftp_close
(
ftp
);
if
(
FtpTimedOut
)
ftp
->
error
=
FTP_TIMED_OUT
;
return
FTP_TIMED_OUT
;
}
i
=
get_a_number
(
ftp
,
&
q
);
if
(
check_code
(
ftp
,
i
,
FTP_EPASSIVE_HAPPY
))
{
if
(
ftp
->
is_verbose
)
fprintf
(
stderr
,
"Sending LPSV
\n
"
);
if
(
writes
(
ftp
->
fd_ctrl
,
"LPSV
\r\n
"
))
{
ftp_close
(
ftp
);
if
(
FtpTimedOut
)
ftp
->
error
=
FTP_TIMED_OUT
;
return
FTP_TIMED_OUT
;
}
i
=
get_a_number
(
ftp
,
&
q
);
if
(
check_code
(
ftp
,
i
,
FTP_LPASSIVE_HAPPY
))
{
ftp_close
(
ftp
);
return
i
;
}
cmdstr
=
"LPSV"
;
}
else
cmdstr
=
"EPSV"
;
}
if
(
strcmp
(
cmdstr
,
"PASV"
)
==
0
||
strcmp
(
cmdstr
,
"LPSV"
)
==
0
)
{
while
(
*
q
&&
!
isdigit
(
*
q
))
q
++
;
if
(
!*
q
)
{
ftp_close
(
ftp
);
return
FAILURE
;
}
q
--
;
l
=
(
ftp
->
addrtype
==
AF_INET
?
6
:
21
);
for
(
i
=
0
;
i
<
l
;
i
++
)
{
q
++
;
addr
[
i
]
=
strtol
(
q
,
&
q
,
10
);
}
sin
.
sin4
.
sin_family
=
ftp
->
addrtype
;
if
(
ftp
->
addrtype
==
AF_INET6
)
{
sin
.
sin6
.
sin6_len
=
sizeof
(
struct
sockaddr_in6
);
bcopy
(
addr
+
2
,
(
char
*
)
&
sin
.
sin6
.
sin6_addr
,
16
);
bcopy
(
addr
+
19
,
(
char
*
)
&
sin
.
sin6
.
sin6_port
,
2
);
}
else
{
sin
.
sin4
.
sin_len
=
sizeof
(
struct
sockaddr_in
);
bcopy
(
addr
,
(
char
*
)
&
sin
.
sin4
.
sin_addr
,
4
);
bcopy
(
addr
+
4
,
(
char
*
)
&
sin
.
sin4
.
sin_port
,
2
);
}
}
else
if
(
strcmp
(
cmdstr
,
"EPSV"
)
==
0
)
{
int
port
;
int
sinlen
;
while
(
*
q
&&
*
q
!=
'('
)
/* ) */
q
++
;
if
(
!*
q
)
{
ftp_close
(
ftp
);
return
FAILURE
;
}
q
++
;
if
(
sscanf
(
q
,
"%c%c%c%d%c"
,
&
addr
[
0
],
&
addr
[
1
],
&
addr
[
2
],
&
port
,
&
addr
[
3
])
!=
5
||
addr
[
0
]
!=
addr
[
1
]
||
addr
[
0
]
!=
addr
[
2
]
||
addr
[
0
]
!=
addr
[
3
])
{
ftp_close
(
ftp
);
return
FAILURE
;
}
sinlen
=
sizeof
(
sin
);
if
(
getpeername
(
ftp
->
fd_ctrl
,
(
struct
sockaddr
*
)
&
sin
,
&
sinlen
)
<
0
)
{
ftp_close
(
ftp
);
return
FAILURE
;
}
switch
(
sin
.
sin4
.
sin_family
)
{
case
AF_INET
:
sin
.
sin4
.
sin_port
=
htons
(
port
);
break
;
case
AF_INET6
:
sin
.
sin6
.
sin6_port
=
htons
(
port
);
break
;
default:
ftp_close
(
ftp
);
return
FAILURE
;
}
}
if
(
connect
(
s
,
(
struct
sockaddr
*
)
&
sin
,
sin
.
sin4
.
sin_len
)
<
0
)
{
(
void
)
close
(
s
);
return
FAILURE
;
}
if
(
seekto
&&
*
seekto
)
{
i
=
cmd
(
ftp
,
"REST %d"
,
*
seekto
);
if
(
i
<
0
||
FTP_TIMEOUT
(
i
))
{
close
(
s
);
ftp
->
error
=
i
;
*
seekto
=
(
off_t
)
0
;
return
i
;
}
}
i
=
cmd
(
ftp
,
"%s %s"
,
operation
,
file
);
if
(
i
<
0
||
i
>
299
)
{
close
(
s
);
ftp
->
error
=
i
;
return
i
;
}
*
fp
=
fdopen
(
s
,
mode
);
}
else
{
int
fd
,
portrange
;
#ifdef IPV6_PORTRANGE
if
(
ftp
->
addrtype
==
AF_INET6
)
{
portrange
=
IPV6_PORTRANGE_HIGH
;
if
(
setsockopt
(
s
,
IPPROTO_IPV6
,
IPV6_PORTRANGE
,
(
char
*
)
&
portrange
,
sizeof
(
portrange
))
<
0
)
{
close
(
s
);
return
FAILURE
;
}
}
#endif
#ifdef IP_PORTRANGE
if
(
ftp
->
addrtype
==
AF_INET
)
{
portrange
=
IP_PORTRANGE_HIGH
;
if
(
setsockopt
(
s
,
IPPROTO_IP
,
IP_PORTRANGE
,
(
char
*
)
&
portrange
,
sizeof
(
portrange
))
<
0
)
{
close
(
s
);
return
FAILURE
;
}
}
#endif
i
=
sizeof
sin
;
getsockname
(
ftp
->
fd_ctrl
,
(
struct
sockaddr
*
)
&
sin
,
&
i
);
sin
.
sin4
.
sin_port
=
0
;
i
=
((
struct
sockaddr
*
)
&
sin
)
->
sa_len
;
if
(
bind
(
s
,
(
struct
sockaddr
*
)
&
sin
,
i
)
<
0
)
{
close
(
s
);
return
FAILURE
;
}
i
=
sizeof
sin
;
getsockname
(
s
,(
struct
sockaddr
*
)
&
sin
,
&
i
);
if
(
listen
(
s
,
1
)
<
0
)
{
close
(
s
);
return
FAILURE
;
}
if
(
sin
.
sin4
.
sin_family
==
AF_INET
)
{
u_long
a
;
a
=
ntohl
(
sin
.
sin4
.
sin_addr
.
s_addr
);
i
=
cmd
(
ftp
,
"PORT %d,%d,%d,%d,%d,%d"
,
(
a
>>
24
)
&
0xff
,
(
a
>>
16
)
&
0xff
,
(
a
>>
8
)
&
0xff
,
a
&
0xff
,
(
ntohs
(
sin
.
sin4
.
sin_port
)
>>
8
)
&
0xff
,
ntohs
(
sin
.
sin4
.
sin_port
)
&
0xff
);
if
(
check_code
(
ftp
,
i
,
FTP_PORT_HAPPY
))
{
close
(
s
);
return
i
;
}
}
else
{
#define UC(b) (((int)b)&0xff)
char
*
a
;
char
hname
[
INET6_ADDRSTRLEN
];
sin
.
sin6
.
sin6_scope_id
=
0
;
if
(
getnameinfo
((
struct
sockaddr
*
)
&
sin
,
sin
.
sin6
.
sin6_len
,
hname
,
sizeof
(
hname
),
NULL
,
0
,
NI_NUMERICHOST
)
!=
0
)
{
goto
try_lprt
;
}
i
=
cmd
(
ftp
,
"EPRT |%d|%s|%d|"
,
2
,
hname
,
htons
(
sin
.
sin6
.
sin6_port
));
if
(
check_code
(
ftp
,
i
,
FTP_PORT_HAPPY
))
{
try_lprt:
a
=
(
char
*
)
&
sin
.
sin6
.
sin6_addr
;
i
=
cmd
(
ftp
,
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d"
,
6
,
16
,
UC
(
a
[
0
]),
UC
(
a
[
1
]),
UC
(
a
[
2
]),
UC
(
a
[
3
]),
UC
(
a
[
4
]),
UC
(
a
[
5
]),
UC
(
a
[
6
]),
UC
(
a
[
7
]),
UC
(
a
[
8
]),
UC
(
a
[
9
]),
UC
(
a
[
10
]),
UC
(
a
[
11
]),
UC
(
a
[
12
]),
UC
(
a
[
13
]),
UC
(
a
[
14
]),
UC
(
a
[
15
]),
2
,
(
ntohs
(
sin
.
sin4
.
sin_port
)
>>
8
)
&
0xff
,
ntohs
(
sin
.
sin4
.
sin_port
)
&
0xff
);
if
(
check_code
(
ftp
,
i
,
FTP_PORT_HAPPY
))
{
close
(
s
);
return
i
;
}
}
}
if
(
seekto
&&
*
seekto
)
{
i
=
cmd
(
ftp
,
"REST %d"
,
*
seekto
);
if
(
i
<
0
||
FTP_TIMEOUT
(
i
))
{
close
(
s
);
ftp
->
error
=
i
;
return
i
;
}
else
if
(
i
!=
350
)
*
seekto
=
(
off_t
)
0
;
}
i
=
cmd
(
ftp
,
"%s %s"
,
operation
,
file
);
if
(
i
<
0
||
i
>
299
)
{
close
(
s
);
ftp
->
error
=
i
;
return
FAILURE
;
}
fd
=
accept
(
s
,
0
,
0
);
if
(
fd
<
0
)
{
close
(
s
);
ftp
->
error
=
401
;
return
FAILURE
;
}
close
(
s
);
*
fp
=
fdopen
(
fd
,
mode
);
}
if
(
*
fp
)
return
SUCCESS
;
else
return
FAILURE
;
}
static
void
ai_unmapped
(
struct
addrinfo
*
ai
)
{
struct
sockaddr_in6
*
sin6
;
struct
sockaddr_in
sin
;
if
(
ai
->
ai_family
!=
AF_INET6
)
return
;
if
(
ai
->
ai_addrlen
!=
sizeof
(
struct
sockaddr_in6
)
||
sizeof
(
sin
)
>
ai
->
ai_addrlen
)
return
;
sin6
=
(
struct
sockaddr_in6
*
)
ai
->
ai_addr
;
if
(
!
IN6_IS_ADDR_V4MAPPED
(
&
sin6
->
sin6_addr
))
return
;
memset
(
&
sin
,
0
,
sizeof
(
sin
));
sin
.
sin_family
=
AF_INET
;
sin
.
sin_len
=
sizeof
(
struct
sockaddr_in
);
memcpy
(
&
sin
.
sin_addr
,
&
sin6
->
sin6_addr
.
s6_addr
[
12
],
sizeof
(
sin
.
sin_addr
));
sin
.
sin_port
=
sin6
->
sin6_port
;
ai
->
ai_family
=
AF_INET
;
memcpy
(
ai
->
ai_addr
,
&
sin
,
sin
.
sin_len
);
ai
->
ai_addrlen
=
sin
.
sin_len
;
}
struct
ftperr
ftpErrList
[]
=
{
{
110
,
"Restart marker reply"
},
{
120
,
"Service ready in a few minutes"
},
{
125
,
"Data connection already open; transfer starting"
},
{
150
,
"File status okay; about to open data connection"
},
{
200
,
"Command okay"
},
{
202
,
"Command not implemented, superfluous at this site"
},
{
211
,
"System status, or system help reply"
},
{
212
,
"Directory status"
},
{
213
,
"File status"
},
{
214
,
"Help message"
},
{
215
,
"Set system type"
},
{
220
,
"Service ready for new user"
},
{
221
,
"Service closing control connection"
},
{
225
,
"Data connection open; no transfer in progress"
},
{
226
,
"Requested file action successful"
},
{
227
,
"Entering Passive Mode"
},
{
229
,
"Entering Extended Passive Mode"
},
{
230
,
"User logged in, proceed"
},
{
250
,
"Requested file action okay, completed"
},
{
257
,
"File/directory created"
},
{
331
,
"User name okay, need password"
},
{
332
,
"Need account for login"
},
{
350
,
"Requested file action pending further information"
},
{
421
,
"Service not available, closing control connection"
},
{
425
,
"Can't open data connection"
},
{
426
,
"Connection closed; transfer aborted"
},
{
450
,
"File unavailable (e.g., file busy)"
},
{
451
,
"Requested action aborted: local error in processing"
},
{
452
,
"Insufficient storage space in system"
},
{
500
,
"Syntax error, command unrecognized"
},
{
501
,
"Syntax error in parameters or arguments"
},
{
502
,
"Command not implemented"
},
{
503
,
"Bad sequence of commands"
},
{
504
,
"Command not implemented for that parameter"
},
{
530
,
"Not logged in"
},
{
532
,
"Need account for storing files"
},
{
550
,
"File unavailable (e.g., file not found, no access)"
},
{
551
,
"Requested action aborted. Page type unknown"
},
{
552
,
"Exceeded storage allocation"
},
{
553
,
"File name not allowed"
},
};
int
const
ftpErrListLength
=
sizeof
(
ftpErrList
)
/
sizeof
(
*
ftpErrList
);
This diff is collapsed.
Click to expand it.
src/sbbs3/install/objects.mk
+
2
−
1
View file @
adacfd7a
...
...
@@ -11,5 +11,6 @@ OBJS = $(ODIR)$(SLASH)sbbsinst.$(OFILE)\
$(
ODIR
)$(
SLASH
)
conwrap.
$(
OFILE
)
\
$(
ODIR
)$(
SLASH
)
genwrap.
$(
OFILE
)
\
$(
ODIR
)$(
SLASH
)
dirwrap.
$(
OFILE
)
\
$(
ODIR
)$(
SLASH
)
uifcx.
$(
OFILE
)
\
$(
ODIR
)$(
SLASH
)
ftpio.
$(
OFILE
)
\
$(
ODIR
)$(
SLASH
)
uifcx.
$(
OFILE
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment