NB: big update - may break stuff. Please test!

- (djm) OpenBSD CVS sync:
   - markus@cvs.openbsd.org  2001/02/03 03:08:38
     [auth-options.c auth-rh-rsa.c auth-rhosts.c auth.c canohost.c]
     [canohost.h servconf.c servconf.h session.c sshconnect1.c sshd.8]
     [sshd_config]
     make ReverseMappingCheck optional in sshd_config; ok djm@,dugsong@
   - markus@cvs.openbsd.org  2001/02/03 03:19:51
     [ssh.1 sshd.8 sshd_config]
     Skey is now called ChallengeResponse
   - markus@cvs.openbsd.org  2001/02/03 03:43:09
     [sshd.8]
     use no-pty option in .ssh/authorized_keys* if you need a 8-bit clean
     channel. note from Erik.Anggard@cygate.se (pr/1659)
   - stevesk@cvs.openbsd.org 2001/02/03 10:03:06
     [ssh.1]
     typos; ok markus@
   - djm@cvs.openbsd.org     2001/02/04 04:11:56
     [scp.1 sftp-server.c ssh.1 sshd.8 sftp-client.c sftp-client.h]
     [sftp-common.c sftp-common.h sftp-int.c sftp-int.h sftp.1 sftp.c]
     Basic interactive sftp client; ok theo@
 - (djm) Update RPM specs for new sftp binary
 - (djm) Update several bits for new optional reverse lookup stuff. I
   think I got them all.
This commit is contained in:
Damien Miller 2001-02-04 23:20:18 +11:00
parent 45cb2937bc
commit 3380426358
34 changed files with 2489 additions and 429 deletions

View File

@ -5,6 +5,29 @@
right.
- (bal) Changed order of LIB="" in -with-skey due to library resolving.
- (bal) next-posix.h changed to bsd-nextstep.h
- (djm) OpenBSD CVS sync:
- markus@cvs.openbsd.org 2001/02/03 03:08:38
[auth-options.c auth-rh-rsa.c auth-rhosts.c auth.c canohost.c]
[canohost.h servconf.c servconf.h session.c sshconnect1.c sshd.8]
[sshd_config]
make ReverseMappingCheck optional in sshd_config; ok djm@,dugsong@
- markus@cvs.openbsd.org 2001/02/03 03:19:51
[ssh.1 sshd.8 sshd_config]
Skey is now called ChallengeResponse
- markus@cvs.openbsd.org 2001/02/03 03:43:09
[sshd.8]
use no-pty option in .ssh/authorized_keys* if you need a 8-bit clean
channel. note from Erik.Anggard@cygate.se (pr/1659)
- stevesk@cvs.openbsd.org 2001/02/03 10:03:06
[ssh.1]
typos; ok markus@
- djm@cvs.openbsd.org 2001/02/04 04:11:56
[scp.1 sftp-server.c ssh.1 sshd.8 sftp-client.c sftp-client.h]
[sftp-common.c sftp-common.h sftp-int.c sftp-int.h sftp.1 sftp.c]
Basic interactive sftp client; ok theo@
- (djm) Update RPM specs for new sftp binary
- (djm) Update several bits for new optional reverse lookup stuff. I
think I got them all.
20010103
- (bal) Cygwin clean up by Corinna Vinschen <vinschen@redhat.com>

View File

@ -33,9 +33,9 @@ SSH_MODE= @SSHMODE@
INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
@NO_SFTP@SFTP-SERVER=sftp-server$(EXEEXT)
@NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) $(SFTP-SERVER)
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) $(SFTP_PROGS)
LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o deattack.o dispatch.o hmac.o hostfile.o key.o kex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o
@ -43,8 +43,8 @@ SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o
SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh-keyscan.0 ssh.0 sshd.0 sftp-server.0
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh-keyscan.0 ssh.0 sshd.0 sftp-server.0 sftp.1
MANPAGES = @MANTYPE@
CONFIGFILES=sshd_config ssh_config primes
@ -105,8 +105,12 @@ ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o log-client.o
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a log-client.o ssh-keyscan.o
$(LD) -o $@ ssh-keyscan.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp-server.o log-server.o
$(LD) -o $@ sftp-server.o log-server.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp-server.o sftp-common.o log-server.o
$(LD) -o $@ sftp-server.o sftp-common.o log-server.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
# XXX: need to -lssh twice here!
sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o log-client.o
$(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
# test driver for the loginrec code - not built by default
logintest: logintest.o $(LIBCOMPAT) libssh.a log-client.o loginrec.o
@ -156,6 +160,7 @@ install-files:
$(INSTALL) -m 0755 -s ssh-keygen $(DESTDIR)$(bindir)/ssh-keygen
$(INSTALL) -m 0775 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan
$(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd
@NO_SFTP@$$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp
@NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(libexecdir)/sftp-server
$(INSTALL) -m 644 ssh.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
$(INSTALL) -m 644 scp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
@ -164,6 +169,7 @@ install-files:
$(INSTALL) -m 644 ssh-keygen.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
$(INSTALL) -m 644 ssh-keyscan.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
$(INSTALL) -m 644 sshd.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
@NO_SFTP@$$(INSTALL) -m 644 sftp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
@NO_SFTP@$(INSTALL) -m 644 sftp-server.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
-rm -f $(DESTDIR)$(bindir)/slogin
ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
@ -241,6 +247,7 @@ uninstall:
-rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
-rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
-rm -r $(DESTDIR)$(libexecdir)/sftp-server$(EXEEXT)
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
@ -248,6 +255,7 @@ uninstall:
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8

2
TODO
View File

@ -1,4 +1,6 @@
Programming:
- Grep for 'XXX' comments and fix
- Replacement for setproctitle() - HP/UX support only currently
- Improve PAM support (a pam_lastlog module will cause sshd to exit)

View File

@ -10,7 +10,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-options.c,v 1.11 2001/01/21 19:05:41 markus Exp $");
RCSID("$OpenBSD: auth-options.c,v 1.12 2001/02/03 10:08:36 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
@ -18,6 +18,7 @@ RCSID("$OpenBSD: auth-options.c,v 1.11 2001/01/21 19:05:41 markus Exp $");
#include "log.h"
#include "canohost.h"
#include "auth-options.h"
#include "servconf.h"
/* Flags set authorized_keys flags */
int no_port_forwarding_flag = 0;
@ -31,6 +32,8 @@ char *forced_command = NULL;
/* "environment=" options. */
struct envstring *custom_environment = NULL;
extern ServerOptions options;
void
auth_clear_options(void)
{
@ -55,61 +58,61 @@ auth_clear_options(void)
* side effect: sets key option flags
*/
int
auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum)
auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
{
const char *cp;
if (!options)
if (!opts)
return 1;
/* reset options */
auth_clear_options();
while (*options && *options != ' ' && *options != '\t') {
while (*opts && *opts != ' ' && *opts != '\t') {
cp = "no-port-forwarding";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Port forwarding disabled.");
no_port_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-agent-forwarding";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Agent forwarding disabled.");
no_agent_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-X11-forwarding";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("X11 forwarding disabled.");
no_x11_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-pty";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Pty allocation disabled.");
no_pty_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "command=\"";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
int i;
options += strlen(cp);
forced_command = xmalloc(strlen(options) + 1);
opts += strlen(cp);
forced_command = xmalloc(strlen(opts) + 1);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
forced_command[i++] = '"';
continue;
}
forced_command[i++] = *options++;
forced_command[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
@ -118,28 +121,28 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum)
}
forced_command[i] = 0;
packet_send_debug("Forced command: %.900s", forced_command);
options++;
opts++;
goto next_option;
}
cp = "environment=\"";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
int i;
char *s;
struct envstring *new_envstring;
options += strlen(cp);
s = xmalloc(strlen(options) + 1);
opts += strlen(cp);
s = xmalloc(strlen(opts) + 1);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
s[i++] = '"';
continue;
}
s[i++] = *options++;
s[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
@ -149,7 +152,7 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum)
s[i] = 0;
packet_send_debug("Adding to environment: %.900s", s);
debug("Adding to environment: %.900s", s);
options++;
opts++;
new_envstring = xmalloc(sizeof(struct envstring));
new_envstring->s = s;
new_envstring->next = custom_environment;
@ -157,23 +160,26 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum)
goto next_option;
}
cp = "from=\"";
if (strncasecmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
int mname, mip;
char *patterns = xmalloc(strlen(options) + 1);
const char *remote_ip = get_remote_ipaddr();
const char *remote_host = get_canonical_hostname(
options.reverse_mapping_check);
char *patterns = xmalloc(strlen(opts) + 1);
int i;
options += strlen(cp);
opts += strlen(cp);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
patterns[i++] = '"';
continue;
}
patterns[i++] = *options++;
patterns[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
@ -181,24 +187,26 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum)
continue;
}
patterns[i] = 0;
options++;
opts++;
/*
* Deny access if we get a negative
* match for the hostname or the ip
* or if we get not match at all
*/
mname = match_hostname(get_canonical_hostname(),
patterns, strlen(patterns));
mip = match_hostname(get_remote_ipaddr(),
patterns, strlen(patterns));
mname = match_hostname(remote_host, patterns,
strlen(patterns));
mip = match_hostname(remote_ip, patterns,
strlen(patterns));
xfree(patterns);
if (mname == -1 || mip == -1 ||
(mname != 1 && mip != 1)) {
log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
pw->pw_name, get_canonical_hostname(),
get_remote_ipaddr());
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
get_canonical_hostname());
log("Authentication tried for %.100s with "
"correct key but not from a permitted "
"host (host=%.200s, ip=%.200s).",
pw->pw_name, remote_host, remote_ip);
packet_send_debug("Your host '%.200s' is not "
"permitted to use this key for login.",
remote_host);
/* deny access */
return 0;
}
@ -210,13 +218,13 @@ next_option:
* Skip the comma, and move to the next option
* (or break out if there are no more).
*/
if (!*options)
if (!*opts)
fatal("Bugs in auth-options.c option processing.");
if (*options == ' ' || *options == '\t')
if (*opts == ' ' || *opts == '\t')
break; /* End of options. */
if (*options != ',')
if (*opts != ',')
goto bad_option;
options++;
opts++;
/* Process the next option. */
}
/* grant access */
@ -224,9 +232,9 @@ next_option:
bad_option:
log("Bad options in %.100s file, line %lu: %.50s",
file, linenum, options);
file, linenum, opts);
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
file, linenum, options);
file, linenum, opts);
/* deny access */
return 0;
}

View File

@ -32,7 +32,7 @@
#include "canohost.h"
#include "readpass.h"
RCSID("$Id: auth-pam.c,v 1.22 2001/01/22 05:34:40 mouring Exp $");
RCSID("$Id: auth-pam.c,v 1.23 2001/02/04 12:20:19 djm Exp $");
#define NEW_AUTHTOK_MSG \
"Warning: Your password has expired, please change it now"
@ -211,10 +211,12 @@ int auth_pam_password(struct passwd *pw, const char *password)
int do_pam_account(char *username, char *remote_user)
{
int pam_retval;
extern ServerOptions options;
debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname());
debug("PAM setting rhost to \"%.200s\"",
get_canonical_hostname(options.reverse_mapping_check));
pam_retval = pam_set_item(pamh, PAM_RHOST,
get_canonical_hostname());
get_canonical_hostname(options.reverse_mapping_check));
if (pam_retval != PAM_SUCCESS) {
fatal("PAM set rhost failed[%d]: %.200s",
pam_retval, PAM_STRERROR(pamh, pam_retval));

View File

@ -13,7 +13,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.21 2001/01/21 19:05:42 markus Exp $");
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.22 2001/02/03 10:08:36 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
@ -49,7 +49,8 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
if (!auth_rhosts(pw, client_user))
return 0;
canonical_hostname = get_canonical_hostname();
canonical_hostname = get_canonical_hostname(
options.reverse_mapping_check);
debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);

View File

@ -14,7 +14,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rhosts.c,v 1.19 2001/01/21 19:05:42 markus Exp $");
RCSID("$OpenBSD: auth-rhosts.c,v 1.20 2001/02/03 10:08:36 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
@ -183,7 +183,7 @@ auth_rhosts(struct passwd *pw, const char *client_user)
stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
return 0;
hostname = get_canonical_hostname();
hostname = get_canonical_hostname(options.reverse_mapping_check);
ipaddr = get_remote_ipaddr();
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */

4
auth.c
View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.14 2001/01/21 19:05:43 markus Exp $");
RCSID("$OpenBSD: auth.c,v 1.15 2001/02/03 10:08:37 markus Exp $");
#ifdef HAVE_LOGIN_H
#include <login.h>
@ -228,7 +228,7 @@ auth_root_allowed(void)
log("Root login accepted for forced command.");
return 1;
} else {
log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
return 0;
}
}

12
auth1.c
View File

@ -266,8 +266,8 @@ do_authloop(Authctxt *authctxt)
#elif defined(HAVE_OSF_SIA)
/* Do SIA auth with password */
if (sia_validate_user(NULL, saved_argc, saved_argv,
get_canonical_hostname(), pw->pw_name, NULL, 0,
NULL, password) == SIASUCCESS) {
get_canonical_hostname(options.reverse_mapping_check),
pw->pw_name, NULL, 0, NULL, password) == SIASUCCESS) {
authenticated = 1;
}
#else /* !USE_PAM && !HAVE_OSF_SIA */
@ -347,7 +347,9 @@ do_authloop(Authctxt *authctxt)
if (authctxt->failures++ > AUTH_FAIL_MAX) {
#ifdef WITH_AIXAUTHENTICATE
loginfailed(user,get_canonical_hostname(),"ssh");
loginfailed(user,
get_canonical_hostname(options.reverse_mapping_check),
"ssh");
#endif /* WITH_AIXAUTHENTICATE */
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
}
@ -433,7 +435,9 @@ do_authentication()
#ifdef WITH_AIXAUTHENTICATE
/* We don't have a pty yet, so just label the line as "ssh" */
if (loginsuccess(authctxt->user,get_canonical_hostname(),"ssh",&aixloginmsg) < 0)
if (loginsuccess(authctxt->user,
get_canonical_hostname(options.reverse_mapping_check),
"ssh", &aixloginmsg) < 0)
aixloginmsg = NULL;
#endif /* WITH_AIXAUTHENTICATE */

13
auth2.c
View File

@ -310,7 +310,8 @@ userauth_reply(Authctxt *authctxt, int authenticated)
#ifdef WITH_AIXAUTHENTICATE
/* We don't have a pty yet, so just label the line as "ssh" */
if (loginsuccess(authctxt->user?authctxt->user:"NOUSER",
get_canonical_hostname(), "ssh", &aixloginmsg) < 0)
get_canonical_hostname(options.reverse_mapping_check),
"ssh", &aixloginmsg) < 0)
aixloginmsg = NULL;
#endif /* WITH_AIXAUTHENTICATE */
/* turn off userauth */
@ -354,8 +355,9 @@ userauth_none(Authctxt *authctxt)
return auth_pam_password(authctxt->pw, "");
#elif defined(HAVE_OSF_SIA)
return (sia_validate_user(NULL, saved_argc, saved_argv,
get_canonical_hostname(), authctxt->user?authctxt->user:"NOUSER",
NULL, 0, NULL, "") == SIASUCCESS);
get_canonical_hostname(options.reverse_mapping_check),
authctxt->user?authctxt->user:"NOUSER", NULL, 0,
NULL, "") == SIASUCCESS);
#else /* !HAVE_OSF_SIA && !USE_PAM */
return auth_password(authctxt->pw, "");
#endif /* USE_PAM */
@ -381,8 +383,9 @@ userauth_passwd(Authctxt *authctxt)
auth_pam_password(authctxt->pw, password) == 1)
#elif defined(HAVE_OSF_SIA)
sia_validate_user(NULL, saved_argc, saved_argv,
get_canonical_hostname(), authctxt->user?authctxt->user:"NOUSER",
NULL, 0, NULL, password) == SIASUCCESS)
get_canonical_hostname(options.reverse_mapping_check),
authctxt->user?authctxt->user:"NOUSER", NULL, 0, NULL,
password) == SIASUCCESS)
#else /* !USE_PAM && !HAVE_OSF_SIA */
auth_password(authctxt->pw, password) == 1)
#endif /* USE_PAM */

View File

@ -12,35 +12,35 @@
*/
#include "includes.h"
RCSID("$OpenBSD: canohost.c,v 1.19 2001/01/29 19:42:33 markus Exp $");
RCSID("$OpenBSD: canohost.c,v 1.20 2001/02/03 10:08:37 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
#include "log.h"
void check_ip_options(int socket, char *ipaddr);
/*
* Return the canonical name of the host at the other end of the socket. The
* caller should free the returned string with xfree.
*/
char *
get_remote_hostname(int socket)
get_remote_hostname(int socket, int reverse_mapping_check)
{
struct sockaddr_storage from;
int i;
socklen_t fromlen;
struct addrinfo hints, *ai, *aitop;
char name[MAXHOSTNAMELEN];
char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
/* Get IP address of client. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
#ifdef IPV4_IN_IPV6
if (from.ss_family == AF_INET6) {
struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
@ -63,6 +63,8 @@ get_remote_hostname(int socket)
}
}
#endif
if (from.ss_family == AF_INET)
check_ip_options(socket, ntop);
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
@ -70,99 +72,99 @@ get_remote_hostname(int socket)
/* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
NULL, 0, NI_NAMEREQD) == 0) {
/* Got host name. */
name[sizeof(name) - 1] = '\0';
/*
* Convert it to all lowercase (which is expected by the rest
* of this software).
*/
for (i = 0; name[i]; i++)
if (isupper(name[i]))
name[i] = tolower(name[i]);
/*
* Map it back to an IP address and check that the given
* address actually is an address of this host. This is
* necessary because anyone with access to a name server can
* define arbitrary names for an IP address. Mapping from
* name to IP address can be trusted better (but can still be
* fooled if the intruder has access to the name server of
* the domain).
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = from.ss_family;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
strlcpy(name, ntop, sizeof name);
goto check_ip_options;
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (!ai) {
/* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
ntop, name);
strlcpy(name, ntop, sizeof name);
goto check_ip_options;
}
/* Address was found for the host name. We accept the host name. */
} else {
/* Host name not found. Use ascii representation of the address. */
strlcpy(name, ntop, sizeof name);
log("Could not reverse map address %.100s.", name);
NULL, 0, NI_NAMEREQD) != 0) {
/* Host name not found. Use ip address. */
log("Could not reverse map address %.100s.", ntop);
return xstrdup(ntop);
}
check_ip_options:
/* Got host name. */
name[sizeof(name) - 1] = '\0';
/*
* If IP options are supported, make sure there are none (log and
* disconnect them if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts autentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
* Convert it to all lowercase (which is expected by the rest
* of this software).
*/
/* IP options -- IPv4 only */
if (from.ss_family == AF_INET) {
u_char options[200], *ucp;
char text[1024], *cp;
socklen_t option_size;
int ipproto;
struct protoent *ip;
for (i = 0; name[i]; i++)
if (isupper(name[i]))
name[i] = tolower(name[i]);
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options,
&option_size) >= 0 && option_size != 0) {
cp = text;
/* Note: "text" buffer must be at least 3x as big as options. */
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
sprintf(cp, " %2.2x", *ucp);
log("Connection from %.100s with IP options:%.800s",
ntop, text);
packet_disconnect("Connection from %.100s with IP options:%.800s",
ntop, text);
}
if (!reverse_mapping_check)
return xstrdup(name);
/*
* Map it back to an IP address and check that the given
* address actually is an address of this host. This is
* necessary because anyone with access to a name server can
* define arbitrary names for an IP address. Mapping from
* name to IP address can be trusted better (but can still be
* fooled if the intruder has access to the name server of
* the domain).
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = from.ss_family;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
log("reverse mapping checking getaddrinfo for %.700s "
"failed - POSSIBLE BREAKIN ATTEMPT!", name);
return xstrdup(ntop);
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (!ai) {
/* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not "
"map back to the address - POSSIBLE BREAKIN ATTEMPT!",
ntop, name);
return xstrdup(ntop);
}
return xstrdup(name);
}
/*
* If IP options are supported, make sure there are none (log and
* disconnect them if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts autentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
*/
/* IPv4 only */
void
check_ip_options(int socket, char *ipaddr)
{
u_char options[200], *ucp;
char text[1024], *cp;
socklen_t option_size;
int ipproto;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
&option_size) >= 0 && option_size != 0) {
cp = text;
/* Note: "text" buffer must be at least 3x as big as options. */
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
sprintf(cp, " %2.2x", *ucp);
log("Connection from %.100s with IP options:%.800s",
ipaddr, text);
packet_disconnect("Connection from %.100s with IP options:%.800s",
ipaddr, text);
}
}
/*
* Return the canonical name of the host in the other side of the current
* connection. The host name is cached, so it is efficient to call this
@ -170,20 +172,27 @@ check_ip_options:
*/
const char *
get_canonical_hostname()
get_canonical_hostname(int reverse_mapping_check)
{
static char *canonical_host_name = NULL;
static int reverse_mapping_checked = 0;
/* Check if we have previously retrieved this same name. */
if (canonical_host_name != NULL)
return canonical_host_name;
/* Check if we have previously retrieved name with same option. */
if (canonical_host_name != NULL) {
if (reverse_mapping_checked != reverse_mapping_check)
xfree(canonical_host_name);
else
return canonical_host_name;
}
/* Get the real hostname if socket; otherwise return UNKNOWN. */
if (packet_connection_is_on_socket())
canonical_host_name = get_remote_hostname(packet_get_connection_in());
canonical_host_name = get_remote_hostname(
packet_get_connection_in(), reverse_mapping_check);
else
canonical_host_name = xstrdup("UNKNOWN");
reverse_mapping_checked = reverse_mapping_check;
return canonical_host_name;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: canohost.h,v 1.3 2001/01/29 19:42:35 markus Exp $ */
/* $OpenBSD: canohost.h,v 1.4 2001/02/03 10:08:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -11,22 +11,17 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Returns the name of the machine at the other end of the socket. The
* returned string should be freed by the caller.
*/
char *get_remote_hostname(int socket);
/*
* Return the canonical name of the host in the other side of the current
* connection (as returned by packet_get_connection). The host name is
* cached, so it is efficient to call this several times.
*/
const char *get_canonical_hostname(void);
const char *get_canonical_hostname(int reverse_mapping_check);
/*
* Returns the IP-address of the remote host as a string. The returned
* string must not be freed.
* string is cached and must not be freed.
*/
const char *get_remote_ipaddr(void);

View File

@ -40,7 +40,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: channels.c,v 1.85 2001/01/29 19:42:35 markus Exp $");
RCSID("$OpenBSD: channels.c,v 1.88 2001/02/01 21:58:08 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
@ -600,7 +600,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
struct sockaddr addr;
int newsock, newch;
socklen_t addrlen;
char buf[1024], *remote_hostname, *rtype;
char buf[1024], *remote_ipaddr, *rtype;
int remote_port;
rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
@ -616,13 +616,13 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
error("accept: %.100s", strerror(errno));
return;
}
remote_hostname = get_remote_hostname(newsock);
remote_ipaddr = get_peer_ipaddr(newsock);
remote_port = get_peer_port(newsock);
snprintf(buf, sizeof buf,
"listen port %d for %.100s port %d, "
"connect from %.200s port %d",
c->listening_port, c->path, c->host_port,
remote_hostname, remote_port);
remote_ipaddr, remote_port);
newch = channel_new(rtype,
SSH_CHANNEL_OPENING, newsock, newsock, -1,
@ -644,7 +644,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
packet_put_int(c->host_port);
}
/* originator host and port */
packet_put_cstring(remote_hostname);
packet_put_cstring(remote_ipaddr);
packet_put_int(remote_port);
packet_send();
} else {
@ -657,7 +657,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
}
packet_send();
}
xfree(remote_hostname);
xfree(remote_ipaddr);
}
}

View File

@ -253,9 +253,13 @@ fi
%attr(4755,root,root) %{_bindir}/ssh
%attr(0755,root,root) %{_bindir}/ssh-agent
%attr(0755,root,root) %{_bindir}/ssh-add
%attr(0755,root,root) %{_bindir}/ssh-keyscan
%attr(0755,root,root) %{_bindir}/sftp
%attr(0644,root,root) %{_mandir}/man1/ssh.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-agent.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-add.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1*
%attr(0644,root,root) %{_mandir}/man1/sftp.1*
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh_config
%attr(-,root,root) %{_bindir}/slogin
%attr(-,root,root) %{_mandir}/man1/slogin.1*

View File

@ -223,9 +223,13 @@ fi
%attr(4755,root,root) %{_bindir}/ssh
%attr(0755,root,root) %{_bindir}/ssh-agent
%attr(0755,root,root) %{_bindir}/ssh-add
%attr(0755,root,root) %{_bindir}/ssh-keyscan
%attr(0755,root,root) %{_bindir}/sftp
%attr(0644,root,root) %{_mandir}/man1/ssh.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-agent.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-add.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1*
%attr(0644,root,root) %{_mandir}/man1/sftp.1*
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh_config
%attr(-,root,root) %{_bindir}/slogin
%attr(-,root,root) %{_mandir}/man1/slogin.1*

View File

@ -180,6 +180,8 @@ fi
%attr(-,root,root) /usr/bin/slogin
%attr(0755,root,root) /usr/bin/ssh-agent
%attr(0755,root,root) /usr/bin/ssh-add
%attr(0755,root,root) /usr/bin/ssh-keyscan
%attr(0755,root,root) /usr/bin/sftp
%attr(0755,root,root) /usr/sbin/sshd
%attr(-,root,root) /usr/sbin/rcsshd
%attr(0755,root,root) %dir /usr/lib/ssh

3
scp.1
View File

@ -9,7 +9,7 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $OpenBSD: scp.1,v 1.13 2000/10/16 09:38:44 djm Exp $
.\" $OpenBSD: scp.1,v 1.14 2001/02/04 11:11:53 djm Exp $
.\"
.Dd September 25, 1999
.Dt SCP 1
@ -129,6 +129,7 @@ program in BSD source code from the Regents of the University of
California.
.Sh SEE ALSO
.Xr rcp 1 ,
.Xr sftp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,

View File

@ -10,7 +10,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: servconf.c,v 1.63 2001/01/22 23:06:39 markus Exp $");
RCSID("$OpenBSD: servconf.c,v 1.64 2001/02/03 10:08:37 markus Exp $");
#ifdef KRB4
#include <krb.h>
@ -92,6 +92,7 @@ initialize_server_options(ServerOptions *options)
options->max_startups_rate = -1;
options->max_startups = -1;
options->banner = NULL;
options->reverse_mapping_check = -1;
}
void
@ -186,6 +187,8 @@ fill_default_server_options(ServerOptions *options)
options->max_startups_rate = 100; /* 100% */
if (options->max_startups_begin == -1)
options->max_startups_begin = options->max_startups;
if (options->reverse_mapping_check == -1)
options->reverse_mapping_check = 0;
}
/* Keyword tokens. */
@ -208,7 +211,7 @@ typedef enum {
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sCiphers, sProtocol, sPidFile,
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
sBanner
sBanner, sReverseMappingCheck
} ServerOpCodes;
/* Textual representation of the tokens. */
@ -268,6 +271,7 @@ static struct {
{ "subsystem", sSubsystem },
{ "maxstartups", sMaxStartups },
{ "banner", sBanner },
{ "reversemappingcheck", sReverseMappingCheck },
{ NULL, 0 }
};
@ -577,6 +581,10 @@ parse_flag:
intptr = &options->gateway_ports;
goto parse_flag;
case sReverseMappingCheck:
intptr = &options->reverse_mapping_check;
goto parse_flag;
case sLogFacility:
intptr = (int *) &options->log_facility;
arg = strdelim(&cp);

View File

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: servconf.h,v 1.35 2001/01/22 23:06:40 markus Exp $"); */
/* RCSID("$OpenBSD: servconf.h,v 1.36 2001/02/03 10:08:37 markus Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@ -102,6 +102,7 @@ typedef struct {
int max_startups_rate;
int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
} ServerOptions;
/*

View File

@ -33,7 +33,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: session.c,v 1.51 2001/01/21 19:05:56 markus Exp $");
RCSID("$OpenBSD: session.c,v 1.52 2001/02/03 10:08:37 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
@ -683,7 +683,7 @@ get_remote_name_or_ip(void)
{
static const char *remote = "";
if (utmp_len > 0)
remote = get_canonical_hostname();
remote = get_canonical_hostname(options.reverse_mapping_check);
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
@ -1061,7 +1061,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
#ifdef HAVE_OSF_SIA
extern char **saved_argv;
extern int saved_argc;
char *host = get_canonical_hostname ();
char *host = get_canonical_hostname(options.reverse_mapping_check);
if (sia_become_user(NULL, saved_argc, saved_argv, host,
pw->pw_name, ttyname, 0, NULL, NULL, SIA_BEU_SETLUID) !=

792
sftp-client.c Normal file
View File

@ -0,0 +1,792 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* XXX: memleaks */
/* XXX: signed vs unsigned */
/* XXX: redesign to allow concurrent overlapped operations */
/* XXX: we use fatal too much, error may be more appropriate in places */
/* XXX: copy between two remote sites */
#include "includes.h"
RCSID("$OpenBSD: sftp-client.c,v 1.1 2001/02/04 11:11:54 djm Exp $");
#include "ssh.h"
#include "buffer.h"
#include "bufaux.h"
#include "getput.h"
#include "xmalloc.h"
#include "log.h"
#include "atomicio.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
/* How much data to read/write at at time during copies */
/* XXX: what should this be? */
#define COPY_SIZE 8192
void
send_msg(int fd, Buffer *m)
{
int mlen = buffer_len(m);
int len;
Buffer oqueue;
buffer_init(&oqueue);
buffer_put_int(&oqueue, mlen);
buffer_append(&oqueue, buffer_ptr(m), mlen);
buffer_consume(m, mlen);
len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
if (len <= 0)
fatal("Couldn't send packet: %s", strerror(errno));
buffer_free(&oqueue);
}
void
get_msg(int fd, Buffer *m)
{
u_int len, msg_len;
unsigned char buf[4096];
len = atomicio(read, fd, buf, 4);
if (len != 4)
fatal("Couldn't read packet: %s", strerror(errno));
msg_len = GET_32BIT(buf);
if (msg_len > 256 * 1024)
fatal("Received message too long %d", msg_len);
while (msg_len) {
len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
if (len <= 0)
fatal("Couldn't read packet: %s", strerror(errno));
msg_len -= len;
buffer_append(m, buf, len);
}
}
void
send_string_request(int fd, u_int id, u_int code, char *s,
u_int len)
{
Buffer msg;
buffer_init(&msg);
buffer_put_char(&msg, code);
buffer_put_int(&msg, id);
buffer_put_string(&msg, s, len);
send_msg(fd, &msg);
debug3("Sent message fd %d T:%d I:%d", fd, code, id);
buffer_free(&msg);
}
void
send_string_attrs_request(int fd, u_int id, u_int code, char *s,
u_int len, Attrib *a)
{
Buffer msg;
buffer_init(&msg);
buffer_put_char(&msg, code);
buffer_put_int(&msg, id);
buffer_put_string(&msg, s, len);
encode_attrib(&msg, a);
send_msg(fd, &msg);
debug3("Sent message fd %d T:%d I:%d", fd, code, id);
buffer_free(&msg);
}
u_int
get_status(int fd, int expected_id)
{
Buffer msg;
u_int type, id, status;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type != SSH2_FXP_STATUS)
fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
SSH2_FXP_STATUS, type);
status = buffer_get_int(&msg);
buffer_free(&msg);
debug3("SSH2_FXP_STATUS %d", status);
return(status);
}
char *
get_handle(int fd, u_int expected_id, u_int *len)
{
Buffer msg;
u_int type, id;
char *handle;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
error("Couldn't get handle: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_HANDLE)
fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
SSH2_FXP_HANDLE, type);
handle = buffer_get_string(&msg, len);
buffer_free(&msg);
return(handle);
}
Attrib *
get_decode_stat(int fd, u_int expected_id)
{
Buffer msg;
u_int type, id;
Attrib *a;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received stat reply T:%d I:%d", type, id);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
error("Couldn't stat remote file: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
SSH2_FXP_ATTRS, type);
}
a = decode_attrib(&msg);
buffer_free(&msg);
return(a);
}
int
do_init(int fd_in, int fd_out)
{
int type, version;
Buffer msg;
buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_INIT);
buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
send_msg(fd_out, &msg);
buffer_clear(&msg);
get_msg(fd_in, &msg);
/* Expecting a VERSION reply */
if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
error("Invalid packet back from SSH2_FXP_INIT (type %d)",
type);
buffer_free(&msg);
return(-1);
}
version = buffer_get_int(&msg);
debug2("Remote version: %d", version);
/* Check for extensions */
while (buffer_len(&msg) > 0) {
char *name = buffer_get_string(&msg, NULL);
char *value = buffer_get_string(&msg, NULL);
debug2("Init extension: \"%s\"", name);
xfree(name);
xfree(value);
}
buffer_free(&msg);
return(0);
}
int
do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
{
u_int id, status;
Buffer msg;
buffer_init(&msg);
id = arc4random();
buffer_put_char(&msg, SSH2_FXP_CLOSE);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't close file: %s", fx2txt(status));
buffer_free(&msg);
return(status);
}
int
do_ls(int fd_in, int fd_out, char *path)
{
Buffer msg;
u_int type, id, handle_len, i, expected_id;
char *handle;
id = arc4random();
buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_OPENDIR);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, path);
send_msg(fd_out, &msg);
buffer_clear(&msg);
handle = get_handle(fd_in, id, &handle_len);
if (handle == NULL)
return(-1);
for(;;) {
int count;
expected_id = ++id;
debug3("Sending SSH2_FXP_READDIR I:%d", id);
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_READDIR);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
send_msg(fd_out, &msg);
buffer_clear(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received reply T:%d I:%d", type, id);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
debug3("Received SSH2_FXP_STATUS %d", status);
if (status == SSH2_FX_EOF) {
break;
} else {
error("Couldn't read directory: %s",
fx2txt(status));
do_close(fd_in, fd_out, handle, handle_len);
return(NULL);
}
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
SSH2_FXP_NAME, type);
count = buffer_get_int(&msg);
debug3("Received %i SSH2_FXP_NAME responses", count);
for(i = 0; i < count; i++) {
char *filename, *longname;
Attrib *a;
filename = buffer_get_string(&msg, NULL);
longname = buffer_get_string(&msg, NULL);
a = decode_attrib(&msg);
printf("%s\n", longname);
xfree(filename);
xfree(longname);
}
}
buffer_free(&msg);
do_close(fd_in, fd_out, handle, handle_len);
xfree(handle);
return(0);
}
int
do_rm(int fd_in, int fd_out, char *path)
{
u_int status, id;
debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
id = arc4random();
send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't delete file: %s", fx2txt(status));
return(status);
}
int
do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
{
u_int status, id;
id = arc4random();
send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
strlen(path), a);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't create directory: %s", fx2txt(status));
return(status);
}
int
do_rmdir(int fd_in, int fd_out, char *path)
{
u_int status, id;
id = arc4random();
send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't remove directory: %s", fx2txt(status));
return(status);
}
Attrib *
do_stat(int fd_in, int fd_out, char *path)
{
u_int id;
id = arc4random();
send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
return(get_decode_stat(fd_in, id));
}
Attrib *
do_lstat(int fd_in, int fd_out, char *path)
{
u_int id;
id = arc4random();
send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
return(get_decode_stat(fd_in, id));
}
Attrib *
do_fstat(int fd_in, int fd_out, char *handle,
u_int handle_len)
{
u_int id;
id = arc4random();
send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
return(get_decode_stat(fd_in, id));
}
int
do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
{
u_int status, id;
id = arc4random();
send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
strlen(path), a);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't setstat on \"%s\": %s", path,
fx2txt(status));
return(status);
}
int
do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
Attrib *a)
{
u_int status, id;
id = arc4random();
send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
handle_len, a);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't fsetstat: %s", fx2txt(status));
return(status);
}
char *
do_realpath(int fd_in, int fd_out, char *path)
{
Buffer msg;
u_int type, expected_id, count, id;
char *filename, *longname;
Attrib *a;
expected_id = id = arc4random();
send_string_request(fd_out, id, SSH2_FXP_REALPATH, path,
strlen(path));
buffer_init(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status = buffer_get_int(&msg);
error("Couldn't canonicalise: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
SSH2_FXP_NAME, type);
count = buffer_get_int(&msg);
if (count != 1)
fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
filename = buffer_get_string(&msg, NULL);
longname = buffer_get_string(&msg, NULL);
a = decode_attrib(&msg);
debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
xfree(longname);
buffer_free(&msg);
return(filename);
}
int
do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
{
Buffer msg;
u_int status, id;
buffer_init(&msg);
/* Send rename request */
id = arc4random();
buffer_put_char(&msg, SSH2_FXP_RENAME);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, oldpath);
buffer_put_cstring(&msg, newpath);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
newpath);
buffer_free(&msg);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
fx2txt(status));
return(status);
}
int
do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
int pflag)
{
int local_fd;
u_int expected_id, handle_len, mode, type, id;
u_int64_t offset;
char *handle;
Buffer msg;
Attrib junk, *a;
a = do_stat(fd_in, fd_out, remote_path);
if (a == NULL)
return(-1);
/* XXX: should we preserve set[ug]id? */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
mode = S_IWRITE | (a->perm & 0777);
else
mode = 0666;
local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (local_fd == -1) {
error("Couldn't open local file \"%s\" for writing: %s",
local_path, strerror(errno));
return(errno);
}
/* Override umask and utimes if asked */
if (pflag && fchmod(local_fd, mode) == -1)
error("Couldn't set mode on \"%s\": %s", local_path,
strerror(errno));
if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
struct timeval tv;
tv.tv_sec = a->atime;
tv.tv_usec = a->mtime;
if (utimes(local_path, &tv) == -1)
error("Can't set times on \"%s\": %s", local_path,
strerror(errno));
}
buffer_init(&msg);
/* Send open request */
id = arc4random();
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, remote_path);
buffer_put_int(&msg, SSH2_FXF_READ);
attrib_clear(&junk); /* Send empty attributes */
encode_attrib(&msg, &junk);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
handle = get_handle(fd_in, id, &handle_len);
if (handle == NULL) {
buffer_free(&msg);
close(local_fd);
return(-1);
}
/* Read from remote and write to local */
offset = 0;
for(;;) {
u_int len;
char *data;
expected_id = ++id;
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_READ);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
buffer_put_int64(&msg, offset);
buffer_put_int(&msg, COPY_SIZE);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
id, offset, COPY_SIZE);
buffer_clear(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received reply T:%d I:%d", type, id);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
if (status == SSH2_FX_EOF)
break;
else {
error("Couldn't read from remote "
"file \"%s\" : %s", remote_path,
fx2txt(status));
do_close(fd_in, fd_out, handle, handle_len);
xfree(handle);
close(local_fd);
buffer_free(&msg);
return(status);
}
} else if (type != SSH2_FXP_DATA) {
fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
SSH2_FXP_DATA, type);
}
data = buffer_get_string(&msg, &len);
if (len > COPY_SIZE)
fatal("Received more data than asked for %d > %d",
len, COPY_SIZE);
debug3("In read loop, got %d offset %lld", len, offset);
if (atomicio(write, local_fd, data, len) != len) {
error("Couldn't write to \"%s\": %s", local_path,
strerror(errno));
do_close(fd_in, fd_out, handle, handle_len);
xfree(handle);
close(local_fd);
xfree(data);
buffer_free(&msg);
return(-1);
}
offset += len;
xfree(data);
}
xfree(handle);
buffer_free(&msg);
close(local_fd);
return(do_close(fd_in, fd_out, handle, handle_len));
}
int
do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
int pflag)
{
int local_fd;
u_int handle_len, id;
u_int64_t offset;
char *handle;
Buffer msg;
struct stat sb;
Attrib a;
if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
error("Couldn't open local file \"%s\" for reading: %s",
local_path, strerror(errno));
return(-1);
}
if (fstat(local_fd, &sb) == -1) {
error("Couldn't fstat local file \"%s\": %s",
local_path, strerror(errno));
close(local_fd);
return(-1);
}
stat_to_attrib(&sb, &a);
a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
a.perm &= 0777;
if (!pflag)
a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
buffer_init(&msg);
/* Send open request */
id = arc4random();
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, remote_path);
buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
encode_attrib(&msg, &a);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
buffer_clear(&msg);
handle = get_handle(fd_in, id, &handle_len);
if (handle == NULL) {
close(local_fd);
buffer_free(&msg);
return(-1);
}
/* Override umask and utimes if asked */
if (pflag)
do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
/* Read from local and write to remote */
offset = 0;
for(;;) {
int len;
char data[COPY_SIZE];
u_int status;
/*
* Can't use atomicio here because it returns 0 on EOF, thus losing
* the last block of the file
*/
do
len = read(local_fd, data, COPY_SIZE);
while ((len == -1) && (errno == EINTR || errno == EAGAIN));
if (len == -1)
fatal("Couldn't read from \"%s\": %s", local_path,
strerror(errno));
if (len == 0)
break;
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_WRITE);
buffer_put_int(&msg, ++id);
buffer_put_string(&msg, handle, handle_len);
buffer_put_int64(&msg, offset);
buffer_put_string(&msg, data, len);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
id, offset, len);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK) {
error("Couldn't write to remote file \"%s\": %s",
remote_path, fx2txt(status));
do_close(fd_in, fd_out, handle, handle_len);
xfree(handle);
close(local_fd);
return(-1);
}
debug3("In write loop, got %d offset %lld", len, offset);
offset += len;
}
xfree(handle);
buffer_free(&msg);
if (close(local_fd) == -1) {
error("Couldn't close local file \"%s\": %s", local_path,
strerror(errno));
do_close(fd_in, fd_out, handle, handle_len);
return(-1);
}
return(do_close(fd_in, fd_out, handle, handle_len));
}

84
sftp-client.h Normal file
View File

@ -0,0 +1,84 @@
/* $OpenBSD: sftp-client.h,v 1.1 2001/02/04 11:11:54 djm Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Client side of SSH2 filexfer protocol */
/* Initialiase a SSH filexfer connection */
int do_init(int fd_in, int fd_out);
/* Close file referred to by 'handle' */
int do_close(int fd_in, int fd_out, char *handle, u_int handle_len);
/* List contents of directory 'path' to stdout */
int do_ls(int fd_in, int fd_out, char *path);
/* Delete file 'path' */
int do_rm(int fd_in, int fd_out, char *path);
/* Create directory 'path' */
int do_mkdir(int fd_in, int fd_out, char *path, Attrib *a);
/* Remove directory 'path' */
int do_rmdir(int fd_in, int fd_out, char *path);
/* Get file attributes of 'path' (follows symlinks) */
Attrib *do_stat(int fd_in, int fd_out, char *path);
/* Get file attributes of 'path' (does not follow symlinks) */
Attrib *do_lstat(int fd_in, int fd_out, char *path);
/* Get file attributes of open file 'handle' */
Attrib *do_fstat(int fd_in, int fd_out, char *handle,
u_int handle_len);
/* Set file attributes of 'path' */
int do_setstat(int fd_in, int fd_out, char *path, Attrib *a);
/* Set file attributes of open file 'handle' */
int do_fsetstat(int fd_in, int fd_out, char *handle,
u_int handle_len, Attrib *a);
/* Canonicalise 'path' - caller must free result */
char *do_realpath(int fd_in, int fd_out, char *path);
/* Rename 'oldpath' to 'newpath' */
int do_rename(int fd_in, int fd_out, char *oldpath, char *newpath);
/* XXX: add callbacks to do_download/do_upload so we can do progress meter */
/*
* Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
int pflag);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
int pflag);

146
sftp-common.c Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-common.c,v 1.1 2001/02/04 11:11:54 djm Exp $");
#include "buffer.h"
#include "bufaux.h"
#include "getput.h"
#include "log.h"
#include "xmalloc.h"
#include "sftp.h"
#include "sftp-common.h"
void
attrib_clear(Attrib *a)
{
a->flags = 0;
a->size = 0;
a->uid = 0;
a->gid = 0;
a->perm = 0;
a->atime = 0;
a->mtime = 0;
}
void
stat_to_attrib(struct stat *st, Attrib *a)
{
attrib_clear(a);
a->flags = 0;
a->flags |= SSH2_FILEXFER_ATTR_SIZE;
a->size = st->st_size;
a->flags |= SSH2_FILEXFER_ATTR_UIDGID;
a->uid = st->st_uid;
a->gid = st->st_gid;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a->perm = st->st_mode;
a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
a->atime = st->st_atime;
a->mtime = st->st_mtime;
}
Attrib *
decode_attrib(Buffer *b)
{
static Attrib a;
attrib_clear(&a);
a.flags = buffer_get_int(b);
if (a.flags & SSH2_FILEXFER_ATTR_SIZE)
a.size = buffer_get_int64(b);
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
a.uid = buffer_get_int(b);
a.gid = buffer_get_int(b);
}
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
a.perm = buffer_get_int(b);
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
a.atime = buffer_get_int(b);
a.mtime = buffer_get_int(b);
}
/* vendor-specific extensions */
if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) {
char *type, *data;
int i, count;
count = buffer_get_int(b);
for (i = 0; i < count; i++) {
type = buffer_get_string(b, NULL);
data = buffer_get_string(b, NULL);
debug3("Got file attribute \"%s\"", type);
xfree(type);
xfree(data);
}
}
return &a;
}
void
encode_attrib(Buffer *b, Attrib *a)
{
buffer_put_int(b, a->flags);
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
buffer_put_int64(b, a->size);
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
buffer_put_int(b, a->uid);
buffer_put_int(b, a->gid);
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
buffer_put_int(b, a->perm);
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
buffer_put_int(b, a->atime);
buffer_put_int(b, a->mtime);
}
}
const char *
fx2txt(int status)
{
switch (status) {
case SSH2_FX_OK:
return("No Error");
case SSH2_FX_EOF:
return("End of File");
case SSH2_FX_NO_SUCH_FILE:
return("No Such File");
case SSH2_FX_PERMISSION_DENIED:
return("Permission Denied");
case SSH2_FX_FAILURE:
return("Failure");
case SSH2_FX_BAD_MESSAGE:
return("Bad message");
case SSH2_FX_NO_CONNECTION:
return("No connection");
case SSH2_FX_CONNECTION_LOST:
return("Connection lost");
case SSH2_FX_OP_UNSUPPORTED:
return("Operation unsupported");
default:
return("Unknown status");
};
/* NOTREACHED */
}

55
sftp-common.h Normal file
View File

@ -0,0 +1,55 @@
/* $OpenBSD: sftp-common.h,v 1.1 2001/02/04 11:11:54 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
typedef struct Attrib Attrib;
/* File attributes */
struct Attrib {
u_int32_t flags;
u_int64_t size;
u_int32_t uid;
u_int32_t gid;
u_int32_t perm;
u_int32_t atime;
u_int32_t mtime;
};
/* Clear contents of attributes structure */
void attrib_clear(Attrib *a);
/* Convert from struct stat to filexfer attribs */
void stat_to_attrib(struct stat *st, Attrib *a);
/* Decode attributes in buffer */
Attrib *decode_attrib(Buffer *b);
/* Encode attributes to buffer */
void encode_attrib(Buffer *b, Attrib *a);
/* Convert from SSH2_FX_ status to text error message */
const char *fx2txt(int status);

583
sftp-int.c Normal file
View File

@ -0,0 +1,583 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* XXX: finish implementation of all commands */
/* XXX: do fnmatch() instead of using raw pathname */
/* XXX: recursive operations */
#include "includes.h"
RCSID("$OpenBSD: sftp-int.c,v 1.1 2001/02/04 11:11:54 djm Exp $");
#include "buffer.h"
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
#include "sftp-int.h"
/* Seperators for interactive commands */
#define WHITESPACE " \t\r\n"
/* Commands for interactive mode */
#define I_CHDIR 1
#define I_CHGRP 2
#define I_CHMOD 3
#define I_CHOWN 4
#define I_GET 5
#define I_HELP 6
#define I_LCHDIR 7
#define I_LLS 8
#define I_LMKDIR 9
#define I_LPWD 10
#define I_LS 11
#define I_LUMASK 12
#define I_MKDIR 13
#define I_PUT 14
#define I_PWD 15
#define I_QUIT 16
#define I_RENAME 17
#define I_RM 18
#define I_RMDIR 19
#define I_SHELL 20
struct CMD {
const int n;
const char *c;
};
const struct CMD cmds[] = {
{ I_CHDIR, "CD" },
{ I_CHDIR, "CHDIR" },
{ I_CHDIR, "LCD" },
{ I_CHGRP, "CHGRP" },
{ I_CHMOD, "CHMOD" },
{ I_CHOWN, "CHOWN" },
{ I_HELP, "HELP" },
{ I_GET, "GET" },
{ I_LCHDIR, "LCHDIR" },
{ I_LLS, "LLS" },
{ I_LMKDIR, "LMKDIR" },
{ I_LPWD, "LPWD" },
{ I_LS, "LS" },
{ I_LUMASK, "LUMASK" },
{ I_MKDIR, "MKDIR" },
{ I_PUT, "PUT" },
{ I_PWD, "PWD" },
{ I_QUIT, "EXIT" },
{ I_QUIT, "QUIT" },
{ I_RENAME, "RENAME" },
{ I_RMDIR, "RMDIR" },
{ I_RM, "RM" },
{ I_SHELL, "!" },
{ -1, NULL}
};
void
help(void)
{
printf("Available commands:\n");
printf("CD path Change remote directory to 'path'\n");
printf("LCD path Change local directory to 'path'\n");
printf("CHGRP grp path Change group of file 'path' to 'grp'\n");
printf("CHMOD mode path Change permissions of file 'path' to 'mode'\n");
printf("CHOWN own path Change owner of file 'path' to 'own'\n");
printf("HELP Display this help text\n");
printf("GET remote-path [local-path] Download file\n");
printf("LLS [ls options] [path] Display local directory listing\n");
printf("LMKDIR path Create local directory\n");
printf("LPWD Print local working directory\n");
printf("LS [path] Display remote directory listing\n");
printf("LUMASK umask Set local umask to 'umask'\n");
printf("MKDIR path Create remote directory\n");
printf("PUT local-path [remote-path] Upload file\n");
printf("PWD Display remote working directory\n");
printf("EXIT Quit sftp\n");
printf("QUIT Quit sftp\n");
printf("RENAME oldpath newpath Rename remote file\n");
printf("RMDIR path Remove remote directory\n");
printf("RM path Delete remote file\n");
printf("!command Execute 'command' in local shell\n");
printf("! Escape to local shell\n");
}
void
local_do_shell(const char *args)
{
int ret, status;
char *shell;
pid_t pid;
if (!*args)
args = NULL;
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
if ((pid = fork()) == -1)
fatal("Couldn't fork: %s", strerror(errno));
if (pid == 0) {
/* XXX: child has pipe fds to ssh subproc open - issue? */
if (args) {
debug3("Executing %s -c \"%s\"", shell, args);
ret = execl(shell, shell, "-c", args, NULL);
} else {
debug3("Executing %s", shell);
ret = execl(shell, shell, NULL);
}
fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
strerror(errno));
_exit(1);
}
if (waitpid(pid, &status, 0) == -1)
fatal("Couldn't wait for child: %s", strerror(errno));
if (!WIFEXITED(status))
error("Shell exited abormally");
else if (WEXITSTATUS(status))
error("Shell exited with status %d", WEXITSTATUS(status));
}
void
local_do_ls(const char *args)
{
if (!args || !*args)
local_do_shell("ls");
else {
char *buf = xmalloc(8 + strlen(args) + 1);
/* XXX: quoting - rip quoting code from ftp? */
sprintf(buf, "/bin/ls %s", args);
local_do_shell(buf);
}
}
char *
make_absolute(char *p, char *pwd)
{
char buf[2048];
/* Derelativise */
if (p && p[0] != '/') {
snprintf(buf, sizeof(buf), "%s/%s", pwd, p);
xfree(p);
p = xstrdup(buf);
}
return(p);
}
int
parse_getput_flags(const char **cpp, int *pflag)
{
const char *cp = *cpp;
/* Check for flags */
if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) {
switch (*cp) {
case 'P':
*pflag = 1;
break;
default:
error("Invalid flag -%c", *cp);
return(-1);
}
cp += 2;
*cpp = cp + strspn(cp, WHITESPACE);
}
return(0);
}
int
get_pathname(const char **cpp, char **path)
{
const char *quot, *cp = *cpp;
int i;
cp += strspn(cp, WHITESPACE);
if (!*cp) {
*cpp = cp;
*path = NULL;
return(0);
}
/* Check for quoted filenames */
if (*cp == '\"' || *cp == '\'') {
quot = cp++;
for(i = 0; cp[i] && cp[i] != *quot; i++)
;
if (!cp[i]) {
error("Unterminated quote");
*path = NULL;
return(-1);
}
if (i == 0) {
error("Empty quotes");
*path = NULL;
return(-1);
}
*path = xmalloc(i + 1);
memcpy(*path, cp, i);
(*path)[i] = '\0';
cp += i + 1;
*cpp = cp + strspn(cp, WHITESPACE);
return(0);
}
/* Read to end of filename */
for(i = 0; cp[i] && cp[i] != ' '; i++)
;
*path = xmalloc(i + 1);
memcpy(*path, cp, i);
(*path)[i] = '\0';
cp += i;
*cpp = cp + strspn(cp, WHITESPACE);
return(0);
}
int
infer_path(const char *p, char **ifp)
{
char *cp;
debug("XXX: P = \"%s\"", p);
cp = strrchr(p, '/');
if (cp == NULL) {
*ifp = xstrdup(p);
return(0);
}
if (!cp[1]) {
error("Invalid path");
return(-1);
}
*ifp = xstrdup(cp + 1);
return(0);
}
int
parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
int i, cmdnum;
/* Skip leading whitespace */
cp = cp + strspn(cp, WHITESPACE);
/* Ignore blank lines */
if (!*cp)
return(-1);
/* Figure out which command we have */
for(i = 0; cmds[i].c; i++) {
int cmdlen = strlen(cmds[i].c);
/* Check for command followed by whitespace */
if (!strncasecmp(cp, cmds[i].c, cmdlen) &&
strchr(WHITESPACE, cp[cmdlen])) {
cp += cmdlen;
cp = cp + strspn(cp, WHITESPACE);
break;
}
}
cmdnum = cmds[i].n;
cmd = cmds[i].c;
/* Special case */
if (*cp == '!') {
cp++;
cmdnum = I_SHELL;
} else if (cmdnum == -1) {
error("Invalid command.");
return(-1);
}
/* Get arguments and parse flags */
*pflag = *n_arg = 0;
*path1 = *path2 = NULL;
switch (cmdnum) {
case I_GET:
case I_PUT:
if (parse_getput_flags(&cp, pflag))
return(-1);
/* Get first pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (*path1 == NULL) {
error("You must specify at least one path after a "
"%s command.", cmd);
return(-1);
}
/* Try to get second pathname (optional) */
if (get_pathname(&cp, path2))
return(-1);
/* Otherwise try to guess it from first path */
if (*path2 == NULL && infer_path(*path1, path2))
return(-1);
break;
case I_RENAME:
/* Get first pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (get_pathname(&cp, path2))
return(-1);
if (!*path1 || !*path2) {
error("You must specify two paths after a %s "
"command.", cmd);
return(-1);
}
break;
case I_RM:
case I_MKDIR:
case I_RMDIR:
case I_CHDIR:
case I_LCHDIR:
case I_LMKDIR:
/* Get pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (*path1 == NULL) {
error("You must specify a path after a %s command.",
cmd);
return(-1);
}
break;
case I_LS:
/* Path is optional */
if (get_pathname(&cp, path1))
return(-1);
break;
case I_LLS:
case I_SHELL:
/* Uses the rest of the line */
break;
case I_LUMASK:
case I_CHMOD:
case I_CHOWN:
case I_CHGRP:
/* Get numeric arg (mandatory) */
if (*cp < '0' && *cp > '9') {
error("You must supply a numeric argument "
"to the %s command.", cmd);
return(-1);
}
*n_arg = strtoul(cp, (char**)&cp, 0);
if (!*cp || !strchr(WHITESPACE, *cp)) {
error("You must supply a numeric argument "
"to the %s command.", cmd);
return(-1);
}
cp += strspn(cp, WHITESPACE);
/* Get pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (*path1 == NULL) {
error("You must specify a path after a %s command.",
cmd);
return(-1);
}
break;
case I_QUIT:
case I_PWD:
case I_LPWD:
case I_HELP:
break;
default:
fatal("Command not implemented");
}
*cpp = cp;
return(cmdnum);
}
int
parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
{
char *path1, *path2;
int pflag, cmdnum;
unsigned long n_arg;
Attrib a, *aa;
char path_buf[PATH_MAX];
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
/* Perform command */
switch (cmdnum) {
case -1:
break;
case I_GET:
path1 = make_absolute(path1, *pwd);
do_download(in, out, path1, path2, pflag);
break;
case I_PUT:
path2 = make_absolute(path2, *pwd);
do_upload(in, out, path1, path2, pflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
do_rename(in, out, path1, path2);
break;
case I_RM:
path1 = make_absolute(path1, *pwd);
do_rm(in, out, path1);
break;
case I_MKDIR:
path1 = make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
do_mkdir(in, out, path1, &a);
break;
case I_RMDIR:
path1 = make_absolute(path1, *pwd);
do_rmdir(in, out, path1);
break;
case I_CHDIR:
path1 = make_absolute(path1, *pwd);
xfree(*pwd);
*pwd = do_realpath(in, out, path1);
break;
case I_LS:
path1 = make_absolute(path1, *pwd);
do_ls(in, out, path1?path1:*pwd);
break;
case I_LCHDIR:
if (chdir(path1) == -1)
error("Couldn't change local directory to "
"\"%s\": %s", path1, strerror(errno));
break;
case I_LMKDIR:
if (mkdir(path1, 0777) == -1)
error("Couldn't create local directory to "
"\"%s\": %s", path1, strerror(errno));
break;
case I_LLS:
local_do_ls(cmd);
break;
case I_SHELL:
local_do_shell(cmd);
break;
case I_LUMASK:
umask(n_arg);
break;
case I_CHMOD:
path1 = make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = n_arg;
do_setstat(in, out, path1, &a);
case I_CHOWN:
path1 = make_absolute(path1, *pwd);
aa = do_stat(in, out, path1);
if (!aa->flags & SSH2_FILEXFER_ATTR_UIDGID) {
error("Can't get current ownership of "
"remote file \"%s\"", path1);
break;
}
aa->uid = n_arg;
do_setstat(in, out, path1, aa);
break;
case I_CHGRP:
path1 = make_absolute(path1, *pwd);
aa = do_stat(in, out, path1);
if (!aa->flags & SSH2_FILEXFER_ATTR_UIDGID) {
error("Can't get current ownership of "
"remote file \"%s\"", path1);
break;
}
aa->gid = n_arg;
do_setstat(in, out, path1, aa);
break;
case I_PWD:
printf("Remote working directory: %s\n", *pwd);
break;
case I_LPWD:
if (!getcwd(path_buf, sizeof(path_buf)))
error("Couldn't get local cwd: %s\n",
strerror(errno));
else
printf("Local working directory: %s\n",
path_buf);
break;
case I_QUIT:
return(-1);
case I_HELP:
help();
break;
default:
fatal("%d is not implemented", cmdnum);
}
if (path1)
xfree(path1);
if (path2)
xfree(path2);
return(0);
}
void
interactive_loop(int fd_in, int fd_out)
{
char *pwd;
char cmd[2048];
pwd = do_realpath(fd_in, fd_out, ".");
if (pwd == NULL)
fatal("Need cwd");
setlinebuf(stdout);
setlinebuf(stdin);
for(;;) {
char *cp;
printf("sftp> ");
/* XXX: use libedit */
if (fgets(cmd, sizeof(cmd), stdin) == NULL) {
printf("\n");
break;
}
cp = strrchr(cmd, '\n');
if (cp)
*cp = '\0';
if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd))
break;
}
xfree(pwd);
}

27
sftp-int.h Normal file
View File

@ -0,0 +1,27 @@
/* $OpenBSD: sftp-int.h,v 1.1 2001/02/04 11:11:54 djm Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void interactive_loop(int fd_in, int fd_out);

View File

@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-server.c,v 1.14 2001/01/21 19:05:56 markus Exp $");
RCSID("$OpenBSD: sftp-server.c,v 1.15 2001/02/04 11:11:54 djm Exp $");
#include "buffer.h"
#include "bufaux.h"
@ -31,6 +31,7 @@ RCSID("$OpenBSD: sftp-server.c,v 1.14 2001/01/21 19:05:56 markus Exp $");
#include "xmalloc.h"
#include "sftp.h"
#include "sftp-common.h"
/* helper */
#define get_int64() buffer_get_int64(&iqueue);
@ -50,22 +51,9 @@ Buffer oqueue;
/* portable attibutes, etc. */
typedef struct Attrib Attrib;
typedef struct Stat Stat;
struct Attrib
{
u_int32_t flags;
u_int64_t size;
u_int32_t uid;
u_int32_t gid;
u_int32_t perm;
u_int32_t atime;
u_int32_t mtime;
};
struct Stat
{
struct Stat {
char *name;
char *long_name;
Attrib attrib;
@ -122,90 +110,6 @@ flags_from_portable(int pflags)
return flags;
}
void
attrib_clear(Attrib *a)
{
a->flags = 0;
a->size = 0;
a->uid = 0;
a->gid = 0;
a->perm = 0;
a->atime = 0;
a->mtime = 0;
}
Attrib *
decode_attrib(Buffer *b)
{
static Attrib a;
attrib_clear(&a);
a.flags = buffer_get_int(b);
if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
a.size = buffer_get_int64(b);
}
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
a.uid = buffer_get_int(b);
a.gid = buffer_get_int(b);
}
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
a.perm = buffer_get_int(b);
}
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
a.atime = buffer_get_int(b);
a.mtime = buffer_get_int(b);
}
/* vendor-specific extensions */
if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) {
char *type, *data;
int i, count;
count = buffer_get_int(b);
for (i = 0; i < count; i++) {
type = buffer_get_string(b, NULL);
data = buffer_get_string(b, NULL);
xfree(type);
xfree(data);
}
}
return &a;
}
void
encode_attrib(Buffer *b, Attrib *a)
{
buffer_put_int(b, a->flags);
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
buffer_put_int64(b, a->size);
}
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
buffer_put_int(b, a->uid);
buffer_put_int(b, a->gid);
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
buffer_put_int(b, a->perm);
}
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
buffer_put_int(b, a->atime);
buffer_put_int(b, a->mtime);
}
}
void
stat_to_attrib(struct stat *st, Attrib *a)
{
attrib_clear(a);
a->flags = 0;
a->flags |= SSH2_FILEXFER_ATTR_SIZE;
a->size = st->st_size;
a->flags |= SSH2_FILEXFER_ATTR_UIDGID;
a->uid = st->st_uid;
a->gid = st->st_gid;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a->perm = st->st_mode;
a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
a->atime = st->st_atime;
a->mtime = st->st_mtime;
}
Attrib *
get_attrib(void)
{

156
sftp.1 Normal file
View File

@ -0,0 +1,156 @@
.\" $OpenBSD: sftp.1,v 1.1 2001/02/04 11:11:54 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd Febuary 4, 2001
.Dt SFTP 1
.Os
.Sh NAME
.Nm sftp
.Nd Secure file tranfer program
.Sh SYNOPSIS
.Nm sftp
.Op Fl v Li | Fl C
.Op Fl o Ar ssh_option
.Op Ar hostname | user@hostname
.Sh DESCRIPTION
.Nm
is an interactive file transfer program, similar to
.Xr ftp 1 ,
which performs all operations over an encrypted
.Xr ssh 1
transport.
It may also use many features of ssh, such as public key authentication and
compression.
.Nm
connects and logs into the specified
.Ar hostname
then enters an interactive command mode.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl C
Enables compression (via ssh's
.Fl C
flag)
.It Fl v
Raise logging level. This option is also passed to ssh.
.It Fl o Ar ssh_option
Specify an option to be directly passed to
.Xr ssh 1 .
.El
.Sh INTERACTIVE COMMANDS
Once in interactive mode
.Nm ,
understands a set of commands similar to those of
.Xr ftp 1 .
Commands are case insensitive.
.Bl -tag -width Ds
.It Ic CD Ar path
Change remote directory to
.Ar path
.It Ic LCD Ar path
Change local directory to
.Ar path
.It Ic CHGRP Ar grp Ar path
Change group of file
.Ar path to
.Ar grp .
.Ar grp
must be numeric.
.It Ic CHMOD Ar mode Ar path
Change permissions of file
.Ar path to
.Ar mode
.It Ic CHOWN Ar own Ar path
Change owner of file
.Ar path to
.Ar own .
.Ar own
must be a numeric UID.
.It Ic HELP
Display help text
.It Ic GET Ar remote-file Op Ar local-file
Retrieve the
.Ar remote-file
and store it on the local machine.
If the local
file name is not specified, it is given the same name it has on the
remote machine.
.It Ic LLS Op Ar ls-options Op Ar path
Display local directory listing of either
.Ar path
or current directory if
.Ar path
was not specified.
.It Ic LMKDIR Ar path
Create local directory specified by
.Ar path
.It Ic LPWD
Print local working directory
.It Ic LS Op Ar path
Display remote directory listing of either
.Ar path
or current directory, is
.Ar path not specified.
.It Ic LUMASK Ar umask
Set local umask to
.Ar umask
.It Ic MKDIR Ar path
Create remote directory specified by
.Ar path
.It Ic PUT local-file Op Ar remote-file
Upload
.Ar local-file
and store it on the remote machine. If the local file name is not specified,
it is given the same name it has on the local machine.
.It Ic PWD
Display remote working directory
.It Ic EXIT
Quit sftp
.It Ic QUIT
Quit sftp
.It Ic RENAME Ar oldpath Ar newpath
Rename remote file from
.Ar oldpath
to
.Ar newpath
.It Ic RMDIR Ar path
Remove remote directory specified by
.Ar path
.It Ic RM Ar path
Delete remote file specified by
.Ar path
.It Ic ! Ar command
Execute
.Ar command
in local shell
.It Ic !
Escape to local shell
.Sh AUTHORS
Damien Miller <djm@mindrot.org>
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-keygen 1 ,
.Xr sshd 8

222
sftp.c Normal file
View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp.c,v 1.1 2001/02/04 11:11:54 djm Exp $");
/* XXX: commandline mode */
/* XXX: copy between two remote hosts (commandline) */
/* XXX: short-form remote directory listings (like 'ls -C') */
#include "buffer.h"
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
#include "sftp-int.h"
void
connect_to_server(char **args, int *in, int *out, pid_t *sshpid)
{
int c_in, c_out;
#ifdef USE_PIPES
int pin[2], pout[2];
if ((pipe(pin) == -1) || (pipe(pout) == -1))
fatal("pipe: %s", strerror(errno));
*in = pin[0];
*out = pout[1];
c_in = pout[0];
c_out = pin[1];
#else /* USE_PIPES */
int inout[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
fatal("socketpair: %s", strerror(errno));
*in = *out = inout[0];
c_in = c_out = inout[1];
#endif /* USE_PIPES */
if ((*sshpid = fork()) == -1)
fatal("fork: %s", strerror(errno));
else if (*sshpid == 0) {
if ((dup2(c_in, STDIN_FILENO) == -1) ||
(dup2(c_out, STDOUT_FILENO) == -1)) {
fprintf(stderr, "dup2: %s\n", strerror(errno));
exit(1);
}
close(*in);
close(*out);
close(c_in);
close(c_out);
execv(_PATH_SSH_PROGRAM, args);
fprintf(stderr, "exec: %s", strerror(errno));
exit(1);
}
close(c_in);
close(c_out);
}
char **
make_ssh_args(char *add_arg)
{
static char **args = NULL;
static int nargs = 0;
char debug_buf[4096];
int i;
/* Init args array */
if (args == NULL) {
nargs = 4;
i = 0;
args = xmalloc(sizeof(*args) * nargs);
args[i++] = "ssh";
args[i++] = "-oProtocol=2";
args[i++] = "-s";
args[i++] = NULL;
}
/* If asked to add args, then do so and return */
if (add_arg) {
i = nargs++ - 1;
args = xrealloc(args, sizeof(*args) * nargs);
args[i++] = add_arg;
args[i++] = NULL;
return(NULL);
}
/* Otherwise finish up and return the arg array */
make_ssh_args("sftp");
/* XXX: overflow - doesn't grow debug_buf */
debug_buf[0] = '\0';
for(i = 0; args[i]; i++) {
if (i)
strlcat(debug_buf, " ", sizeof(debug_buf));
strlcat(debug_buf, args[i], sizeof(debug_buf));
}
debug("SSH args \"%s\"", debug_buf);
return(args);
}
void
usage(void)
{
fprintf(stderr, "usage: sftp [-vC] [-osshopt=value] [user@]host\n");
exit(1);
}
int
main(int argc, char **argv)
{
int in, out, i, debug_level, compress_flag;
pid_t sshpid;
char *cp;
LogLevel ll;
debug_level = compress_flag = 0;
for(i = 1; i < argc && argv[i][0] == '-'; i++) {
if (!strcmp(argv[i], "-v"))
debug_level = MIN(3, debug_level + 1);
else if (!strcmp(argv[i], "-C"))
compress_flag = 1;
else if (!strncmp(argv[i], "-o", 2)) {
make_ssh_args(argv[i]);
} else {
fprintf(stderr, "Unknown option \"%s\"\n", argv[i]);
usage();
}
}
if (i == argc || argc > (i + 1))
usage();
if ((cp = strchr(argv[i], '@')) == NULL)
cp = argv[i];
else {
*cp = '\0';
if (!argv[i][0]) {
fprintf(stderr, "Missing username\n");
usage();
}
make_ssh_args("-l");
make_ssh_args(argv[i]);
cp++;
}
if (!*cp) {
fprintf(stderr, "Missing hostname\n");
usage();
}
/* Set up logging and debug '-d' arguments to ssh */
ll = SYSLOG_LEVEL_INFO;
switch (debug_level) {
case 1:
ll = SYSLOG_LEVEL_DEBUG1;
make_ssh_args("-v");
break;
case 2:
ll = SYSLOG_LEVEL_DEBUG2;
make_ssh_args("-v");
make_ssh_args("-v");
break;
case 3:
ll = SYSLOG_LEVEL_DEBUG3;
make_ssh_args("-v");
make_ssh_args("-v");
make_ssh_args("-v");
break;
}
if (compress_flag)
make_ssh_args("-C");
log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
make_ssh_args(cp);
fprintf(stderr, "Connecting to %s...\n", cp);
connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid);
do_init(in, out);
interactive_loop(in, out);
close(in);
close(out);
if (kill(sshpid, SIGHUP) == -1)
fatal("Couldn't terminate ssh process: %s", strerror(errno));
/* XXX: wait? */
exit(0);
}

12
ssh.1
View File

@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.80 2001/01/29 12:36:10 djm Exp $
.\" $OpenBSD: ssh.1,v 1.83 2001/02/04 11:11:55 djm Exp $
.Dd September 25, 1999
.Dt SSH 1
.Os
@ -753,8 +753,8 @@ Specifies a file to use instead of
.It Cm HostKeyAlias
Specifies an alias that should be used instead of the
real host name when looking up or saving the host key
the kown_hosts files.
This option is useful for tunneling ssh connection
in the known_hosts files.
This option is useful for tunneling ssh connections
or if you have multiple servers running on a single host.
.It Cm HostName
Specifies the real host name to log into.
@ -914,8 +914,9 @@ RSA authentication will only be
attempted if the identity file exists, or an authentication agent is
running.
Note that this option applies to protocol version 1 only.
.It Cm SkeyAuthentication
Specifies whether to use
.It Cm ChallengeResponseAuthentication
Specifies whether to use challenge response authentication.
Currently there is only support for
.Xr skey 1
authentication.
The argument to this keyword must be
@ -1270,6 +1271,7 @@ protocol versions 1.5 and 2.0.
.Xr rlogin 1 ,
.Xr rsh 1 ,
.Xr scp 1 ,
.Xr sftp 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,

View File

@ -1,8 +1,8 @@
# $OpenBSD: ssh_config,v 1.7 2001/01/29 01:58:18 niklas Exp $
# $OpenBSD: ssh_config,v 1.8 2001/02/02 12:57:51 deraadt Exp $
# This is ssh client systemwide configuration file. This file provides
# defaults for users, and the values can be changed in per-user configuration
# files or on the command line.
# This is ssh client systemwide configuration file. See ssh(1) for more
# information. This file provides defaults for users, and the values can
# be changed in per-user configuration files or on the command line.
# Configuration data is parsed as follows:
# 1. command line options

View File

@ -13,7 +13,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sshconnect1.c,v 1.21 2001/01/29 19:47:31 markus Exp $");
RCSID("$OpenBSD: sshconnect1.c,v 1.22 2001/02/03 10:08:37 markus Exp $");
#include <openssl/bn.h>
#include <openssl/evp.h>
@ -399,11 +399,11 @@ try_kerberos_authentication()
if (stat(tkt_string(), &st) < 0)
return 0;
strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
strncpy(inst, (char *) krb_get_phost(get_canonical_hostname(1)), INST_SZ);
realm = (char *) krb_realmofhost(get_canonical_hostname());
realm = (char *) krb_realmofhost(get_canonical_hostname(1));
if (!realm) {
debug("Kerberos V4: no realm for %s", get_canonical_hostname());
debug("Kerberos V4: no realm for %s", get_canonical_hostname(1));
return 0;
}
/* This can really be anything. */

24
sshd.8
View File

@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd.8,v 1.86 2001/01/28 20:43:25 stevesk Exp $
.\" $OpenBSD: sshd.8,v 1.90 2001/02/04 11:11:55 djm Exp $
.Dd September 25, 1999
.Dt SSHD 8
.Os
@ -593,6 +593,14 @@ The default is
.It Cm RandomSeed
Obsolete.
Random number generation uses other techniques.
.It Cm ReverseMappingCheck
Specifies whether
.Nm
should try to verify the remote host name and check that
the resolved host name for the remote IP address maps back to the
very same IP address.
The default is
.Dq no .
.It Cm RhostsAuthentication
Specifies whether authentication using rhosts or /etc/hosts.equiv
files is sufficient.
@ -616,15 +624,15 @@ Note that this option applies to protocol version 1 only.
.It Cm ServerKeyBits
Defines the number of bits in the server key.
The minimum value is 512, and the default is 768.
.It Cm SkeyAuthentication
.It Cm ChallengeResponseAuthentication
Specifies whether
.Xr skey 1
challenge reponse
authentication is allowed.
Currently there is only support for
.Xr skey 1
authentication.
The default is
.Dq yes .
Note that s/key authentication is enabled only if
.Cm PasswordAuthentication
is allowed, too.
.It Cm StrictModes
Specifies whether
.Nm
@ -797,6 +805,9 @@ authentication.
The command supplied by the user (if any) is ignored.
The command is run on a pty if the connection requests a pty;
otherwise it is run without a tty.
Note that if you want a 8-bit clean channel,
you must not request a pty or should specify
.Cm no-pty .
A quote may be included in the command by quoting it with a backslash.
This option might be useful
to restrict certain RSA keys to perform just a specific operation.
@ -1076,6 +1087,7 @@ Markus Friedl contributed the support for SSH
protocol versions 1.5 and 2.0.
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,
.Xr sftp-server 8 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,

View File

@ -1,6 +1,7 @@
# $OpenBSD: sshd_config,v 1.27 2001/01/29 01:58:19 niklas Exp $
# $OpenBSD: sshd_config,v 1.30 2001/02/03 10:19:51 markus Exp $
# This is ssh server systemwide configuration file.
# This is the sshd server system-wide configuration file. See sshd(8)
# for more information.
Port 22
#Protocol 2,1
@ -39,9 +40,9 @@ RSAAuthentication yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes
PermitEmptyPasswords no
# Uncomment to disable s/key passwords
#SkeyAuthentication no
#KbdInteractiveAuthentication yes
#ChallengeResposeAuthentication no
# To change Kerberos options
#KerberosAuthentication no
@ -59,3 +60,4 @@ PermitEmptyPasswords no
#Subsystem sftp /usr/libexec/sftp-server
#MaxStartups 10:30:60
#Banner /etc/issue.net
#ReverseMappingCheck yes