aboutsummaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2001-05-13 00:03:40 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2001-05-13 00:03:40 +0000
commit980ef5a6173d1608d3580c1954785f0d62f0b2cd (patch)
treeed47d23e3f734a59de25b63ca998a89ec4fa1324 /crypto
parent087928ac375333310734d209fd35a3ec9cdeb583 (diff)
downloadsrc-980ef5a6173d1608d3580c1954785f0d62f0b2cd.tar.gz
src-980ef5a6173d1608d3580c1954785f0d62f0b2cd.zip
This commit was manufactured by cvs2svn to create branch 'RELENG_4'.
Notes
Notes: svn path=/stable/4/; revision=76528
Diffstat (limited to 'crypto')
-rw-r--r--crypto/openssh/atomicio.h31
-rw-r--r--crypto/openssh/auth-chall.c105
-rw-r--r--crypto/openssh/auth2-chall.c112
-rw-r--r--crypto/openssh/canohost.h38
-rw-r--r--crypto/openssh/clientloop.h39
-rw-r--r--crypto/openssh/groupaccess.c78
-rw-r--r--crypto/openssh/groupaccess.h49
-rw-r--r--crypto/openssh/kexdh.c304
-rw-r--r--crypto/openssh/kexgex.c408
-rw-r--r--crypto/openssh/log.h75
-rw-r--r--crypto/openssh/mac.c114
-rw-r--r--crypto/openssh/mac.h28
-rw-r--r--crypto/openssh/misc.c130
-rw-r--r--crypto/openssh/misc.h30
-rw-r--r--crypto/openssh/pathnames.h112
-rw-r--r--crypto/openssh/radix.h28
-rw-r--r--crypto/openssh/readpass.h20
-rw-r--r--crypto/openssh/scp-common.c98
-rw-r--r--crypto/openssh/scp-common.h64
-rw-r--r--crypto/openssh/serverloop.h22
-rw-r--r--crypto/openssh/sftp-client.c930
-rw-r--r--crypto/openssh/sftp-client.h107
-rw-r--r--crypto/openssh/sftp-common.c146
-rw-r--r--crypto/openssh/sftp-common.h55
-rw-r--r--crypto/openssh/sftp-glob.c146
-rw-r--r--crypto/openssh/sftp-glob.h32
-rw-r--r--crypto/openssh/sftp-int.c917
-rw-r--r--crypto/openssh/sftp-int.h27
-rw-r--r--crypto/openssh/sftp.1222
-rw-r--r--crypto/openssh/sftp.c271
-rw-r--r--crypto/openssh/sftp.h91
-rw-r--r--crypto/openssh/ssh-dss.c217
-rw-r--r--crypto/openssh/ssh-dss.h41
-rw-r--r--crypto/openssh/ssh-keyscan.1104
-rw-r--r--crypto/openssh/ssh-keyscan.c625
-rw-r--r--crypto/openssh/ssh-rsa.c174
-rw-r--r--crypto/openssh/ssh-rsa.h41
-rw-r--r--crypto/openssh/ssh1.h86
-rw-r--r--crypto/openssh/sshlogin.h40
-rw-r--r--crypto/openssh/sshpty.c298
-rw-r--r--crypto/openssh/sshpty.h47
-rw-r--r--crypto/openssh/sshtty.c96
-rw-r--r--crypto/openssh/sshtty.h65
-rw-r--r--crypto/openssh/tildexpand.h19
-rw-r--r--crypto/openssh/version.c59
45 files changed, 6741 insertions, 0 deletions
diff --git a/crypto/openssh/atomicio.h b/crypto/openssh/atomicio.h
new file mode 100644
index 000000000000..d878687d63d0
--- /dev/null
+++ b/crypto/openssh/atomicio.h
@@ -0,0 +1,31 @@
+/* $OpenBSD: atomicio.h,v 1.3 2001/03/02 18:54:30 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
+ * 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.
+ */
+
+/*
+ * Ensure all of data on socket comes through. f==read || f==write
+ */
+ssize_t atomicio(ssize_t (*f)(), int fd, void *s, size_t n);
diff --git a/crypto/openssh/auth-chall.c b/crypto/openssh/auth-chall.c
new file mode 100644
index 000000000000..a87799b9dccb
--- /dev/null
+++ b/crypto/openssh/auth-chall.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2001 Markus Friedl. 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: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
+RCSID("$FreeBSD$");
+
+#include "auth.h"
+#include "log.h"
+
+#ifdef BSD_AUTH
+char *
+get_challenge(Authctxt *authctxt, char *devs)
+{
+ char *challenge;
+
+ if (authctxt->as != NULL) {
+ debug2("try reuse session");
+ challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
+ if (challenge != NULL) {
+ debug2("reuse bsd auth session");
+ return challenge;
+ }
+ auth_close(authctxt->as);
+ authctxt->as = NULL;
+ }
+ debug2("new bsd auth session");
+ if (devs == NULL || strlen(devs) == 0)
+ devs = authctxt->style;
+ debug3("bsd auth: devs %s", devs ? devs : "<default>");
+ authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh",
+ &challenge);
+ if (authctxt->as == NULL)
+ return NULL;
+ debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY");
+ return challenge;
+}
+int
+verify_response(Authctxt *authctxt, char *response)
+{
+ int authok;
+
+ if (authctxt->as == 0)
+ error("verify_response: no bsd auth session");
+ authok = auth_userresponse(authctxt->as, response, 0);
+ authctxt->as = NULL;
+ debug("verify_response: <%s> = <%d>", response, authok);
+ return authok != 0;
+}
+#else
+#ifdef SKEY
+#include <opie.h>
+
+char *
+get_challenge(Authctxt *authctxt, char *devs)
+{
+ static char challenge[1024];
+ struct opie opie;
+ if (opiechallenge(&opie, authctxt->user, challenge) == -1)
+ return NULL;
+ strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
+ return challenge;
+}
+int
+verify_response(Authctxt *authctxt, char *response)
+{
+ return (authctxt->valid &&
+ opie_haskey(authctxt->pw->pw_name) == 0 &&
+ opie_passverify(authctxt->pw->pw_name, response) != -1);
+}
+#else
+/* not available */
+char *
+get_challenge(Authctxt *authctxt, char *devs)
+{
+ return NULL;
+}
+int
+verify_response(Authctxt *authctxt, char *response)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/crypto/openssh/auth2-chall.c b/crypto/openssh/auth2-chall.c
new file mode 100644
index 000000000000..5af60e42fa0f
--- /dev/null
+++ b/crypto/openssh/auth2-chall.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2001 Markus Friedl. 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: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $");
+
+#include "ssh2.h"
+#include "auth.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "dispatch.h"
+#include "log.h"
+
+void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo);
+void input_userauth_info_response(int type, int plen, void *ctxt);
+
+/*
+ * try challenge-reponse, return -1 (= postponed) if we have to
+ * wait for the response.
+ */
+int
+auth2_challenge(Authctxt *authctxt, char *devs)
+{
+ char *challenge;
+
+ if (!authctxt->valid || authctxt->user == NULL)
+ return 0;
+ if ((challenge = get_challenge(authctxt, devs)) == NULL)
+ return 0;
+ send_userauth_into_request(authctxt, challenge, 0);
+ dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
+ &input_userauth_info_response);
+ authctxt->postponed = 1;
+ return 0;
+}
+
+void
+send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo)
+{
+ int nprompts = 1;
+
+ packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
+ /* name, instruction and language are unused */
+ packet_put_cstring("");
+ packet_put_cstring("");
+ packet_put_cstring("");
+ packet_put_int(nprompts);
+ packet_put_cstring(challenge);
+ packet_put_char(echo);
+ packet_send();
+ packet_write_wait();
+}
+
+void
+input_userauth_info_response(int type, int plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ int authenticated = 0;
+ u_int nresp, rlen;
+ char *response, *method = "challenge-reponse";
+
+ if (authctxt == NULL)
+ fatal("input_userauth_info_response: no authctxt");
+
+ authctxt->postponed = 0; /* reset */
+ nresp = packet_get_int();
+ if (nresp == 1) {
+ response = packet_get_string(&rlen);
+ packet_done();
+ if (strlen(response) == 0) {
+ /*
+ * if we received an empty response, resend challenge
+ * with echo enabled
+ */
+ char *challenge = get_challenge(authctxt, NULL);
+ if (challenge != NULL) {
+ send_userauth_into_request(authctxt,
+ challenge, 1);
+ authctxt->postponed = 1;
+ }
+ } else if (authctxt->valid) {
+ authenticated = verify_response(authctxt, response);
+ memset(response, 'r', rlen);
+ }
+ xfree(response);
+ }
+ /* unregister callback */
+ if (!authctxt->postponed)
+ dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+
+ userauth_finish(authctxt, authenticated, method);
+}
diff --git a/crypto/openssh/canohost.h b/crypto/openssh/canohost.h
new file mode 100644
index 000000000000..36fb345a1223
--- /dev/null
+++ b/crypto/openssh/canohost.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: canohost.h,v 1.6 2001/04/12 19:15:24 markus Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * 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(int reverse_mapping_check);
+
+/*
+ * Returns the IP-address of the remote host as a string. The returned
+ * string is cached and must not be freed.
+ */
+const char *get_remote_ipaddr(void);
+
+const char *get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check);
+
+/* Returns the ipaddr/port number of the peer of the socket. */
+char * get_peer_ipaddr(int socket);
+int get_peer_port(int sock);
+char * get_local_ipaddr(int socket);
+char * get_local_name(int socket);
+
+/* Returns the port number of the remote/local host. */
+int get_remote_port(void);
+int get_local_port(void);
diff --git a/crypto/openssh/clientloop.h b/crypto/openssh/clientloop.h
new file mode 100644
index 000000000000..ee40d87ea908
--- /dev/null
+++ b/crypto/openssh/clientloop.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: clientloop.h,v 1.4 2001/02/06 22:43:02 markus Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2001 Markus Friedl. 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 main loop for the interactive session. */
+int client_loop(int have_pty, int escape_char, int id);
diff --git a/crypto/openssh/groupaccess.c b/crypto/openssh/groupaccess.c
new file mode 100644
index 000000000000..ac9e00acaf2d
--- /dev/null
+++ b/crypto/openssh/groupaccess.c
@@ -0,0 +1,78 @@
+/* $OpenBSD: groupaccess.c,v 1.3 2001/01/29 01:58:15 niklas Exp $ */
+
+/*
+ * Copyright (c) 2001 Kevin Steves. 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"
+
+#include "groupaccess.h"
+#include "xmalloc.h"
+#include "match.h"
+#include "log.h"
+
+static int ngroups;
+static char *groups_byname[NGROUPS_MAX + 1]; /* +1 for base/primary group */
+
+int
+ga_init(const char *user, gid_t base)
+{
+ gid_t groups_bygid[NGROUPS_MAX + 1];
+ int i, j;
+ struct group *gr;
+
+ if (ngroups > 0)
+ ga_free();
+
+ ngroups = sizeof(groups_bygid) / sizeof(gid_t);
+ if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
+ log("getgrouplist: groups list too small");
+ for (i = 0, j = 0; i < ngroups; i++)
+ if ((gr = getgrgid(groups_bygid[i])) != NULL)
+ groups_byname[j++] = xstrdup(gr->gr_name);
+ return (ngroups = j);
+}
+
+int
+ga_match(char * const *groups, int n)
+{
+ int i, j;
+
+ for (i = 0; i < ngroups; i++)
+ for (j = 0; j < n; j++)
+ if (match_pattern(groups_byname[i], groups[j]))
+ return 1;
+ return 0;
+}
+
+void
+ga_free(void)
+{
+ int i;
+
+ if (ngroups > 0) {
+ for (i = 0; i < ngroups; i++)
+ xfree(groups_byname[i]);
+ ngroups = 0;
+ }
+}
diff --git a/crypto/openssh/groupaccess.h b/crypto/openssh/groupaccess.h
new file mode 100644
index 000000000000..b4e5e42fc634
--- /dev/null
+++ b/crypto/openssh/groupaccess.h
@@ -0,0 +1,49 @@
+/* $OpenBSD: groupaccess.h,v 1.2 2001/01/29 01:58:15 niklas Exp $ */
+
+/*
+ * Copyright (c) 2001 Kevin Steves. 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.
+ */
+
+#ifndef GROUPACCESS_H
+#define GROUPACCESS_H
+
+#include <grp.h>
+
+/*
+ * Initialize group access list for user with primary (base) and
+ * supplementary groups. Return the number of groups in the list.
+ */
+int ga_init(const char *user, gid_t base);
+
+/*
+ * Return 1 if one of user's groups is contained in groups.
+ * Return 0 otherwise. Use match_pattern() for string comparison.
+ */
+int ga_match(char * const *groups, int ngroups);
+
+/*
+ * Free memory allocated for group access list.
+ */
+void ga_free(void);
+
+#endif
diff --git a/crypto/openssh/kexdh.c b/crypto/openssh/kexdh.c
new file mode 100644
index 000000000000..7b6a22040a3e
--- /dev/null
+++ b/crypto/openssh/kexdh.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2001 Markus Friedl. 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: kexdh.c,v 1.3 2001/04/04 09:48:34 markus Exp $");
+
+#include <openssl/crypto.h>
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+
+u_char *
+kex_dh_hash(
+ char *client_version_string,
+ char *server_version_string,
+ char *ckexinit, int ckexinitlen,
+ char *skexinit, int skexinitlen,
+ char *serverhostkeyblob, int sbloblen,
+ BIGNUM *client_dh_pub,
+ BIGNUM *server_dh_pub,
+ BIGNUM *shared_secret)
+{
+ Buffer b;
+ static u_char digest[EVP_MAX_MD_SIZE];
+ EVP_MD *evp_md = EVP_sha1();
+ EVP_MD_CTX md;
+
+ buffer_init(&b);
+ buffer_put_string(&b, client_version_string, strlen(client_version_string));
+ buffer_put_string(&b, server_version_string, strlen(server_version_string));
+
+ /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+ buffer_put_int(&b, ckexinitlen+1);
+ buffer_put_char(&b, SSH2_MSG_KEXINIT);
+ buffer_append(&b, ckexinit, ckexinitlen);
+ buffer_put_int(&b, skexinitlen+1);
+ buffer_put_char(&b, SSH2_MSG_KEXINIT);
+ buffer_append(&b, skexinit, skexinitlen);
+
+ buffer_put_string(&b, serverhostkeyblob, sbloblen);
+ buffer_put_bignum2(&b, client_dh_pub);
+ buffer_put_bignum2(&b, server_dh_pub);
+ buffer_put_bignum2(&b, shared_secret);
+
+#ifdef DEBUG_KEX
+ buffer_dump(&b);
+#endif
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+ EVP_DigestFinal(&md, digest, NULL);
+
+ buffer_free(&b);
+
+#ifdef DEBUG_KEX
+ dump_digest("hash", digest, evp_md->md_size);
+#endif
+ return digest;
+}
+
+/* client */
+
+void
+kexdh_client(Kex *kex)
+{
+ BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+ DH *dh;
+ Key *server_host_key;
+ char *server_host_key_blob = NULL, *signature = NULL;
+ u_char *kbuf, *hash;
+ u_int klen, kout, slen, sbloblen;
+ int dlen, plen;
+
+ /* generate and send 'e', client DH public key */
+ dh = dh_new_group1();
+ dh_gen_key(dh, kex->we_need * 8);
+ packet_start(SSH2_MSG_KEXDH_INIT);
+ packet_put_bignum2(dh->pub_key);
+ packet_send();
+
+ debug("sending SSH2_MSG_KEXDH_INIT");
+#ifdef DEBUG_KEXDH
+ DHparams_print_fp(stderr, dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, dh->pub_key);
+ fprintf(stderr, "\n");
+#endif
+
+ debug("expecting SSH2_MSG_KEXDH_REPLY");
+ packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
+
+ /* key, cert */
+ server_host_key_blob = packet_get_string(&sbloblen);
+ server_host_key = key_from_blob(server_host_key_blob, sbloblen);
+ if (server_host_key == NULL)
+ fatal("cannot decode server_host_key_blob");
+
+ if (kex->check_host_key == NULL)
+ fatal("cannot check server_host_key");
+ kex->check_host_key(server_host_key);
+
+ /* DH paramter f, server public DH key */
+ dh_server_pub = BN_new();
+ if (dh_server_pub == NULL)
+ fatal("dh_server_pub == NULL");
+ packet_get_bignum2(dh_server_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "dh_server_pub= ");
+ BN_print_fp(stderr, dh_server_pub);
+ fprintf(stderr, "\n");
+ debug("bits %d", BN_num_bits(dh_server_pub));
+#endif
+
+ /* signed H */
+ signature = packet_get_string(&slen);
+ packet_done();
+
+ if (!dh_pub_is_valid(dh, dh_server_pub))
+ packet_disconnect("bad server public DH value");
+
+ klen = DH_size(dh);
+ kbuf = xmalloc(klen);
+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
+#ifdef DEBUG_KEXDH
+ dump_digest("shared secret", kbuf, kout);
+#endif
+ shared_secret = BN_new();
+ BN_bin2bn(kbuf, kout, shared_secret);
+ memset(kbuf, 0, klen);
+ xfree(kbuf);
+
+ /* calc and verify H */
+ hash = kex_dh_hash(
+ kex->client_version_string,
+ kex->server_version_string,
+ buffer_ptr(&kex->my), buffer_len(&kex->my),
+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+ server_host_key_blob, sbloblen,
+ dh->pub_key,
+ dh_server_pub,
+ shared_secret
+ );
+ xfree(server_host_key_blob);
+ BN_free(dh_server_pub);
+ DH_free(dh);
+
+ if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
+ fatal("key_verify failed for server_host_key");
+ key_free(server_host_key);
+ xfree(signature);
+
+ /* save session id */
+ if (kex->session_id == NULL) {
+ kex->session_id_len = 20;
+ kex->session_id = xmalloc(kex->session_id_len);
+ memcpy(kex->session_id, hash, kex->session_id_len);
+ }
+
+ kex_derive_keys(kex, hash, shared_secret);
+ BN_clear_free(shared_secret);
+ kex_finish(kex);
+}
+
+/* server */
+
+void
+kexdh_server(Kex *kex)
+{
+ BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+ DH *dh;
+ Key *server_host_key;
+ u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+ u_int sbloblen, klen, kout;
+ int dlen, slen, plen;
+
+ /* generate server DH public key */
+ dh = dh_new_group1();
+ dh_gen_key(dh, kex->we_need * 8);
+
+ debug("expecting SSH2_MSG_KEXDH_INIT");
+ packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT);
+
+ if (kex->load_host_key == NULL)
+ fatal("Cannot load hostkey");
+ server_host_key = kex->load_host_key(kex->hostkey_type);
+ if (server_host_key == NULL)
+ fatal("Unsupported hostkey type %d", kex->hostkey_type);
+
+ /* key, cert */
+ dh_client_pub = BN_new();
+ if (dh_client_pub == NULL)
+ fatal("dh_client_pub == NULL");
+ packet_get_bignum2(dh_client_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "dh_client_pub= ");
+ BN_print_fp(stderr, dh_client_pub);
+ fprintf(stderr, "\n");
+ debug("bits %d", BN_num_bits(dh_client_pub));
+#endif
+
+#ifdef DEBUG_KEXDH
+ DHparams_print_fp(stderr, dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, dh->pub_key);
+ fprintf(stderr, "\n");
+#endif
+ if (!dh_pub_is_valid(dh, dh_client_pub))
+ packet_disconnect("bad client public DH value");
+
+ klen = DH_size(dh);
+ kbuf = xmalloc(klen);
+ kout = DH_compute_key(kbuf, dh_client_pub, dh);
+#ifdef DEBUG_KEXDH
+ dump_digest("shared secret", kbuf, kout);
+#endif
+ shared_secret = BN_new();
+ BN_bin2bn(kbuf, kout, shared_secret);
+ memset(kbuf, 0, klen);
+ xfree(kbuf);
+
+ key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
+
+ /* calc H */
+ hash = kex_dh_hash(
+ kex->client_version_string,
+ kex->server_version_string,
+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+ buffer_ptr(&kex->my), buffer_len(&kex->my),
+ (char *)server_host_key_blob, sbloblen,
+ dh_client_pub,
+ dh->pub_key,
+ shared_secret
+ );
+ BN_free(dh_client_pub);
+
+ /* save session id := H */
+ /* XXX hashlen depends on KEX */
+ if (kex->session_id == NULL) {
+ kex->session_id_len = 20;
+ kex->session_id = xmalloc(kex->session_id_len);
+ memcpy(kex->session_id, hash, kex->session_id_len);
+ }
+
+ /* sign H */
+ /* XXX hashlen depends on KEX */
+ key_sign(server_host_key, &signature, &slen, hash, 20);
+
+ /* destroy_sensitive_data(); */
+
+ /* send server hostkey, DH pubkey 'f' and singed H */
+ packet_start(SSH2_MSG_KEXDH_REPLY);
+ packet_put_string((char *)server_host_key_blob, sbloblen);
+ packet_put_bignum2(dh->pub_key); /* f */
+ packet_put_string((char *)signature, slen);
+ packet_send();
+
+ xfree(signature);
+ xfree(server_host_key_blob);
+ /* have keys, free DH */
+ DH_free(dh);
+
+ kex_derive_keys(kex, hash, shared_secret);
+ BN_clear_free(shared_secret);
+ kex_finish(kex);
+}
+
+void
+kexdh(Kex *kex)
+{
+ if (kex->server)
+ kexdh_server(kex);
+ else
+ kexdh_client(kex);
+}
diff --git a/crypto/openssh/kexgex.c b/crypto/openssh/kexgex.c
new file mode 100644
index 000000000000..44f2f5c950de
--- /dev/null
+++ b/crypto/openssh/kexgex.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2000 Niels Provos. All rights reserved.
+ * Copyright (c) 2001 Markus Friedl. 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: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $");
+
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#include "compat.h"
+
+u_char *
+kexgex_hash(
+ char *client_version_string,
+ char *server_version_string,
+ char *ckexinit, int ckexinitlen,
+ char *skexinit, int skexinitlen,
+ char *serverhostkeyblob, int sbloblen,
+ int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
+ BIGNUM *client_dh_pub,
+ BIGNUM *server_dh_pub,
+ BIGNUM *shared_secret)
+{
+ Buffer b;
+ static u_char digest[EVP_MAX_MD_SIZE];
+ EVP_MD *evp_md = EVP_sha1();
+ EVP_MD_CTX md;
+
+ buffer_init(&b);
+ buffer_put_string(&b, client_version_string, strlen(client_version_string));
+ buffer_put_string(&b, server_version_string, strlen(server_version_string));
+
+ /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+ buffer_put_int(&b, ckexinitlen+1);
+ buffer_put_char(&b, SSH2_MSG_KEXINIT);
+ buffer_append(&b, ckexinit, ckexinitlen);
+ buffer_put_int(&b, skexinitlen+1);
+ buffer_put_char(&b, SSH2_MSG_KEXINIT);
+ buffer_append(&b, skexinit, skexinitlen);
+
+ buffer_put_string(&b, serverhostkeyblob, sbloblen);
+ if (min == -1 || max == -1)
+ buffer_put_int(&b, wantbits);
+ else {
+ buffer_put_int(&b, min);
+ buffer_put_int(&b, wantbits);
+ buffer_put_int(&b, max);
+ }
+ buffer_put_bignum2(&b, prime);
+ buffer_put_bignum2(&b, gen);
+ buffer_put_bignum2(&b, client_dh_pub);
+ buffer_put_bignum2(&b, server_dh_pub);
+ buffer_put_bignum2(&b, shared_secret);
+
+#ifdef DEBUG_KEXDH
+ buffer_dump(&b);
+#endif
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+ EVP_DigestFinal(&md, digest, NULL);
+
+ buffer_free(&b);
+
+#ifdef DEBUG_KEXDH
+ dump_digest("hash", digest, evp_md->md_size);
+#endif
+ return digest;
+}
+
+/* client */
+
+void
+kexgex_client(Kex *kex)
+{
+ BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+ BIGNUM *p = NULL, *g = NULL;
+ Key *server_host_key;
+ u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+ u_int klen, kout, slen, sbloblen;
+ int dlen, plen, min, max, nbits;
+ DH *dh;
+
+ nbits = dh_estimate(kex->we_need * 8);
+
+ if (datafellows & SSH_OLD_DHGEX) {
+ debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
+
+ /* Old GEX request */
+ packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
+ packet_put_int(nbits);
+ min = DH_GRP_MIN;
+ max = DH_GRP_MAX;
+ } else {
+ debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
+
+ /* New GEX request */
+ min = DH_GRP_MIN;
+ max = DH_GRP_MAX;
+ packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
+ packet_put_int(min);
+ packet_put_int(nbits);
+ packet_put_int(max);
+ }
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
+ min, nbits, max);
+#endif
+ packet_send();
+
+ debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
+ packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
+
+ if ((p = BN_new()) == NULL)
+ fatal("BN_new");
+ packet_get_bignum2(p, &dlen);
+ if ((g = BN_new()) == NULL)
+ fatal("BN_new");
+ packet_get_bignum2(g, &dlen);
+ packet_done();
+
+ if (BN_num_bits(p) < min || BN_num_bits(p) > max)
+ fatal("DH_GEX group out of range: %d !< %d !< %d",
+ min, BN_num_bits(p), max);
+
+ dh = dh_new_group(g, p);
+ dh_gen_key(dh, kex->we_need * 8);
+
+#ifdef DEBUG_KEXDH
+ DHparams_print_fp(stderr, dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, dh->pub_key);
+ fprintf(stderr, "\n");
+#endif
+
+ debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
+ /* generate and send 'e', client DH public key */
+ packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
+ packet_put_bignum2(dh->pub_key);
+ packet_send();
+
+ debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
+ packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
+
+ /* key, cert */
+ server_host_key_blob = packet_get_string(&sbloblen);
+ server_host_key = key_from_blob(server_host_key_blob, sbloblen);
+ if (server_host_key == NULL)
+ fatal("cannot decode server_host_key_blob");
+
+ if (kex->check_host_key == NULL)
+ fatal("cannot check server_host_key");
+ kex->check_host_key(server_host_key);
+
+ /* DH paramter f, server public DH key */
+ dh_server_pub = BN_new();
+ if (dh_server_pub == NULL)
+ fatal("dh_server_pub == NULL");
+ packet_get_bignum2(dh_server_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "dh_server_pub= ");
+ BN_print_fp(stderr, dh_server_pub);
+ fprintf(stderr, "\n");
+ debug("bits %d", BN_num_bits(dh_server_pub));
+#endif
+
+ /* signed H */
+ signature = packet_get_string(&slen);
+ packet_done();
+
+ if (!dh_pub_is_valid(dh, dh_server_pub))
+ packet_disconnect("bad server public DH value");
+
+ klen = DH_size(dh);
+ kbuf = xmalloc(klen);
+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
+#ifdef DEBUG_KEXDH
+ dump_digest("shared secret", kbuf, kout);
+#endif
+ shared_secret = BN_new();
+ BN_bin2bn(kbuf, kout, shared_secret);
+ memset(kbuf, 0, klen);
+ xfree(kbuf);
+
+ if (datafellows & SSH_OLD_DHGEX)
+ min = max = -1;
+
+ /* calc and verify H */
+ hash = kexgex_hash(
+ kex->client_version_string,
+ kex->server_version_string,
+ buffer_ptr(&kex->my), buffer_len(&kex->my),
+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+ server_host_key_blob, sbloblen,
+ min, nbits, max,
+ dh->p, dh->g,
+ dh->pub_key,
+ dh_server_pub,
+ shared_secret
+ );
+ /* have keys, free DH */
+ DH_free(dh);
+ xfree(server_host_key_blob);
+ BN_free(dh_server_pub);
+
+ if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
+ fatal("key_verify failed for server_host_key");
+ key_free(server_host_key);
+ xfree(signature);
+
+ /* save session id */
+ if (kex->session_id == NULL) {
+ kex->session_id_len = 20;
+ kex->session_id = xmalloc(kex->session_id_len);
+ memcpy(kex->session_id, hash, kex->session_id_len);
+ }
+ kex_derive_keys(kex, hash, shared_secret);
+ BN_clear_free(shared_secret);
+
+ kex_finish(kex);
+}
+
+/* server */
+
+void
+kexgex_server(Kex *kex)
+{
+ BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+ Key *server_host_key;
+ DH *dh = dh;
+ u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+ u_int sbloblen, klen, kout;
+ int min = -1, max = -1, nbits = -1, type, plen, dlen, slen;
+
+ if (kex->load_host_key == NULL)
+ fatal("Cannot load hostkey");
+ server_host_key = kex->load_host_key(kex->hostkey_type);
+ if (server_host_key == NULL)
+ fatal("Unsupported hostkey type %d", kex->hostkey_type);
+
+ type = packet_read(&plen);
+ switch(type){
+ case SSH2_MSG_KEX_DH_GEX_REQUEST:
+ debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
+ min = packet_get_int();
+ nbits = packet_get_int();
+ max = packet_get_int();
+ min = MAX(DH_GRP_MIN, min);
+ max = MIN(DH_GRP_MAX, max);
+ break;
+ case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
+ debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
+ nbits = packet_get_int();
+ min = DH_GRP_MIN;
+ max = DH_GRP_MAX;
+ /* unused for old GEX */
+ break;
+ default:
+ fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
+ }
+ packet_done();
+
+ if (max < min || nbits < min || max < nbits)
+ fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
+ min, nbits, max);
+
+ dh = choose_dh(min, nbits, max);
+ if (dh == NULL)
+ packet_disconnect("Protocol error: no matching DH grp found");
+
+ debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
+ packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
+ packet_put_bignum2(dh->p);
+ packet_put_bignum2(dh->g);
+ packet_send();
+
+ /* flush */
+ packet_write_wait();
+
+ /* Compute our exchange value in parallel with the client */
+ dh_gen_key(dh, kex->we_need * 8);
+
+ debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
+ packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT);
+
+ /* key, cert */
+ dh_client_pub = BN_new();
+ if (dh_client_pub == NULL)
+ fatal("dh_client_pub == NULL");
+ packet_get_bignum2(dh_client_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "dh_client_pub= ");
+ BN_print_fp(stderr, dh_client_pub);
+ fprintf(stderr, "\n");
+ debug("bits %d", BN_num_bits(dh_client_pub));
+#endif
+
+#ifdef DEBUG_KEXDH
+ DHparams_print_fp(stderr, dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, dh->pub_key);
+ fprintf(stderr, "\n");
+#endif
+ if (!dh_pub_is_valid(dh, dh_client_pub))
+ packet_disconnect("bad client public DH value");
+
+ klen = DH_size(dh);
+ kbuf = xmalloc(klen);
+ kout = DH_compute_key(kbuf, dh_client_pub, dh);
+#ifdef DEBUG_KEXDH
+ dump_digest("shared secret", kbuf, kout);
+#endif
+ shared_secret = BN_new();
+ BN_bin2bn(kbuf, kout, shared_secret);
+ memset(kbuf, 0, klen);
+ xfree(kbuf);
+
+ key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
+
+ if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
+ min = max = -1;
+
+ /* calc H */ /* XXX depends on 'kex' */
+ hash = kexgex_hash(
+ kex->client_version_string,
+ kex->server_version_string,
+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+ buffer_ptr(&kex->my), buffer_len(&kex->my),
+ (char *)server_host_key_blob, sbloblen,
+ min, nbits, max,
+ dh->p, dh->g,
+ dh_client_pub,
+ dh->pub_key,
+ shared_secret
+ );
+ BN_free(dh_client_pub);
+
+ /* save session id := H */
+ /* XXX hashlen depends on KEX */
+ if (kex->session_id == NULL) {
+ kex->session_id_len = 20;
+ kex->session_id = xmalloc(kex->session_id_len);
+ memcpy(kex->session_id, hash, kex->session_id_len);
+ }
+
+ /* sign H */
+ /* XXX hashlen depends on KEX */
+ key_sign(server_host_key, &signature, &slen, hash, 20);
+
+ /* destroy_sensitive_data(); */
+
+ /* send server hostkey, DH pubkey 'f' and singed H */
+ debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
+ packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
+ packet_put_string((char *)server_host_key_blob, sbloblen);
+ packet_put_bignum2(dh->pub_key); /* f */
+ packet_put_string((char *)signature, slen);
+ packet_send();
+ xfree(signature);
+ xfree(server_host_key_blob);
+ /* have keys, free DH */
+ DH_free(dh);
+
+ kex_derive_keys(kex, hash, shared_secret);
+ BN_clear_free(shared_secret);
+
+ kex_finish(kex);
+}
+
+void
+kexgex(Kex *kex)
+{
+ if (kex->server)
+ kexgex_server(kex);
+ else
+ kexgex_client(kex);
+}
diff --git a/crypto/openssh/log.h b/crypto/openssh/log.h
new file mode 100644
index 000000000000..ad9fa3f2ab1b
--- /dev/null
+++ b/crypto/openssh/log.h
@@ -0,0 +1,75 @@
+/* $OpenBSD: log.h,v 1.2 2001/01/29 01:58:16 niklas Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef SSH_LOG_H
+#define SSH_LOG_H
+
+/* Supported syslog facilities and levels. */
+typedef enum {
+ SYSLOG_FACILITY_DAEMON,
+ SYSLOG_FACILITY_USER,
+ SYSLOG_FACILITY_AUTH,
+ SYSLOG_FACILITY_LOCAL0,
+ SYSLOG_FACILITY_LOCAL1,
+ SYSLOG_FACILITY_LOCAL2,
+ SYSLOG_FACILITY_LOCAL3,
+ SYSLOG_FACILITY_LOCAL4,
+ SYSLOG_FACILITY_LOCAL5,
+ SYSLOG_FACILITY_LOCAL6,
+ SYSLOG_FACILITY_LOCAL7
+} SyslogFacility;
+
+typedef enum {
+ SYSLOG_LEVEL_QUIET,
+ SYSLOG_LEVEL_FATAL,
+ SYSLOG_LEVEL_ERROR,
+ SYSLOG_LEVEL_INFO,
+ SYSLOG_LEVEL_VERBOSE,
+ SYSLOG_LEVEL_DEBUG1,
+ SYSLOG_LEVEL_DEBUG2,
+ SYSLOG_LEVEL_DEBUG3
+} LogLevel;
+/* Initializes logging. */
+void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
+
+/* Logging implementation, depending on server or client */
+void do_log(LogLevel level, const char *fmt, va_list args);
+
+/* name to facility/level */
+SyslogFacility log_facility_number(char *name);
+LogLevel log_level_number(char *name);
+
+/* Output a message to syslog or stderr */
+void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+
+/* same as fatal() but w/o logging */
+void fatal_cleanup(void);
+
+/*
+ * Registers a cleanup function to be called by fatal()/fatal_cleanup()
+ * before exiting. It is permissible to call fatal_remove_cleanup for the
+ * function itself from the function.
+ */
+void fatal_add_cleanup(void (*proc) (void *context), void *context);
+
+/* Removes a cleanup function to be called at fatal(). */
+void fatal_remove_cleanup(void (*proc) (void *context), void *context);
+
+#endif
diff --git a/crypto/openssh/mac.c b/crypto/openssh/mac.c
new file mode 100644
index 000000000000..e8b4267c3fc1
--- /dev/null
+++ b/crypto/openssh/mac.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2001 Markus Friedl. 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: mac.c,v 1.2 2001/04/05 10:42:51 markus Exp $");
+
+#include <openssl/hmac.h>
+
+#include "xmalloc.h"
+#include "getput.h"
+#include "log.h"
+#include "cipher.h"
+#include "kex.h"
+#include "mac.h"
+
+struct {
+ char *name;
+ EVP_MD * (*mdfunc)(void);
+ int truncatebits; /* truncate digest if != 0 */
+} macs[] = {
+ { "hmac-sha1", EVP_sha1, 0, },
+ { "hmac-sha1-96", EVP_sha1, 96 },
+ { "hmac-md5", EVP_md5, 0 },
+ { "hmac-md5-96", EVP_md5, 96 },
+ { "hmac-ripemd160", EVP_ripemd160, 0 },
+ { "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 },
+ { NULL, NULL, 0 }
+};
+
+int
+mac_init(Mac *mac, char *name)
+{
+ int i;
+ for (i = 0; macs[i].name; i++) {
+ if (strcmp(name, macs[i].name) == 0) {
+ if (mac != NULL) {
+ mac->md = (*macs[i].mdfunc)();
+ mac->key_len = mac->mac_len = mac->md->md_size;
+ if (macs[i].truncatebits != 0)
+ mac->mac_len = macs[i].truncatebits/8;
+ }
+ debug2("mac_init: found %s", name);
+ return (0);
+ }
+ }
+ debug2("mac_init: unknown %s", name);
+ return (-1);
+}
+
+u_char *
+mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
+{
+ HMAC_CTX c;
+ static u_char m[EVP_MAX_MD_SIZE];
+ u_char b[4];
+
+ if (mac->key == NULL)
+ fatal("mac_compute: no key");
+ if (mac->mac_len > sizeof(m))
+ fatal("mac_compute: mac too long");
+ HMAC_Init(&c, mac->key, mac->key_len, mac->md);
+ PUT_32BIT(b, seqno);
+ HMAC_Update(&c, b, sizeof(b));
+ HMAC_Update(&c, data, datalen);
+ HMAC_Final(&c, m, NULL);
+ HMAC_cleanup(&c);
+ return (m);
+}
+
+/* XXX copied from ciphers_valid */
+#define MAC_SEP ","
+int
+mac_valid(const char *names)
+{
+ char *maclist, *cp, *p;
+
+ if (names == NULL || strcmp(names, "") == 0)
+ return (0);
+ maclist = cp = xstrdup(names);
+ for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
+ (p = strsep(&cp, MAC_SEP))) {
+ if (mac_init(NULL, p) < 0) {
+ debug("bad mac %s [%s]", p, names);
+ xfree(maclist);
+ return (0);
+ } else {
+ debug3("mac ok: %s [%s]", p, names);
+ }
+ }
+ debug3("macs ok: [%s]", names);
+ xfree(maclist);
+ return (1);
+}
diff --git a/crypto/openssh/mac.h b/crypto/openssh/mac.h
new file mode 100644
index 000000000000..6173eaa66a41
--- /dev/null
+++ b/crypto/openssh/mac.h
@@ -0,0 +1,28 @@
+/* $OpenBSD: mac.h,v 1.1 2001/02/11 12:59:24 markus Exp $ */
+/*
+ * Copyright (c) 2001 Markus Friedl. 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.
+ */
+
+int mac_valid(const char *names);
+int mac_init(Mac *mac, char *name);
+u_char *mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen);
diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c
new file mode 100644
index 000000000000..b5c0fd1734c7
--- /dev/null
+++ b/crypto/openssh/misc.c
@@ -0,0 +1,130 @@
+/* $OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $ */
+
+/*
+ * Copyright (c) 2000 Markus Friedl. 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: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $");
+
+#include "misc.h"
+#include "log.h"
+#include "xmalloc.h"
+
+char *
+chop(char *s)
+{
+ char *t = s;
+ while (*t) {
+ if(*t == '\n' || *t == '\r') {
+ *t = '\0';
+ return s;
+ }
+ t++;
+ }
+ return s;
+
+}
+
+void
+set_nonblock(int fd)
+{
+ int val;
+ val = fcntl(fd, F_GETFL, 0);
+ if (val < 0) {
+ error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
+ return;
+ }
+ if (val & O_NONBLOCK) {
+ debug("fd %d IS O_NONBLOCK", fd);
+ return;
+ }
+ debug("fd %d setting O_NONBLOCK", fd);
+ val |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, val) == -1)
+ if (errno != ENODEV)
+ error("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
+ fd, strerror(errno));
+}
+
+/* Characters considered whitespace in strsep calls. */
+#define WHITESPACE " \t\r\n"
+
+char *
+strdelim(char **s)
+{
+ char *old;
+ int wspace = 0;
+
+ if (*s == NULL)
+ return NULL;
+
+ old = *s;
+
+ *s = strpbrk(*s, WHITESPACE "=");
+ if (*s == NULL)
+ return (old);
+
+ /* Allow only one '=' to be skipped */
+ if (*s[0] == '=')
+ wspace = 1;
+ *s[0] = '\0';
+
+ *s += strspn(*s + 1, WHITESPACE) + 1;
+ if (*s[0] == '=' && !wspace)
+ *s += strspn(*s + 1, WHITESPACE) + 1;
+
+ return (old);
+}
+
+struct passwd *
+pwcopy(struct passwd *pw)
+{
+ struct passwd *copy = xmalloc(sizeof(*copy));
+
+ memset(copy, 0, sizeof(*copy));
+ copy->pw_name = xstrdup(pw->pw_name);
+ copy->pw_passwd = xstrdup(pw->pw_passwd);
+ copy->pw_gecos = xstrdup(pw->pw_gecos);
+ copy->pw_uid = pw->pw_uid;
+ copy->pw_gid = pw->pw_gid;
+ copy->pw_class = xstrdup(pw->pw_class);
+ copy->pw_dir = xstrdup(pw->pw_dir);
+ copy->pw_shell = xstrdup(pw->pw_shell);
+ return copy;
+}
+
+int a2port(const char *s)
+{
+ long port;
+ char *endp;
+
+ errno = 0;
+ port = strtol(s, &endp, 0);
+ if (s == endp || *endp != '\0' ||
+ (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
+ port <= 0 || port > 65535)
+ return 0;
+
+ return port;
+}
diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h
new file mode 100644
index 000000000000..9cd4ac1b1b6b
--- /dev/null
+++ b/crypto/openssh/misc.h
@@ -0,0 +1,30 @@
+/* $OpenBSD: misc.h,v 1.4 2001/04/12 20:09:36 stevesk Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/* remove newline at end of string */
+char *chop(char *s);
+
+/* return next token in configuration line */
+char *strdelim(char **s);
+
+/* set filedescriptor to non-blocking */
+void set_nonblock(int fd);
+
+struct passwd * pwcopy(struct passwd *pw);
+
+/*
+ * Convert ASCII string to TCP/IP port number.
+ * Port must be >0 and <=65535.
+ * Return 0 if invalid.
+ */
+int a2port(const char *s);
diff --git a/crypto/openssh/pathnames.h b/crypto/openssh/pathnames.h
new file mode 100644
index 000000000000..0b0f2d333d4f
--- /dev/null
+++ b/crypto/openssh/pathnames.h
@@ -0,0 +1,112 @@
+/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#define ETCDIR "/etc/ssh"
+#define _PATH_SSH_PIDDIR "/var/run"
+
+/*
+ * System-wide file containing host keys of known hosts. This file should be
+ * world-readable.
+ */
+#define _PATH_SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
+#define _PATH_SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
+
+/*
+ * Of these, ssh_host_key must be readable only by root, whereas ssh_config
+ * should be world-readable.
+ */
+#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config"
+#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config"
+#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key"
+#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
+#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key"
+#define _PATH_DH_PRIMES ETCDIR "/primes"
+
+#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
+
+/*
+ * The process id of the daemon listening for connections is saved here to
+ * make it easier to kill the correct daemon when necessary.
+ */
+#define _PATH_SSH_DAEMON_PID_FILE _PATH_SSH_PIDDIR "/sshd.pid"
+
+/*
+ * The directory in user\'s home directory in which the files reside. The
+ * directory should be world-readable (though not all files are).
+ */
+#define _PATH_SSH_USER_DIR ".ssh"
+
+/*
+ * Per-user file containing host keys of known hosts. This file need not be
+ * readable by anyone except the user him/herself, though this does not
+ * contain anything particularly secret.
+ */
+#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts"
+#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
+
+/*
+ * Name of the default file containing client-side authentication key. This
+ * file should only be readable by the user him/herself.
+ */
+#define _PATH_SSH_CLIENT_IDENTITY ".ssh/identity"
+#define _PATH_SSH_CLIENT_ID_DSA ".ssh/id_dsa"
+#define _PATH_SSH_CLIENT_ID_RSA ".ssh/id_rsa"
+
+/*
+ * Configuration file in user\'s home directory. This file need not be
+ * readable by anyone but the user him/herself, but does not contain anything
+ * particularly secret. If the user\'s home directory resides on an NFS
+ * volume where root is mapped to nobody, this may need to be world-readable.
+ */
+#define _PATH_SSH_USER_CONFFILE ".ssh/config"
+
+/*
+ * File containing a list of those rsa keys that permit logging in as this
+ * user. This file need not be readable by anyone but the user him/herself,
+ * but does not contain anything particularly secret. If the user\'s home
+ * directory resides on an NFS volume where root is mapped to nobody, this
+ * may need to be world-readable. (This file is read by the daemon which is
+ * running as root.)
+ */
+#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
+#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
+
+/*
+ * Per-user and system-wide ssh "rc" files. These files are executed with
+ * /bin/sh before starting the shell or command if they exist. They will be
+ * passed "proto cookie" as arguments if X11 forwarding with spoofing is in
+ * use. xauth will be run if neither of these exists.
+ */
+#define _PATH_SSH_USER_RC ".ssh/rc"
+#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc"
+
+/*
+ * Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
+ * ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
+ */
+#define _PATH_SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
+#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv"
+
+/*
+ * Default location of askpass
+ */
+#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
+
+/* for scp */
+#define _PATH_CP "cp"
+
+/* for sftp */
+#define _PATH_SFTP_SERVER "/usr/libexec/sftp-server"
+#define _PATH_LS "ls"
diff --git a/crypto/openssh/radix.h b/crypto/openssh/radix.h
new file mode 100644
index 000000000000..57592d82313e
--- /dev/null
+++ b/crypto/openssh/radix.h
@@ -0,0 +1,28 @@
+/* $OpenBSD: radix.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999 Dug Song. 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.
+ */
+
+int creds_to_radix(CREDENTIALS * creds, u_char *buf, size_t buflen);
+int radix_to_creds(const char *buf, CREDENTIALS * creds);
diff --git a/crypto/openssh/readpass.h b/crypto/openssh/readpass.h
new file mode 100644
index 000000000000..d8da448a7a7b
--- /dev/null
+++ b/crypto/openssh/readpass.h
@@ -0,0 +1,20 @@
+/* $OpenBSD: readpass.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * Reads a passphrase from /dev/tty with echo turned off. Returns the
+ * passphrase (allocated with xmalloc). Exits if EOF is encountered. If
+ * from_stdin is true, the passphrase will be read from stdin instead.
+ */
+char *read_passphrase(char *prompt, int from_stdin);
diff --git a/crypto/openssh/scp-common.c b/crypto/openssh/scp-common.c
new file mode 100644
index 000000000000..7e5f09c74fae
--- /dev/null
+++ b/crypto/openssh/scp-common.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1999 Theo de Raadt. All rights reserved.
+ * Copyright (c) 1999 Aaron Campbell. 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.
+ */
+
+/*
+ * Parts from:
+ *
+ * Copyright (c) 1983, 1990, 1992, 1993, 1995
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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: scp-common.c,v 1.1 2001/04/16 02:31:43 mouring Exp $");
+
+char *
+cleanhostname(host)
+ char *host;
+{
+ if (*host == '[' && host[strlen(host) - 1] == ']') {
+ host[strlen(host) - 1] = '\0';
+ return (host + 1);
+ } else
+ return host;
+}
+
+char *
+colon(cp)
+ char *cp;
+{
+ int flag = 0;
+
+ if (*cp == ':') /* Leading colon is part of file name. */
+ return (0);
+ if (*cp == '[')
+ flag = 1;
+
+ for (; *cp; ++cp) {
+ if (*cp == '@' && *(cp+1) == '[')
+ flag = 1;
+ if (*cp == ']' && *(cp+1) == ':' && flag)
+ return (cp+1);
+ if (*cp == ':' && !flag)
+ return (cp);
+ if (*cp == '/')
+ return (0);
+ }
+ return (0);
+}
diff --git a/crypto/openssh/scp-common.h b/crypto/openssh/scp-common.h
new file mode 100644
index 000000000000..e0ab6ec32a7d
--- /dev/null
+++ b/crypto/openssh/scp-common.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: scp-common.h,v 1.1 2001/04/16 02:31:43 mouring Exp $ */
+/*
+ * Copyright (c) 1999 Theo de Raadt. All rights reserved.
+ * Copyright (c) 1999 Aaron Campbell. 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.
+ */
+
+/*
+ * Parts from:
+ *
+ * Copyright (c) 1983, 1990, 1992, 1993, 1995
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ */
+
+char *cleanhostname(char *host);
+char *colon(char *cp);
diff --git a/crypto/openssh/serverloop.h b/crypto/openssh/serverloop.h
new file mode 100644
index 000000000000..652c1d9f8e5f
--- /dev/null
+++ b/crypto/openssh/serverloop.h
@@ -0,0 +1,22 @@
+/* $OpenBSD: serverloop.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Performs the interactive session. This handles data transmission between
+ * the client and the program. Note that the notion of stdin, stdout, and
+ * stderr in this function is sort of reversed: this function writes to stdin
+ * (of the child program), and reads from stdout and stderr (of the child
+ * program).
+ */
+void server_loop(pid_t pid, int fdin, int fdout, int fderr);
+void server_loop2(void);
diff --git a/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c
new file mode 100644
index 000000000000..b5d2fd3b9476
--- /dev/null
+++ b/crypto/openssh/sftp-client.c
@@ -0,0 +1,930 @@
+/*
+ * 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.16 2001/04/05 10:42:52 markus 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
+
+/* Message ID */
+static u_int msg_id = 1;
+
+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 == 0)
+ fatal("Connection closed");
+ else if (len == -1)
+ 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("Connection closed");
+ else if (len == -1)
+ 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, int quiet)
+{
+ 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);
+
+ if (quiet)
+ debug("Couldn't stat remote file: %s", fx2txt(status));
+ else
+ 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(version);
+}
+
+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 = msg_id++;
+ 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_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
+ SFTP_DIRENT ***dir)
+{
+ Buffer msg;
+ u_int type, id, handle_len, i, expected_id, ents = 0;
+ char *handle;
+
+ id = msg_id++;
+
+ 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);
+
+ if (dir) {
+ ents = 0;
+ *dir = xmalloc(sizeof(**dir));
+ (*dir)[0] = NULL;
+ }
+
+
+ for(;;) {
+ int count;
+
+ id = expected_id = msg_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(status);
+ }
+ } 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 == 0)
+ break;
+ debug3("Received %d 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);
+
+ if (printflag)
+ printf("%s\n", longname);
+
+ if (dir) {
+ *dir = xrealloc(*dir, sizeof(**dir) *
+ (ents + 2));
+ (*dir)[ents] = xmalloc(sizeof(***dir));
+ (*dir)[ents]->filename = xstrdup(filename);
+ (*dir)[ents]->longname = xstrdup(longname);
+ memcpy(&(*dir)[ents]->a, a, sizeof(*a));
+ (*dir)[++ents] = NULL;
+ }
+
+ xfree(filename);
+ xfree(longname);
+ }
+ }
+
+ buffer_free(&msg);
+ do_close(fd_in, fd_out, handle, handle_len);
+ xfree(handle);
+
+ return(0);
+}
+
+int
+do_ls(int fd_in, int fd_out, char *path)
+{
+ return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
+}
+
+int
+do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
+{
+ return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
+}
+
+void free_sftp_dirents(SFTP_DIRENT **s)
+{
+ int i;
+
+ for(i = 0; s[i]; i++) {
+ xfree(s[i]->filename);
+ xfree(s[i]->longname);
+ xfree(s[i]);
+ }
+ xfree(s);
+}
+
+int
+do_rm(int fd_in, int fd_out, char *path)
+{
+ u_int status, id;
+
+ debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
+
+ id = msg_id++;
+ 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 = msg_id++;
+ 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 = msg_id++;
+ 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, int quiet)
+{
+ u_int id;
+
+ id = msg_id++;
+ send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
+ return(get_decode_stat(fd_in, id, quiet));
+}
+
+Attrib *
+do_lstat(int fd_in, int fd_out, char *path, int quiet)
+{
+ u_int id;
+
+ id = msg_id++;
+ send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
+ return(get_decode_stat(fd_in, id, quiet));
+}
+
+Attrib *
+do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
+{
+ u_int id;
+
+ id = msg_id++;
+ send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
+ return(get_decode_stat(fd_in, id, quiet));
+}
+
+int
+do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
+{
+ u_int status, id;
+
+ id = msg_id++;
+ 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 = msg_id++;
+ 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 = msg_id++;
+ 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 = msg_id++;
+ 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_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
+{
+ Buffer msg;
+ u_int status, id;
+
+ buffer_init(&msg);
+
+ /* Send rename request */
+ id = msg_id++;
+ buffer_put_char(&msg, SSH2_FXP_SYMLINK);
+ 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_SYMLINK \"%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);
+}
+
+char *
+do_readlink(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 = msg_id++;
+ send_string_request(fd_out, id, SSH2_FXP_READLINK, 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 readlink: %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_READLINK", count);
+
+ filename = buffer_get_string(&msg, NULL);
+ longname = buffer_get_string(&msg, NULL);
+ a = decode_attrib(&msg);
+
+ debug3("SSH_FXP_READLINK %s -> %s", path, filename);
+
+ xfree(longname);
+
+ buffer_free(&msg);
+
+ return(filename);
+}
+
+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;
+ int status;
+
+ a = do_stat(fd_in, fd_out, remote_path, 0);
+ 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;
+
+ if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+ (a->perm & S_IFDIR)) {
+ error("Cannot download a directory: %s", remote_path);
+ return(-1);
+ }
+
+ 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(-1);
+ }
+
+ buffer_init(&msg);
+
+ /* Send open request */
+ id = msg_id++;
+ 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;
+
+ id = expected_id = msg_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, (unsigned long long)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) {
+ 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);
+ goto done;
+ }
+ } 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 %llu", len,
+ (unsigned long long)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);
+ status = -1;
+ xfree(data);
+ goto done;
+ }
+
+ offset += len;
+ xfree(data);
+ }
+ status = do_close(fd_in, fd_out, handle, handle_len);
+
+ /* 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[2];
+ tv[0].tv_sec = a->atime;
+ tv[1].tv_sec = a->mtime;
+ tv[0].tv_usec = tv[1].tv_usec = 0;
+ if (utimes(local_path, tv) == -1)
+ error("Can't set times on \"%s\": %s", local_path,
+ strerror(errno));
+ }
+
+done:
+ close(local_fd);
+ buffer_free(&msg);
+ xfree(handle);
+ return status;
+}
+
+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;
+ int status;
+
+ 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 = msg_id++;
+ 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);
+ }
+
+ /* Read from local and write to remote */
+ offset = 0;
+ for(;;) {
+ int len;
+ char data[COPY_SIZE];
+
+ /*
+ * 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, (unsigned long long)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);
+ close(local_fd);
+ goto done;
+ }
+ debug3("In write loop, got %d offset %llu", len,
+ (unsigned long long)offset);
+
+ offset += len;
+ }
+
+ 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);
+ status = -1;
+ goto done;
+ }
+
+ /* Override umask and utimes if asked */
+ if (pflag)
+ do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
+
+ status = do_close(fd_in, fd_out, handle, handle_len);
+
+done:
+ xfree(handle);
+ buffer_free(&msg);
+ return status;
+}
+
diff --git a/crypto/openssh/sftp-client.h b/crypto/openssh/sftp-client.h
new file mode 100644
index 000000000000..09ffcc05cb37
--- /dev/null
+++ b/crypto/openssh/sftp-client.h
@@ -0,0 +1,107 @@
+/* $OpenBSD: sftp-client.h,v 1.5 2001/04/05 10:42:52 markus 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 */
+
+typedef struct SFTP_DIRENT SFTP_DIRENT;
+
+struct SFTP_DIRENT {
+ char *filename;
+ char *longname;
+ Attrib a;
+};
+
+/*
+ * Initialiase a SSH filexfer connection. Returns -1 on error or
+ * protocol version on success.
+ */
+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);
+
+/* Read contents of 'path' to NULL-terminated array 'dir' */
+int do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir);
+
+/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
+void free_sftp_dirents(SFTP_DIRENT **s);
+
+/* 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, int quiet);
+
+/* Get file attributes of 'path' (does not follow symlinks) */
+Attrib *do_lstat(int fd_in, int fd_out, char *path, int quiet);
+
+/* Get file attributes of open file 'handle' */
+Attrib *do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len,
+ int quiet);
+
+/* 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);
+
+/* Rename 'oldpath' to 'newpath' */
+int do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath);
+
+/* Return target of symlink 'path' - caller must free result */
+char *do_readlink(int fd_in, int fd_out, char *path);
+
+/* 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);
diff --git a/crypto/openssh/sftp-common.c b/crypto/openssh/sftp-common.c
new file mode 100644
index 000000000000..3310eabab577
--- /dev/null
+++ b/crypto/openssh/sftp-common.c
@@ -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.2 2001/02/06 23:50:10 markus 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 or directory");
+ 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 */
+}
+
diff --git a/crypto/openssh/sftp-common.h b/crypto/openssh/sftp-common.h
new file mode 100644
index 000000000000..6dc1a32f8fde
--- /dev/null
+++ b/crypto/openssh/sftp-common.h
@@ -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);
+
diff --git a/crypto/openssh/sftp-glob.c b/crypto/openssh/sftp-glob.c
new file mode 100644
index 000000000000..18d81c0b0e46
--- /dev/null
+++ b/crypto/openssh/sftp-glob.c
@@ -0,0 +1,146 @@
+/*
+ * 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-glob.c,v 1.5 2001/04/15 08:43:46 markus Exp $");
+
+#include <glob.h>
+
+#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"
+#include "sftp-glob.h"
+
+struct SFTP_OPENDIR {
+ SFTP_DIRENT **dir;
+ int offset;
+};
+
+static struct {
+ int fd_in;
+ int fd_out;
+} cur;
+
+void *fudge_opendir(const char *path)
+{
+ struct SFTP_OPENDIR *r;
+
+ r = xmalloc(sizeof(*r));
+
+ if (do_readdir(cur.fd_in, cur.fd_out, (char*)path, &r->dir))
+ return(NULL);
+
+ r->offset = 0;
+
+ return((void*)r);
+}
+
+struct dirent *fudge_readdir(struct SFTP_OPENDIR *od)
+{
+ static struct dirent ret;
+
+ if (od->dir[od->offset] == NULL)
+ return(NULL);
+
+ memset(&ret, 0, sizeof(ret));
+ strlcpy(ret.d_name, od->dir[od->offset++]->filename,
+ sizeof(ret.d_name));
+
+ return(&ret);
+}
+
+void fudge_closedir(struct SFTP_OPENDIR *od)
+{
+ free_sftp_dirents(od->dir);
+ xfree(od);
+}
+
+void attrib_to_stat(Attrib *a, struct stat *st)
+{
+ memset(st, 0, sizeof(*st));
+
+ if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
+ st->st_size = a->size;
+ if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+ st->st_uid = a->uid;
+ st->st_gid = a->gid;
+ }
+ if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+ st->st_mode = a->perm;
+ if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+ st->st_atime = a->atime;
+ st->st_mtime = a->mtime;
+ }
+}
+
+int fudge_lstat(const char *path, struct stat *st)
+{
+ Attrib *a;
+
+ if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0)))
+ return(-1);
+
+ attrib_to_stat(a, st);
+
+ return(0);
+}
+
+int fudge_stat(const char *path, struct stat *st)
+{
+ Attrib *a;
+
+ if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0)))
+ return(-1);
+
+ attrib_to_stat(a, st);
+
+ return(0);
+}
+
+int
+remote_glob(int fd_in, int fd_out, const char *pattern, int flags,
+ int (*errfunc)(const char *, int), glob_t *pglob)
+{
+ pglob->gl_opendir = (void*)fudge_opendir;
+ pglob->gl_readdir = (void*)fudge_readdir;
+ pglob->gl_closedir = (void*)fudge_closedir;
+ pglob->gl_lstat = fudge_lstat;
+ pglob->gl_stat = fudge_stat;
+
+ memset(&cur, 0, sizeof(cur));
+ cur.fd_in = fd_in;
+ cur.fd_out = fd_out;
+
+ return(glob(pattern, flags | GLOB_ALTDIRFUNC, (void*)errfunc,
+ pglob));
+}
diff --git a/crypto/openssh/sftp-glob.h b/crypto/openssh/sftp-glob.h
new file mode 100644
index 000000000000..4206af439769
--- /dev/null
+++ b/crypto/openssh/sftp-glob.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: sftp-glob.h,v 1.3 2001/04/15 08:43:46 markus 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.
+ */
+
+/* Remote sftp filename globbing */
+
+int
+remote_glob(int fd_in, int fd_out, const char *pattern, int flags,
+ int (*errfunc)(const char *, int), glob_t *pglob);
+
diff --git a/crypto/openssh/sftp-int.c b/crypto/openssh/sftp-int.c
new file mode 100644
index 000000000000..3a71daac4cb2
--- /dev/null
+++ b/crypto/openssh/sftp-int.c
@@ -0,0 +1,917 @@
+/*
+ * 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: globbed ls */
+/* XXX: recursive operations */
+
+#include "includes.h"
+RCSID("$OpenBSD: sftp-int.c,v 1.36 2001/04/15 08:43:46 markus Exp $");
+
+#include <glob.h>
+
+#include "buffer.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "pathnames.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+#include "sftp-glob.h"
+#include "sftp-client.h"
+#include "sftp-int.h"
+
+/* File to read commands from */
+extern FILE *infile;
+
+/* Version of server we are speaking to */
+int version;
+
+/* 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
+#define I_SYMLINK 21
+#define I_VERSION 22
+
+struct CMD {
+ const char *c;
+ const int n;
+};
+
+const struct CMD cmds[] = {
+ { "cd", I_CHDIR },
+ { "chdir", I_CHDIR },
+ { "chgrp", I_CHGRP },
+ { "chmod", I_CHMOD },
+ { "chown", I_CHOWN },
+ { "dir", I_LS },
+ { "exit", I_QUIT },
+ { "get", I_GET },
+ { "mget", I_GET },
+ { "help", I_HELP },
+ { "lcd", I_LCHDIR },
+ { "lchdir", I_LCHDIR },
+ { "lls", I_LLS },
+ { "lmkdir", I_LMKDIR },
+ { "ln", I_SYMLINK },
+ { "lpwd", I_LPWD },
+ { "ls", I_LS },
+ { "lumask", I_LUMASK },
+ { "mkdir", I_MKDIR },
+ { "put", I_PUT },
+ { "mput", I_PUT },
+ { "pwd", I_PWD },
+ { "quit", I_QUIT },
+ { "rename", I_RENAME },
+ { "rm", I_RM },
+ { "rmdir", I_RMDIR },
+ { "symlink", I_SYMLINK },
+ { "version", I_VERSION },
+ { "!", I_SHELL },
+ { "?", I_HELP },
+ { NULL, -1}
+};
+
+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("ln oldpath newpath Symlink remote file\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("symlink oldpath newpath Symlink remote file\n");
+ printf("version Show SFTP version\n");
+ printf("!command Execute 'command' in local shell\n");
+ printf("! Escape to local shell\n");
+ printf("? Synonym for help\n");
+}
+
+void
+local_do_shell(const char *args)
+{
+ int 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);
+ execl(shell, shell, "-c", args, NULL);
+ } else {
+ debug3("Executing %s", shell);
+ 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(_PATH_LS);
+ else {
+ int len = strlen(_PATH_LS " ") + strlen(args) + 1;
+ char *buf = xmalloc(len);
+
+ /* XXX: quoting - rip quoting code from ftp? */
+ snprintf(buf, len, _PATH_LS " %s", args);
+ local_do_shell(buf);
+ xfree(buf);
+ }
+}
+
+char *
+path_append(char *p1, char *p2)
+{
+ char *ret;
+ int len = strlen(p1) + strlen(p2) + 2;
+
+ ret = xmalloc(len);
+ strlcpy(ret, p1, len);
+ strlcat(ret, "/", len);
+ strlcat(ret, p2, len);
+
+ return(ret);
+}
+
+char *
+make_absolute(char *p, char *pwd)
+{
+ char *abs;
+
+ /* Derelativise */
+ if (p && p[0] != '/') {
+ abs = path_append(pwd, p);
+ xfree(p);
+ return(abs);
+ } else
+ return(p);
+}
+
+int
+infer_path(const char *p, char **ifp)
+{
+ char *cp;
+
+ 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_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[1]) {
+ case 'p':
+ case 'P':
+ *pflag = 1;
+ break;
+ default:
+ error("Invalid flag -%c", cp[1]);
+ return(-1);
+ }
+ cp += 2;
+ *cpp = cp + strspn(cp, WHITESPACE);
+ }
+
+ return(0);
+}
+
+int
+get_pathname(const char **cpp, char **path)
+{
+ const char *cp = *cpp, *end;
+ char quot;
+ int i;
+
+ cp += strspn(cp, WHITESPACE);
+ if (!*cp) {
+ *cpp = cp;
+ *path = NULL;
+ return (0);
+ }
+
+ /* Check for quoted filenames */
+ if (*cp == '\"' || *cp == '\'') {
+ quot = *cp++;
+
+ end = strchr(cp, quot);
+ if (end == NULL) {
+ error("Unterminated quote");
+ goto fail;
+ }
+ if (cp == end) {
+ error("Empty quotes");
+ goto fail;
+ }
+ *cpp = end + 1 + strspn(end + 1, WHITESPACE);
+ } else {
+ /* Read to end of filename */
+ end = strpbrk(cp, WHITESPACE);
+ if (end == NULL)
+ end = strchr(cp, '\0');
+ *cpp = end + strspn(end, WHITESPACE);
+ }
+
+ i = end - cp;
+
+ *path = xmalloc(i + 1);
+ memcpy(*path, cp, i);
+ (*path)[i] = '\0';
+ return(0);
+
+ fail:
+ *path = NULL;
+ return (-1);
+}
+
+int
+is_dir(char *path)
+{
+ struct stat sb;
+
+ /* XXX: report errors? */
+ if (stat(path, &sb) == -1)
+ return(0);
+
+ return(sb.st_mode & S_IFDIR);
+}
+
+int
+remote_is_dir(int in, int out, char *path)
+{
+ Attrib *a;
+
+ /* XXX: report errors? */
+ if ((a = do_stat(in, out, path, 1)) == NULL)
+ return(0);
+ if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
+ return(0);
+ return(a->perm & S_IFDIR);
+}
+
+int
+process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
+{
+ char *abs_src = NULL;
+ char *abs_dst = NULL;
+ char *tmp;
+ glob_t g;
+ int err = 0;
+ int i;
+
+ abs_src = xstrdup(src);
+ abs_src = make_absolute(abs_src, pwd);
+
+ memset(&g, 0, sizeof(g));
+ debug3("Looking up %s", abs_src);
+ if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
+ error("File \"%s\" not found.", abs_src);
+ err = -1;
+ goto out;
+ }
+
+ /* Only one match, dst may be file, directory or unspecified */
+ if (g.gl_pathv[0] && g.gl_matchc == 1) {
+ if (dst) {
+ /* If directory specified, append filename */
+ if (is_dir(dst)) {
+ if (infer_path(g.gl_pathv[0], &tmp)) {
+ err = 1;
+ goto out;
+ }
+ abs_dst = path_append(dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = xstrdup(dst);
+ } else if (infer_path(g.gl_pathv[0], &abs_dst)) {
+ err = -1;
+ goto out;
+ }
+ printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
+ err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
+ goto out;
+ }
+
+ /* Multiple matches, dst may be directory or unspecified */
+ if (dst && !is_dir(dst)) {
+ error("Multiple files match, but \"%s\" is not a directory",
+ dst);
+ err = -1;
+ goto out;
+ }
+
+ for(i = 0; g.gl_pathv[i]; i++) {
+ if (infer_path(g.gl_pathv[i], &tmp)) {
+ err = -1;
+ goto out;
+ }
+ if (dst) {
+ abs_dst = path_append(dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = tmp;
+
+ printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
+ if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
+ err = -1;
+ xfree(abs_dst);
+ abs_dst = NULL;
+ }
+
+out:
+ xfree(abs_src);
+ if (abs_dst)
+ xfree(abs_dst);
+ globfree(&g);
+ return(err);
+}
+
+int
+process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
+{
+ char *tmp_dst = NULL;
+ char *abs_dst = NULL;
+ char *tmp;
+ glob_t g;
+ int err = 0;
+ int i;
+
+ if (dst) {
+ tmp_dst = xstrdup(dst);
+ tmp_dst = make_absolute(tmp_dst, pwd);
+ }
+
+ memset(&g, 0, sizeof(g));
+ debug3("Looking up %s", src);
+ if (glob(src, 0, NULL, &g)) {
+ error("File \"%s\" not found.", src);
+ err = -1;
+ goto out;
+ }
+
+ /* Only one match, dst may be file, directory or unspecified */
+ if (g.gl_pathv[0] && g.gl_matchc == 1) {
+ if (tmp_dst) {
+ /* If directory specified, append filename */
+ if (remote_is_dir(in, out, tmp_dst)) {
+ if (infer_path(g.gl_pathv[0], &tmp)) {
+ err = 1;
+ goto out;
+ }
+ abs_dst = path_append(tmp_dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = xstrdup(tmp_dst);
+ } else {
+ if (infer_path(g.gl_pathv[0], &abs_dst)) {
+ err = -1;
+ goto out;
+ }
+ abs_dst = make_absolute(abs_dst, pwd);
+ }
+ printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
+ err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
+ goto out;
+ }
+
+ /* Multiple matches, dst may be directory or unspecified */
+ if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
+ error("Multiple files match, but \"%s\" is not a directory",
+ tmp_dst);
+ err = -1;
+ goto out;
+ }
+
+ for(i = 0; g.gl_pathv[i]; i++) {
+ if (infer_path(g.gl_pathv[i], &tmp)) {
+ err = -1;
+ goto out;
+ }
+ if (tmp_dst) {
+ abs_dst = path_append(tmp_dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = make_absolute(tmp, pwd);
+
+ printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
+ if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
+ err = -1;
+ }
+
+out:
+ if (abs_dst)
+ xfree(abs_dst);
+ if (tmp_dst)
+ xfree(tmp_dst);
+ return(err);
+}
+
+int
+parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
+ char **path1, char **path2)
+{
+ const char *cmd, *cp = *cpp;
+ char *cp2;
+ int base = 0;
+ long l;
+ 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);
+ break;
+ case I_RENAME:
+ case I_SYMLINK:
+ 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:
+ base = 8;
+ case I_CHMOD:
+ base = 8;
+ case I_CHOWN:
+ case I_CHGRP:
+ /* Get numeric arg (mandatory) */
+ l = strtol(cp, &cp2, base);
+ if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) &&
+ errno == ERANGE) || l < 0) {
+ error("You must supply a numeric argument "
+ "to the %s command.", cmd);
+ return(-1);
+ }
+ cp = cp2;
+ *n_arg = l;
+ if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp))
+ break;
+ if (cmdnum == I_LUMASK || !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:
+ case I_VERSION:
+ 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, *tmp;
+ int pflag, cmdnum, i;
+ unsigned long n_arg;
+ Attrib a, *aa;
+ char path_buf[MAXPATHLEN];
+ int err = 0;
+ glob_t g;
+
+ path1 = path2 = NULL;
+ cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
+
+ memset(&g, 0, sizeof(g));
+
+ /* Perform command */
+ switch (cmdnum) {
+ case -1:
+ break;
+ case I_GET:
+ err = process_get(in, out, path1, path2, *pwd, pflag);
+ break;
+ case I_PUT:
+ err = process_put(in, out, path1, path2, *pwd, pflag);
+ break;
+ case I_RENAME:
+ path1 = make_absolute(path1, *pwd);
+ path2 = make_absolute(path2, *pwd);
+ err = do_rename(in, out, path1, path2);
+ break;
+ case I_SYMLINK:
+ if (version < 3) {
+ error("The server (version %d) does not support "
+ "this operation", version);
+ err = -1;
+ } else {
+ path2 = make_absolute(path2, *pwd);
+ err = do_symlink(in, out, path1, path2);
+ }
+ break;
+ case I_RM:
+ path1 = make_absolute(path1, *pwd);
+ remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+ for(i = 0; g.gl_pathv[i]; i++) {
+ printf("Removing %s\n", g.gl_pathv[i]);
+ if (do_rm(in, out, g.gl_pathv[i]) == -1)
+ err = -1;
+ }
+ break;
+ case I_MKDIR:
+ path1 = make_absolute(path1, *pwd);
+ attrib_clear(&a);
+ a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
+ a.perm = 0777;
+ err = do_mkdir(in, out, path1, &a);
+ break;
+ case I_RMDIR:
+ path1 = make_absolute(path1, *pwd);
+ err = do_rmdir(in, out, path1);
+ break;
+ case I_CHDIR:
+ path1 = make_absolute(path1, *pwd);
+ if ((tmp = do_realpath(in, out, path1)) == NULL) {
+ err = 1;
+ break;
+ }
+ if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
+ xfree(tmp);
+ err = 1;
+ break;
+ }
+ if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
+ error("Can't change directory: Can't check target");
+ xfree(tmp);
+ err = 1;
+ break;
+ }
+ if (!S_ISDIR(aa->perm)) {
+ error("Can't change directory: \"%s\" is not "
+ "a directory", tmp);
+ xfree(tmp);
+ err = 1;
+ break;
+ }
+ xfree(*pwd);
+ *pwd = tmp;
+ break;
+ case I_LS:
+ if (!path1) {
+ do_ls(in, out, *pwd);
+ break;
+ }
+ path1 = make_absolute(path1, *pwd);
+ if ((tmp = do_realpath(in, out, path1)) == NULL)
+ break;
+ xfree(path1);
+ path1 = tmp;
+ if ((aa = do_stat(in, out, path1, 0)) == NULL)
+ break;
+ if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+ !S_ISDIR(aa->perm)) {
+ error("Can't ls: \"%s\" is not a directory", path1);
+ break;
+ }
+ do_ls(in, out, path1);
+ break;
+ case I_LCHDIR:
+ if (chdir(path1) == -1) {
+ error("Couldn't change local directory to "
+ "\"%s\": %s", path1, strerror(errno));
+ err = 1;
+ }
+ break;
+ case I_LMKDIR:
+ if (mkdir(path1, 0777) == -1) {
+ error("Couldn't create local directory "
+ "\"%s\": %s", path1, strerror(errno));
+ err = 1;
+ }
+ break;
+ case I_LLS:
+ local_do_ls(cmd);
+ break;
+ case I_SHELL:
+ local_do_shell(cmd);
+ break;
+ case I_LUMASK:
+ umask(n_arg);
+ printf("Local umask: %03lo\n", n_arg);
+ break;
+ case I_CHMOD:
+ path1 = make_absolute(path1, *pwd);
+ attrib_clear(&a);
+ a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
+ a.perm = n_arg;
+ remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+ for(i = 0; g.gl_pathv[i]; i++) {
+ printf("Changing mode on %s\n", g.gl_pathv[i]);
+ do_setstat(in, out, g.gl_pathv[i], &a);
+ }
+ break;
+ case I_CHOWN:
+ path1 = make_absolute(path1, *pwd);
+ remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+ for(i = 0; g.gl_pathv[i]; i++) {
+ if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
+ continue;
+ if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
+ error("Can't get current ownership of "
+ "remote file \"%s\"", g.gl_pathv[i]);
+ continue;
+ }
+ printf("Changing owner on %s\n", g.gl_pathv[i]);
+ aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
+ aa->uid = n_arg;
+ do_setstat(in, out, g.gl_pathv[i], aa);
+ }
+ break;
+ case I_CHGRP:
+ path1 = make_absolute(path1, *pwd);
+ remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+ for(i = 0; g.gl_pathv[i]; i++) {
+ if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
+ continue;
+ if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
+ error("Can't get current ownership of "
+ "remote file \"%s\"", g.gl_pathv[i]);
+ continue;
+ }
+ printf("Changing group on %s\n", g.gl_pathv[i]);
+ aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
+ aa->gid = n_arg;
+ do_setstat(in, out, g.gl_pathv[i], 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",
+ strerror(errno));
+ else
+ printf("Local working directory: %s\n",
+ path_buf);
+ break;
+ case I_QUIT:
+ return(-1);
+ case I_HELP:
+ help();
+ break;
+ case I_VERSION:
+ printf("SFTP protocol version %d\n", version);
+ break;
+ default:
+ fatal("%d is not implemented", cmdnum);
+ }
+
+ if (g.gl_pathc)
+ globfree(&g);
+ if (path1)
+ xfree(path1);
+ if (path2)
+ xfree(path2);
+
+ /* If an error occurs in batch mode we should abort. */
+ if (infile != stdin && err > 0)
+ return -1;
+
+ return(0);
+}
+
+void
+interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
+{
+ char *pwd;
+ char *dir = NULL;
+ char cmd[2048];
+
+ version = do_init(fd_in, fd_out);
+ if (version == -1)
+ fatal("Couldn't initialise connection to server");
+
+ pwd = do_realpath(fd_in, fd_out, ".");
+ if (pwd == NULL)
+ fatal("Need cwd");
+
+ if (file1 != NULL) {
+ dir = xstrdup(file1);
+ dir = make_absolute(dir, pwd);
+
+ if (remote_is_dir(fd_in, fd_out, dir) && file2 == NULL) {
+ printf("Changing to: %s\n", dir);
+ snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
+ parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
+ } else {
+ if (file2 == NULL)
+ snprintf(cmd, sizeof cmd, "get %s", dir);
+ else
+ snprintf(cmd, sizeof cmd, "get %s %s", dir,
+ file2);
+
+ parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
+ return;
+ }
+ }
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ setvbuf(infile, NULL, _IOLBF, 0);
+
+ for(;;) {
+ char *cp;
+
+ printf("sftp> ");
+
+ /* XXX: use libedit */
+ if (fgets(cmd, sizeof(cmd), infile) == NULL) {
+ printf("\n");
+ break;
+ } else if (infile != stdin) /* Bluff typing */
+ printf("%s", cmd);
+
+ cp = strrchr(cmd, '\n');
+ if (cp)
+ *cp = '\0';
+
+ if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd))
+ break;
+ }
+ xfree(pwd);
+}
diff --git a/crypto/openssh/sftp-int.h b/crypto/openssh/sftp-int.h
new file mode 100644
index 000000000000..b47f862f8fed
--- /dev/null
+++ b/crypto/openssh/sftp-int.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: sftp-int.h,v 1.2 2001/04/12 23:17:54 mouring 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, char *file1, char *file2);
diff --git a/crypto/openssh/sftp.1 b/crypto/openssh/sftp.1
new file mode 100644
index 000000000000..b482996ed1c7
--- /dev/null
+++ b/crypto/openssh/sftp.1
@@ -0,0 +1,222 @@
+.\" $OpenBSD: sftp.1,v 1.17 2001/04/22 13:32:27 markus 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 February 4, 2001
+.Dt SFTP 1
+.Os
+.Sh NAME
+.Nm sftp
+.Nd Secure file transfer program
+.Sh SYNOPSIS
+.Nm sftp
+.Op Fl vC
+.Op Fl b Ar batchfile
+.Op Fl o Ar ssh_option
+.Op Ar host
+.Nm sftp
+.Op [\fIuser\fR@]\fIhost\fR[:\fIfile\fR [\fIfile\fR]]
+.Nm sftp
+.Op [\fIuser\fR@]\fIhost\fR[:\fIdir\fR[\fI/\fR]]
+.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 second usage format will fetch files automaticly if a non-interactive
+authentication is used, else it do so after an interactive authentication
+is used.
+.Pp
+The last usage format allows the sftp client to start in a remote directory.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b Ar batchfile
+Batch mode reads a series of commands from an input
+.Ar batchfile
+instead of
+.Em stdin .
+Since it lacks user interaction it should be used in conjunction with
+non-interactive authentication.
+.Nm
+will abort if any of the following
+commands fail:
+.Ic get , put , rename , ln , rm , mkdir , chdir , lchdir
+and
+.Ic lmkdir .
+.It Fl C
+Enables compression (via ssh's
+.Fl C
+flag)
+.It Fl o Ar ssh_option
+Specify an option to be directly passed to
+.Xr ssh 1 .
+.It Fl v
+Raise logging level. This option is also passed to ssh.
+.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 and pathnames may be enclosed in quotes if they
+contain spaces.
+.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 a numeric GID.
+.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 exit
+Quit sftp.
+.It Xo Ic get
+.Op Ar flags
+.Ar remote-path
+.Op Ar local-path
+.Xc
+Retrieve the
+.Ar remote-path
+and store it on the local machine.
+If the local
+path name is not specified, it is given the same name it has on the
+remote machine. If the
+.Fl P
+flag is specified, then the file's full permission and access time are
+copied too.
+.It Ic help
+Display help text.
+.It Ic lls Op Ar ls-options Op Ar path
+Display local directory listing of either
+.Ar path
+or current directory if
+.Ar path
+is not specified.
+.It Ic lmkdir Ar path
+Create local directory specified by
+.Ar path .
+.It Ic ln Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic lpwd
+Print local working directory.
+.It Ic ls Op Ar path
+Display remote directory listing of either
+.Ar path
+or current directory if
+.Ar path
+is 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 Xo Ic put
+.Op Ar flags
+.Ar local-path
+.Op Ar local-path
+.Xc
+Upload
+.Ar local-path
+and store it on the remote machine. If the remote path name is not
+specified, it is given the same name it has on the local machine. If the
+.Fl P
+flag is specified, then the file's full permission and access time are
+copied too.
+.It Ic pwd
+Display remote working directory.
+.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 symlink Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic ! Ar command
+Execute
+.Ar command
+in local shell.
+.It Ic !
+Escape to local shell.
+.It Ic ?
+Synonym for help.
+.El
+.Sh AUTHORS
+Damien Miller <djm@mindrot.org>
+.Sh SEE ALSO
+.Xr scp 1 ,
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sftp-server 8 ,
+.Xr sshd 8
+.Rs
+.%A T. Ylonen
+.%A S. Lehtinen
+.%T "SSH File Transfer Protocol"
+.%N draft-ietf-secsh-filexfer-00.txt
+.%D January 2001
+.%O work in progress material
+.Re
diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c
new file mode 100644
index 000000000000..2c57bef0207a
--- /dev/null
+++ b/crypto/openssh/sftp.c
@@ -0,0 +1,271 @@
+/*
+ * 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.15 2001/04/16 02:31:44 mouring Exp $");
+
+/* XXX: commandline mode */
+/* 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"
+
+#include "scp-common.h"
+
+int use_ssh1 = 0;
+char *ssh_program = _PATH_SSH_PROGRAM;
+char *sftp_server = NULL;
+FILE* infile;
+
+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(ssh_program, args);
+ fprintf(stderr, "exec: %s: %s\n", ssh_program, 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 = 2;
+ i = 0;
+ args = xmalloc(sizeof(*args) * nargs);
+ args[i++] = "ssh";
+ 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);
+ }
+
+ /* no subsystem if the server-spec contains a '/' */
+ if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
+ make_ssh_args("-s");
+ make_ssh_args("-oForwardX11=no");
+ make_ssh_args("-oForwardAgent=no");
+ make_ssh_args(use_ssh1 ? "-oProtocol=1" : "-oProtocol=2");
+
+ /* Otherwise finish up and return the arg array */
+ if (sftp_server != NULL)
+ make_ssh_args(sftp_server);
+ else
+ 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 [-1vC] [-b batchfile] [-osshopt=value] [user@]host[:file [file]]\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int in, out, ch, debug_level, compress_flag;
+ pid_t sshpid;
+ char *file1 = NULL;
+ char *host, *userhost, *cp, *file2;
+ LogLevel ll;
+ extern int optind;
+ extern char *optarg;
+
+ infile = stdin; /* Read from STDIN unless changed by -b */
+ debug_level = compress_flag = 0;
+
+ while ((ch = getopt(argc, argv, "1hvCo:s:S:b:")) != -1) {
+ switch (ch) {
+ case 'C':
+ compress_flag = 1;
+ break;
+ case 'v':
+ debug_level = MIN(3, debug_level + 1);
+ break;
+ case 'o':
+ make_ssh_args("-o");
+ make_ssh_args(optarg);
+ break;
+ case '1':
+ use_ssh1 = 1;
+ if (sftp_server == NULL)
+ sftp_server = _PATH_SFTP_SERVER;
+ break;
+ case 's':
+ sftp_server = optarg;
+ break;
+ case 'S':
+ ssh_program = optarg;
+ break;
+ case 'b':
+ if (infile == stdin) {
+ infile = fopen(optarg, "r");
+ if (infile == NULL)
+ fatal("%s (%s).", strerror(errno), optarg);
+ } else
+ fatal("Filename already specified.");
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ if (optind == argc || argc > (optind + 2))
+ usage();
+
+ userhost = xstrdup(argv[optind]);
+ file2 = argv[optind+1];
+
+ if ((cp = colon(userhost)) != NULL) {
+ *cp++ = '\0';
+ file1 = cp;
+ }
+
+ if ((host = strchr(userhost, '@')) == NULL)
+ host = userhost;
+ else {
+ *host++ = '\0';
+ if (!userhost[0]) {
+ fprintf(stderr, "Missing username\n");
+ usage();
+ }
+ make_ssh_args("-l");
+ make_ssh_args(userhost);
+ }
+
+ host = cleanhostname(host);
+ if (!*host) {
+ 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(host);
+
+ fprintf(stderr, "Connecting to %s...\n", host);
+
+ connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid);
+
+ interactive_loop(in, out, file1, file2);
+
+ close(in);
+ close(out);
+ if (infile != stdin)
+ fclose(infile);
+
+ if (waitpid(sshpid, NULL, 0) == -1)
+ fatal("Couldn't wait for ssh process: %s", strerror(errno));
+
+ exit(0);
+}
diff --git a/crypto/openssh/sftp.h b/crypto/openssh/sftp.h
new file mode 100644
index 000000000000..2ad95864b8e0
--- /dev/null
+++ b/crypto/openssh/sftp.h
@@ -0,0 +1,91 @@
+/* $OpenBSD: sftp.h,v 1.3 2001/03/07 10:11:23 djm Exp $ */
+
+/*
+ * Copyright (c) 2001 Markus Friedl. 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.
+ */
+
+/*
+ * draft-ietf-secsh-filexfer-01.txt
+ */
+
+/* version */
+#define SSH2_FILEXFER_VERSION 3
+
+/* client to server */
+#define SSH2_FXP_INIT 1
+#define SSH2_FXP_OPEN 3
+#define SSH2_FXP_CLOSE 4
+#define SSH2_FXP_READ 5
+#define SSH2_FXP_WRITE 6
+#define SSH2_FXP_LSTAT 7
+#define SSH2_FXP_FSTAT 8
+#define SSH2_FXP_SETSTAT 9
+#define SSH2_FXP_FSETSTAT 10
+#define SSH2_FXP_OPENDIR 11
+#define SSH2_FXP_READDIR 12
+#define SSH2_FXP_REMOVE 13
+#define SSH2_FXP_MKDIR 14
+#define SSH2_FXP_RMDIR 15
+#define SSH2_FXP_REALPATH 16
+#define SSH2_FXP_STAT 17
+#define SSH2_FXP_RENAME 18
+#define SSH2_FXP_READLINK 19
+#define SSH2_FXP_SYMLINK 20
+
+/* server to client */
+#define SSH2_FXP_VERSION 2
+#define SSH2_FXP_STATUS 101
+#define SSH2_FXP_HANDLE 102
+#define SSH2_FXP_DATA 103
+#define SSH2_FXP_NAME 104
+#define SSH2_FXP_ATTRS 105
+
+#define SSH2_FXP_EXTENDED 200
+#define SSH2_FXP_EXTENDED_REPLY 201
+
+/* attributes */
+#define SSH2_FILEXFER_ATTR_SIZE 0x00000001
+#define SSH2_FILEXFER_ATTR_UIDGID 0x00000002
+#define SSH2_FILEXFER_ATTR_PERMISSIONS 0x00000004
+#define SSH2_FILEXFER_ATTR_ACMODTIME 0x00000008
+#define SSH2_FILEXFER_ATTR_EXTENDED 0x80000000
+
+/* portable open modes */
+#define SSH2_FXF_READ 0x00000001
+#define SSH2_FXF_WRITE 0x00000002
+#define SSH2_FXF_APPEND 0x00000004
+#define SSH2_FXF_CREAT 0x00000008
+#define SSH2_FXF_TRUNC 0x00000010
+#define SSH2_FXF_EXCL 0x00000020
+
+/* status messages */
+#define SSH2_FX_OK 0
+#define SSH2_FX_EOF 1
+#define SSH2_FX_NO_SUCH_FILE 2
+#define SSH2_FX_PERMISSION_DENIED 3
+#define SSH2_FX_FAILURE 4
+#define SSH2_FX_BAD_MESSAGE 5
+#define SSH2_FX_NO_CONNECTION 6
+#define SSH2_FX_CONNECTION_LOST 7
+#define SSH2_FX_OP_UNSUPPORTED 8
+#define SSH2_FX_MAX 8
diff --git a/crypto/openssh/ssh-dss.c b/crypto/openssh/ssh-dss.c
new file mode 100644
index 000000000000..adc8f983e092
--- /dev/null
+++ b/crypto/openssh/ssh-dss.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2000 Markus Friedl. 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: ssh-dss.c,v 1.6 2001/02/08 19:30:52 itojun Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "compat.h"
+#include "log.h"
+#include "key.h"
+#include "ssh-dss.h"
+
+#define INTBLOB_LEN 20
+#define SIGBLOB_LEN (2*INTBLOB_LEN)
+
+int
+ssh_dss_sign(
+ Key *key,
+ u_char **sigp, int *lenp,
+ u_char *data, int datalen)
+{
+ u_char *digest;
+ u_char *ret;
+ DSA_SIG *sig;
+ EVP_MD *evp_md = EVP_sha1();
+ EVP_MD_CTX md;
+ u_int rlen;
+ u_int slen;
+ u_int len, dlen;
+ u_char sigblob[SIGBLOB_LEN];
+ Buffer b;
+
+ if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
+ error("ssh_dss_sign: no DSA key");
+ return -1;
+ }
+ dlen = evp_md->md_size;
+ digest = xmalloc(dlen);
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, data, datalen);
+ EVP_DigestFinal(&md, digest, NULL);
+
+ sig = DSA_do_sign(digest, dlen, key->dsa);
+ if (sig == NULL) {
+ fatal("ssh_dss_sign: cannot sign");
+ }
+ memset(digest, 0, dlen);
+ xfree(digest);
+
+ rlen = BN_num_bytes(sig->r);
+ slen = BN_num_bytes(sig->s);
+ if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
+ error("bad sig size %d %d", rlen, slen);
+ DSA_SIG_free(sig);
+ return -1;
+ }
+ debug("sig size %d %d", rlen, slen);
+
+ memset(sigblob, 0, SIGBLOB_LEN);
+ BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
+ BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
+ DSA_SIG_free(sig);
+
+ if (datafellows & SSH_BUG_SIGBLOB) {
+ debug("datafellows");
+ ret = xmalloc(SIGBLOB_LEN);
+ memcpy(ret, sigblob, SIGBLOB_LEN);
+ if (lenp != NULL)
+ *lenp = SIGBLOB_LEN;
+ if (sigp != NULL)
+ *sigp = ret;
+ } else {
+ /* ietf-drafts */
+ buffer_init(&b);
+ buffer_put_cstring(&b, "ssh-dss");
+ buffer_put_string(&b, sigblob, SIGBLOB_LEN);
+ len = buffer_len(&b);
+ ret = xmalloc(len);
+ memcpy(ret, buffer_ptr(&b), len);
+ buffer_free(&b);
+ if (lenp != NULL)
+ *lenp = len;
+ if (sigp != NULL)
+ *sigp = ret;
+ }
+ return 0;
+}
+int
+ssh_dss_verify(
+ Key *key,
+ u_char *signature, int signaturelen,
+ u_char *data, int datalen)
+{
+ Buffer b;
+ u_char *digest;
+ DSA_SIG *sig;
+ EVP_MD *evp_md = EVP_sha1();
+ EVP_MD_CTX md;
+ u_char *sigblob;
+ char *txt;
+ u_int len, dlen;
+ int rlen;
+ int ret;
+
+ if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
+ error("ssh_dss_verify: no DSA key");
+ return -1;
+ }
+
+ if (!(datafellows & SSH_BUG_SIGBLOB) &&
+ signaturelen == SIGBLOB_LEN) {
+ datafellows |= ~SSH_BUG_SIGBLOB;
+ log("autodetect SSH_BUG_SIGBLOB");
+ } else if ((datafellows & SSH_BUG_SIGBLOB) &&
+ signaturelen != SIGBLOB_LEN) {
+ log("autoremove SSH_BUG_SIGBLOB");
+ datafellows &= ~SSH_BUG_SIGBLOB;
+ }
+
+ debug("len %d datafellows %d", signaturelen, datafellows);
+
+ /* fetch signature */
+ if (datafellows & SSH_BUG_SIGBLOB) {
+ sigblob = signature;
+ len = signaturelen;
+ } else {
+ /* ietf-drafts */
+ char *ktype;
+ buffer_init(&b);
+ buffer_append(&b, (char *) signature, signaturelen);
+ ktype = buffer_get_string(&b, NULL);
+ if (strcmp("ssh-dss", ktype) != 0) {
+ error("ssh_dss_verify: cannot handle type %s", ktype);
+ buffer_free(&b);
+ return -1;
+ }
+ sigblob = (u_char *)buffer_get_string(&b, &len);
+ rlen = buffer_len(&b);
+ if(rlen != 0) {
+ error("remaining bytes in signature %d", rlen);
+ buffer_free(&b);
+ return -1;
+ }
+ buffer_free(&b);
+ xfree(ktype);
+ }
+
+ if (len != SIGBLOB_LEN) {
+ fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
+ }
+
+ /* parse signature */
+ sig = DSA_SIG_new();
+ sig->r = BN_new();
+ sig->s = BN_new();
+ BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
+ BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
+
+ if (!(datafellows & SSH_BUG_SIGBLOB)) {
+ memset(sigblob, 0, len);
+ xfree(sigblob);
+ }
+
+ /* sha1 the data */
+ dlen = evp_md->md_size;
+ digest = xmalloc(dlen);
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, data, datalen);
+ EVP_DigestFinal(&md, digest, NULL);
+
+ ret = DSA_do_verify(digest, dlen, sig, key->dsa);
+
+ memset(digest, 0, dlen);
+ xfree(digest);
+ DSA_SIG_free(sig);
+
+ switch (ret) {
+ case 1:
+ txt = "correct";
+ break;
+ case 0:
+ txt = "incorrect";
+ break;
+ case -1:
+ default:
+ txt = "error";
+ break;
+ }
+ debug("ssh_dss_verify: signature %s", txt);
+ return ret;
+}
diff --git a/crypto/openssh/ssh-dss.h b/crypto/openssh/ssh-dss.h
new file mode 100644
index 000000000000..0e6a20a59d92
--- /dev/null
+++ b/crypto/openssh/ssh-dss.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: ssh-dss.h,v 1.3 2001/01/29 01:58:18 niklas Exp $ */
+
+/*
+ * Copyright (c) 2000 Markus Friedl. 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.
+ */
+#ifndef DSA_H
+#define DSA_H
+
+int
+ssh_dss_sign(
+ Key *key,
+ u_char **sigp, int *lenp,
+ u_char *data, int datalen);
+
+int
+ssh_dss_verify(
+ Key *key,
+ u_char *signature, int signaturelen,
+ u_char *data, int datalen);
+
+#endif
diff --git a/crypto/openssh/ssh-keyscan.1 b/crypto/openssh/ssh-keyscan.1
new file mode 100644
index 000000000000..4db8c5f15f9d
--- /dev/null
+++ b/crypto/openssh/ssh-keyscan.1
@@ -0,0 +1,104 @@
+.\" $OpenBSD: ssh-keyscan.1,v 1.5 2001/04/18 16:21:05 ian Exp $
+.\"
+.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
+.\"
+.\" Modification and redistribution in source and binary forms is
+.\" permitted provided that due credit is given to the author and the
+.\" OpenBSD project (for instance by leaving this copyright notice
+.\" intact).
+.\"
+.Dd January 1, 1996
+.Dt SSH-KEYSCAN 1
+.Os
+.Sh NAME
+.Nm ssh-keyscan
+.Nd gather ssh public keys
+.Sh SYNOPSIS
+.Nm ssh-keyscan
+.Op Fl t Ar timeout
+.Op Ar -- | host | addrlist namelist
+.Op Fl f Ar files ...
+.Sh DESCRIPTION
+.Nm
+is a utility for gathering the public ssh host keys of a number of
+hosts. It was designed to aid in building and verifying
+.Pa ssh_known_hosts
+files.
+.Nm
+provides a minimal interface suitable for use by shell and perl
+scripts.
+.Pp
+.Nm
+uses non-blocking socket I/O to contact as many hosts as possible in
+parallel, so it is very efficient. The keys from a domain of 1,000
+hosts can be collected in tens of seconds, even when some of those
+hosts are down or do not run ssh. You do not need login access to the
+machines you are scanning, nor does the scanning process involve
+any encryption.
+.Sh SECURITY
+If you make an ssh_known_hosts file using
+.Nm
+without verifying the keys, you will be vulnerable to
+.I man in the middle
+attacks.
+On the other hand, if your security model allows such a risk,
+.Nm
+can help you detect tampered keyfiles or man in the middle attacks which
+have begun after you created your ssh_known_hosts file.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl t
+Set the timeout for connection attempts. If
+.Pa timeout
+seconds have elapsed since a connection was initiated to a host or since the
+last time anything was read from that host, then the connection is
+closed and the host in question considered unavailable. Default is 5
+seconds.
+.It Fl f
+Read hosts or
+.Pa addrlist namelist
+pairs from this file, one per line.
+If
+.Pa -
+is supplied instead of a filename,
+.Nm
+will read hosts or
+.Pa addrlist namelist
+pairs from the standard input.
+.El
+.Sh EXAMPLES
+.Pp
+Print the host key for machine
+.Pa hostname :
+.Bd -literal
+ssh-keyscan hostname
+.Ed
+.Pp
+Find all hosts from the file
+.Pa ssh_hosts
+which have new or different keys from those in the sorted file
+.Pa ssh_known_hosts :
+.Bd -literal
+$ ssh-keyscan -f ssh_hosts | sort -u - ssh_known_hosts | \e\
+ diff ssh_known_hosts -
+.Ed
+.Pp
+.Sh FILES
+.Pp
+.Pa Input format:
+1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
+.Pp
+.Pa Output format:
+host-or-namelist bits exponent modulus
+.Pp
+.Pa /etc/ssh_known_hosts
+.Sh BUGS
+It generates "Connection closed by remote host" messages on the consoles
+of all the machines it scans.
+This is because it opens a connection to the ssh port, reads the public
+key, and drops the connection as soon as it gets the key.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr sshd 8
+.Sh AUTHOR
+David Mazieres <dm@lcs.mit.edu>
diff --git a/crypto/openssh/ssh-keyscan.c b/crypto/openssh/ssh-keyscan.c
new file mode 100644
index 000000000000..dba2d838e579
--- /dev/null
+++ b/crypto/openssh/ssh-keyscan.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
+ *
+ * Modification and redistribution in source and binary forms is
+ * permitted provided that due credit is given to the author and the
+ * OpenBSD project (for instance by leaving this copyright notice
+ * intact).
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-keyscan.c,v 1.22 2001/03/06 06:11:18 deraadt Exp $");
+
+#include <sys/queue.h>
+#include <errno.h>
+
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "key.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "log.h"
+#include "atomicio.h"
+
+static int argno = 1; /* Number of argument currently being parsed */
+
+int family = AF_UNSPEC; /* IPv4, IPv6 or both */
+
+#define MAXMAXFD 256
+
+/* The number of seconds after which to give up on a TCP connection */
+int timeout = 5;
+
+int maxfd;
+#define MAXCON (maxfd - 10)
+
+extern char *__progname;
+fd_set *read_wait;
+size_t read_wait_size;
+int ncon;
+
+/*
+ * Keep a connection structure for each file descriptor. The state
+ * associated with file descriptor n is held in fdcon[n].
+ */
+typedef struct Connection {
+ u_char c_status; /* State of connection on this file desc. */
+#define CS_UNUSED 0 /* File descriptor unused */
+#define CS_CON 1 /* Waiting to connect/read greeting */
+#define CS_SIZE 2 /* Waiting to read initial packet size */
+#define CS_KEYS 3 /* Waiting to read public key packet */
+ int c_fd; /* Quick lookup: c->c_fd == c - fdcon */
+ int c_plen; /* Packet length field for ssh packet */
+ int c_len; /* Total bytes which must be read. */
+ int c_off; /* Length of data read so far. */
+ char *c_namebase; /* Address to free for c_name and c_namelist */
+ char *c_name; /* Hostname of connection for errors */
+ char *c_namelist; /* Pointer to other possible addresses */
+ char *c_output_name; /* Hostname of connection for output */
+ char *c_data; /* Data read from this fd */
+ struct timeval c_tv; /* Time at which connection gets aborted */
+ TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
+} con;
+
+TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */
+con *fdcon;
+
+/*
+ * This is just a wrapper around fgets() to make it usable.
+ */
+
+/* Stress-test. Increase this later. */
+#define LINEBUF_SIZE 16
+
+typedef struct {
+ char *buf;
+ u_int size;
+ int lineno;
+ const char *filename;
+ FILE *stream;
+ void (*errfun) (const char *,...);
+} Linebuf;
+
+Linebuf *
+Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
+{
+ Linebuf *lb;
+
+ if (!(lb = malloc(sizeof(*lb)))) {
+ if (errfun)
+ (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
+ return (NULL);
+ }
+ if (filename) {
+ lb->filename = filename;
+ if (!(lb->stream = fopen(filename, "r"))) {
+ xfree(lb);
+ if (errfun)
+ (*errfun) ("%s: %s\n", filename, strerror(errno));
+ return (NULL);
+ }
+ } else {
+ lb->filename = "(stdin)";
+ lb->stream = stdin;
+ }
+
+ if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) {
+ if (errfun)
+ (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
+ xfree(lb);
+ return (NULL);
+ }
+ lb->errfun = errfun;
+ lb->lineno = 0;
+ return (lb);
+}
+
+void
+Linebuf_free(Linebuf * lb)
+{
+ fclose(lb->stream);
+ xfree(lb->buf);
+ xfree(lb);
+}
+
+void
+Linebuf_restart(Linebuf * lb)
+{
+ clearerr(lb->stream);
+ rewind(lb->stream);
+ lb->lineno = 0;
+}
+
+int
+Linebuf_lineno(Linebuf * lb)
+{
+ return (lb->lineno);
+}
+
+char *
+Linebuf_getline(Linebuf * lb)
+{
+ int n = 0;
+
+ lb->lineno++;
+ for (;;) {
+ /* Read a line */
+ if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
+ if (ferror(lb->stream) && lb->errfun)
+ (*lb->errfun) ("%s: %s\n", lb->filename,
+ strerror(errno));
+ return (NULL);
+ }
+ n = strlen(lb->buf);
+
+ /* Return it or an error if it fits */
+ if (n > 0 && lb->buf[n - 1] == '\n') {
+ lb->buf[n - 1] = '\0';
+ return (lb->buf);
+ }
+ if (n != lb->size - 1) {
+ if (lb->errfun)
+ (*lb->errfun) ("%s: skipping incomplete last line\n",
+ lb->filename);
+ return (NULL);
+ }
+ /* Double the buffer if we need more space */
+ if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) {
+ if (lb->errfun)
+ (*lb->errfun) ("linebuf (%s): realloc failed\n",
+ lb->filename);
+ return (NULL);
+ }
+ }
+}
+
+int
+fdlim_get(int hard)
+{
+ struct rlimit rlfd;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
+ return (-1);
+ if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
+ return 10000;
+ else
+ return hard ? rlfd.rlim_max : rlfd.rlim_cur;
+}
+
+int
+fdlim_set(int lim)
+{
+ struct rlimit rlfd;
+ if (lim <= 0)
+ return (-1);
+ if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
+ return (-1);
+ rlfd.rlim_cur = lim;
+ if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * This is an strsep function that returns a null field for adjacent
+ * separators. This is the same as the 4.4BSD strsep, but different from the
+ * one in the GNU libc.
+ */
+char *
+xstrsep(char **str, const char *delim)
+{
+ char *s, *e;
+
+ if (!**str)
+ return (NULL);
+
+ s = *str;
+ e = s + strcspn(s, delim);
+
+ if (*e != '\0')
+ *e++ = '\0';
+ *str = e;
+
+ return (s);
+}
+
+/*
+ * Get the next non-null token (like GNU strsep). Strsep() will return a
+ * null token for two adjacent separators, so we may have to loop.
+ */
+char *
+strnnsep(char **stringp, char *delim)
+{
+ char *tok;
+
+ do {
+ tok = xstrsep(stringp, delim);
+ } while (tok && *tok == '\0');
+ return (tok);
+}
+
+void
+keyprint(char *host, char *output_name, char *kd, int len)
+{
+ static Key *rsa;
+ static Buffer msg;
+
+ if (rsa == NULL) {
+ buffer_init(&msg);
+ rsa = key_new(KEY_RSA1);
+ }
+ buffer_append(&msg, kd, len);
+ buffer_consume(&msg, 8 - (len & 7)); /* padding */
+ if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
+ error("%s: invalid packet type", host);
+ buffer_clear(&msg);
+ return;
+ }
+ buffer_consume(&msg, 8); /* cookie */
+
+ /* server key */
+ (void) buffer_get_int(&msg);
+ buffer_get_bignum(&msg, rsa->rsa->e);
+ buffer_get_bignum(&msg, rsa->rsa->n);
+
+ /* host key */
+ (void) buffer_get_int(&msg);
+ buffer_get_bignum(&msg, rsa->rsa->e);
+ buffer_get_bignum(&msg, rsa->rsa->n);
+ buffer_clear(&msg);
+
+ fprintf(stdout, "%s ", output_name ? output_name : host);
+ key_write(rsa, stdout);
+ fputs("\n", stdout);
+}
+
+int
+tcpconnect(char *host)
+{
+ struct addrinfo hints, *ai, *aitop;
+ char strport[NI_MAXSERV];
+ int gaierr, s = -1;
+
+ snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
+ fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
+ for (ai = aitop; ai; ai = ai->ai_next) {
+ s = socket(ai->ai_family, SOCK_STREAM, 0);
+ if (s < 0) {
+ error("socket: %s", strerror(errno));
+ continue;
+ }
+ if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
+ fatal("F_SETFL: %s", strerror(errno));
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
+ errno != EINPROGRESS)
+ error("connect (`%s'): %s", host, strerror(errno));
+ else
+ break;
+ close(s);
+ s = -1;
+ }
+ freeaddrinfo(aitop);
+ return s;
+}
+
+int
+conalloc(char *iname, char *oname)
+{
+ int s;
+ char *namebase, *name, *namelist;
+
+ namebase = namelist = xstrdup(iname);
+
+ do {
+ name = xstrsep(&namelist, ",");
+ if (!name) {
+ xfree(namebase);
+ return (-1);
+ }
+ } while ((s = tcpconnect(name)) < 0);
+
+ if (s >= maxfd)
+ fatal("conalloc: fdno %d too high", s);
+ if (fdcon[s].c_status)
+ fatal("conalloc: attempt to reuse fdno %d", s);
+
+ fdcon[s].c_fd = s;
+ fdcon[s].c_status = CS_CON;
+ fdcon[s].c_namebase = namebase;
+ fdcon[s].c_name = name;
+ fdcon[s].c_namelist = namelist;
+ fdcon[s].c_output_name = xstrdup(oname);
+ fdcon[s].c_data = (char *) &fdcon[s].c_plen;
+ fdcon[s].c_len = 4;
+ fdcon[s].c_off = 0;
+ gettimeofday(&fdcon[s].c_tv, NULL);
+ fdcon[s].c_tv.tv_sec += timeout;
+ TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
+ FD_SET(s, read_wait);
+ ncon++;
+ return (s);
+}
+
+void
+confree(int s)
+{
+ if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
+ fatal("confree: attempt to free bad fdno %d", s);
+ close(s);
+ xfree(fdcon[s].c_namebase);
+ xfree(fdcon[s].c_output_name);
+ if (fdcon[s].c_status == CS_KEYS)
+ xfree(fdcon[s].c_data);
+ fdcon[s].c_status = CS_UNUSED;
+ TAILQ_REMOVE(&tq, &fdcon[s], c_link);
+ FD_CLR(s, read_wait);
+ ncon--;
+}
+
+void
+contouch(int s)
+{
+ TAILQ_REMOVE(&tq, &fdcon[s], c_link);
+ gettimeofday(&fdcon[s].c_tv, NULL);
+ fdcon[s].c_tv.tv_sec += timeout;
+ TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
+}
+
+int
+conrecycle(int s)
+{
+ int ret;
+ con *c = &fdcon[s];
+ char *iname, *oname;
+
+ iname = xstrdup(c->c_namelist);
+ oname = xstrdup(c->c_output_name);
+ confree(s);
+ ret = conalloc(iname, oname);
+ xfree(iname);
+ xfree(oname);
+ return (ret);
+}
+
+void
+congreet(int s)
+{
+ char buf[80], *cp;
+ size_t bufsiz;
+ int n = 0;
+ con *c = &fdcon[s];
+
+ bufsiz = sizeof(buf);
+ cp = buf;
+ while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n' && *cp != '\r')
+ cp++;
+ if (n < 0) {
+ if (errno != ECONNREFUSED)
+ error("read (%s): %s", c->c_name, strerror(errno));
+ conrecycle(s);
+ return;
+ }
+ if (*cp != '\n' && *cp != '\r') {
+ error("%s: bad greeting", c->c_name);
+ confree(s);
+ return;
+ }
+ *cp = '\0';
+ fprintf(stderr, "# %s %s\n", c->c_name, buf);
+ n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n");
+ if (atomicio(write, s, buf, n) != n) {
+ error("write (%s): %s", c->c_name, strerror(errno));
+ confree(s);
+ return;
+ }
+ c->c_status = CS_SIZE;
+ contouch(s);
+}
+
+void
+conread(int s)
+{
+ int n;
+ con *c = &fdcon[s];
+
+ if (c->c_status == CS_CON) {
+ congreet(s);
+ return;
+ }
+ n = read(s, c->c_data + c->c_off, c->c_len - c->c_off);
+ if (n < 0) {
+ error("read (%s): %s", c->c_name, strerror(errno));
+ confree(s);
+ return;
+ }
+ c->c_off += n;
+
+ if (c->c_off == c->c_len)
+ switch (c->c_status) {
+ case CS_SIZE:
+ c->c_plen = htonl(c->c_plen);
+ c->c_len = c->c_plen + 8 - (c->c_plen & 7);
+ c->c_off = 0;
+ c->c_data = xmalloc(c->c_len);
+ c->c_status = CS_KEYS;
+ break;
+ case CS_KEYS:
+ keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen);
+ confree(s);
+ return;
+ break;
+ default:
+ fatal("conread: invalid status %d", c->c_status);
+ break;
+ }
+
+ contouch(s);
+}
+
+void
+conloop(void)
+{
+ fd_set *r, *e;
+ struct timeval seltime, now;
+ int i;
+ con *c;
+
+ gettimeofday(&now, NULL);
+ c = tq.tqh_first;
+
+ if (c && (c->c_tv.tv_sec > now.tv_sec ||
+ (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
+ seltime = c->c_tv;
+ seltime.tv_sec -= now.tv_sec;
+ seltime.tv_usec -= now.tv_usec;
+ if (seltime.tv_usec < 0) {
+ seltime.tv_usec += 1000000;
+ seltime.tv_sec--;
+ }
+ } else
+ seltime.tv_sec = seltime.tv_usec = 0;
+
+ r = xmalloc(read_wait_size);
+ memcpy(r, read_wait, read_wait_size);
+ e = xmalloc(read_wait_size);
+ memcpy(e, read_wait, read_wait_size);
+
+ while (select(maxfd, r, NULL, e, &seltime) == -1 &&
+ (errno == EAGAIN || errno == EINTR))
+ ;
+
+ for (i = 0; i < maxfd; i++) {
+ if (FD_ISSET(i, e)) {
+ error("%s: exception!", fdcon[i].c_name);
+ confree(i);
+ } else if (FD_ISSET(i, r))
+ conread(i);
+ }
+ xfree(r);
+ xfree(e);
+
+ c = tq.tqh_first;
+ while (c && (c->c_tv.tv_sec < now.tv_sec ||
+ (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
+ int s = c->c_fd;
+
+ c = c->c_link.tqe_next;
+ conrecycle(s);
+ }
+}
+
+char *
+nexthost(int argc, char **argv)
+{
+ static Linebuf *lb;
+
+ for (;;) {
+ if (!lb) {
+ if (argno >= argc)
+ return (NULL);
+ if (argv[argno][0] != '-')
+ return (argv[argno++]);
+ if (!strcmp(argv[argno], "--")) {
+ if (++argno >= argc)
+ return (NULL);
+ return (argv[argno++]);
+ } else if (!strncmp(argv[argno], "-f", 2)) {
+ char *fname;
+
+ if (argv[argno][2])
+ fname = &argv[argno++][2];
+ else if (++argno >= argc) {
+ error("missing filename for `-f'");
+ return (NULL);
+ } else
+ fname = argv[argno++];
+ if (!strcmp(fname, "-"))
+ fname = NULL;
+ lb = Linebuf_alloc(fname, error);
+ } else
+ error("ignoring invalid/misplaced option `%s'",
+ argv[argno++]);
+ } else {
+ char *line;
+
+ line = Linebuf_getline(lb);
+ if (line)
+ return (line);
+ Linebuf_free(lb);
+ lb = NULL;
+ }
+ }
+}
+
+void
+usage(void)
+{
+ fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname);
+ return;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *host = NULL;
+
+ TAILQ_INIT(&tq);
+
+ if (argc <= argno)
+ usage();
+
+ if (argv[1][0] == '-' && argv[1][1] == 't') {
+ argno++;
+ if (argv[1][2])
+ timeout = atoi(&argv[1][2]);
+ else {
+ if (argno >= argc)
+ usage();
+ timeout = atoi(argv[argno++]);
+ }
+ if (timeout <= 0)
+ usage();
+ }
+ if (argc <= argno)
+ usage();
+
+ maxfd = fdlim_get(1);
+ if (maxfd < 0)
+ fatal("%s: fdlim_get: bad value", __progname);
+ if (maxfd > MAXMAXFD)
+ maxfd = MAXMAXFD;
+ if (MAXCON <= 0)
+ fatal("%s: not enough file descriptors", __progname);
+ if (maxfd > fdlim_get(0))
+ fdlim_set(maxfd);
+ fdcon = xmalloc(maxfd * sizeof(con));
+ memset(fdcon, 0, maxfd * sizeof(con));
+
+ read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+ read_wait = xmalloc(read_wait_size);
+ memset(read_wait, 0, read_wait_size);
+
+ do {
+ while (ncon < MAXCON) {
+ char *name;
+
+ host = nexthost(argc, argv);
+ if (host == NULL)
+ break;
+ name = strnnsep(&host, " \t\n");
+ conalloc(name, *host ? host : name);
+ }
+ conloop();
+ } while (host);
+ while (ncon > 0)
+ conloop();
+
+ return (0);
+}
diff --git a/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c
new file mode 100644
index 000000000000..b502ddb6e0dc
--- /dev/null
+++ b/crypto/openssh/ssh-rsa.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2000 Markus Friedl. 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: ssh-rsa.c,v 1.8 2001/03/27 10:57:00 markus Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+#include "xmalloc.h"
+#include "log.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "ssh-rsa.h"
+#include "compat.h"
+
+/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
+int
+ssh_rsa_sign(
+ Key *key,
+ u_char **sigp, int *lenp,
+ u_char *data, int datalen)
+{
+ const EVP_MD *evp_md;
+ EVP_MD_CTX md;
+ u_char *digest, *sig, *ret;
+ u_int slen, dlen, len;
+ int ok, nid;
+ Buffer b;
+
+ if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
+ error("ssh_rsa_sign: no RSA key");
+ return -1;
+ }
+ nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+ if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
+ error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
+ return -1;
+ }
+ dlen = evp_md->md_size;
+ digest = xmalloc(dlen);
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, data, datalen);
+ EVP_DigestFinal(&md, digest, NULL);
+
+ slen = RSA_size(key->rsa);
+ sig = xmalloc(slen);
+
+ ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
+ memset(digest, 'd', dlen);
+ xfree(digest);
+
+ if (ok != 1) {
+ int ecode = ERR_get_error();
+ error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL));
+ xfree(sig);
+ return -1;
+ }
+ if (len < slen) {
+ int diff = slen - len;
+ debug("slen %d > len %d", slen, len);
+ memmove(sig + diff, sig, len);
+ memset(sig, 0, diff);
+ } else if (len > slen) {
+ error("ssh_rsa_sign: slen %d slen2 %d", slen, len);
+ xfree(sig);
+ return -1;
+ }
+ /* encode signature */
+ buffer_init(&b);
+ buffer_put_cstring(&b, "ssh-rsa");
+ buffer_put_string(&b, sig, slen);
+ len = buffer_len(&b);
+ ret = xmalloc(len);
+ memcpy(ret, buffer_ptr(&b), len);
+ buffer_free(&b);
+ memset(sig, 's', slen);
+ xfree(sig);
+
+ if (lenp != NULL)
+ *lenp = len;
+ if (sigp != NULL)
+ *sigp = ret;
+ debug2("ssh_rsa_sign: done");
+ return 0;
+}
+
+int
+ssh_rsa_verify(
+ Key *key,
+ u_char *signature, int signaturelen,
+ u_char *data, int datalen)
+{
+ Buffer b;
+ const EVP_MD *evp_md;
+ EVP_MD_CTX md;
+ char *ktype;
+ u_char *sigblob, *digest;
+ u_int len, dlen;
+ int rlen, ret, nid;
+
+ if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
+ error("ssh_rsa_verify: no RSA key");
+ return -1;
+ }
+ if (BN_num_bits(key->rsa->n) < 768) {
+ error("ssh_rsa_verify: n too small: %d bits",
+ BN_num_bits(key->rsa->n));
+ return -1;
+ }
+ buffer_init(&b);
+ buffer_append(&b, (char *) signature, signaturelen);
+ ktype = buffer_get_string(&b, NULL);
+ if (strcmp("ssh-rsa", ktype) != 0) {
+ error("ssh_rsa_verify: cannot handle type %s", ktype);
+ buffer_free(&b);
+ xfree(ktype);
+ return -1;
+ }
+ xfree(ktype);
+ sigblob = (u_char *)buffer_get_string(&b, &len);
+ rlen = buffer_len(&b);
+ buffer_free(&b);
+ if(rlen != 0) {
+ xfree(sigblob);
+ error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
+ return -1;
+ }
+ nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+ if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
+ xfree(sigblob);
+ error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
+ return -1;
+ }
+ dlen = evp_md->md_size;
+ digest = xmalloc(dlen);
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, data, datalen);
+ EVP_DigestFinal(&md, digest, NULL);
+
+ ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
+ memset(digest, 'd', dlen);
+ xfree(digest);
+ memset(sigblob, 's', len);
+ xfree(sigblob);
+ if (ret == 0) {
+ int ecode = ERR_get_error();
+ error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL));
+ }
+ debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
+ return ret;
+}
diff --git a/crypto/openssh/ssh-rsa.h b/crypto/openssh/ssh-rsa.h
new file mode 100644
index 000000000000..af2b2fe281b6
--- /dev/null
+++ b/crypto/openssh/ssh-rsa.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: ssh-rsa.h,v 1.3 2001/01/29 01:58:18 niklas Exp $ */
+
+/*
+ * Copyright (c) 2000 Markus Friedl. 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.
+ */
+#ifndef SSH_RSA_H
+#define SSH_RSA_H
+
+int
+ssh_rsa_sign(
+ Key *key,
+ u_char **sigp, int *lenp,
+ u_char *data, int datalen);
+
+int
+ssh_rsa_verify(
+ Key *key,
+ u_char *signature, int signaturelen,
+ u_char *data, int datalen);
+
+#endif
diff --git a/crypto/openssh/ssh1.h b/crypto/openssh/ssh1.h
new file mode 100644
index 000000000000..770c5e4b021b
--- /dev/null
+++ b/crypto/openssh/ssh1.h
@@ -0,0 +1,86 @@
+/* $OpenBSD: ssh1.h,v 1.2 2001/01/29 01:58:18 niklas Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * Definition of message types. New values can be added, but old values
+ * should not be removed or without careful consideration of the consequences
+ * for compatibility. The maximum value is 254; value 255 is reserved for
+ * future extension.
+ */
+/* Message name */ /* msg code */ /* arguments */
+#define SSH_MSG_NONE 0 /* no message */
+#define SSH_MSG_DISCONNECT 1 /* cause (string) */
+#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
+#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
+#define SSH_CMSG_USER 4 /* user (string) */
+#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
+#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
+#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
+#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
+#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
+#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
+#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
+#define SSH_CMSG_EXEC_SHELL 12 /* */
+#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
+#define SSH_SMSG_SUCCESS 14 /* */
+#define SSH_SMSG_FAILURE 15 /* */
+#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
+#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
+#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
+#define SSH_CMSG_EOF 19 /* */
+#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
+#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
+#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
+#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
+#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
+#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
+/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
+#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
+#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
+#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
+#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
+#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
+#define SSH_MSG_IGNORE 32 /* string */
+#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
+#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
+#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
+#define SSH_MSG_DEBUG 36 /* string */
+#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
+#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
+#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
+#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
+#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
+#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
+#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
+#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
+#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
+
+/*
+ * Authentication methods. New types can be added, but old types should not
+ * be removed for compatibility. The maximum allowed value is 31.
+ */
+#define SSH_AUTH_RHOSTS 1
+#define SSH_AUTH_RSA 2
+#define SSH_AUTH_PASSWORD 3
+#define SSH_AUTH_RHOSTS_RSA 4
+#define SSH_AUTH_TIS 5
+#define SSH_AUTH_KERBEROS 6
+#define SSH_PASS_KERBEROS_TGT 7
+ /* 8 to 15 are reserved */
+#define SSH_PASS_AFS_TOKEN 21
+
+/* Protocol flags. These are bit masks. */
+#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
+#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
+
diff --git a/crypto/openssh/sshlogin.h b/crypto/openssh/sshlogin.h
new file mode 100644
index 000000000000..7285bc23e60a
--- /dev/null
+++ b/crypto/openssh/sshlogin.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: sshlogin.h,v 1.1 2001/03/04 01:46:30 djm Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+#ifndef SSHLOGIN_H
+#define SSHLOGIN_H
+
+/*
+ * Returns the time when the user last logged in. Returns 0 if the
+ * information is not available. This must be called before record_login.
+ * The host from which the user logged in is stored in buf.
+ */
+u_long
+get_last_login_time(uid_t uid, const char *logname,
+ char *buf, u_int bufsize);
+
+/*
+ * Records that the user has logged in. This does many things normally done
+ * by login(1).
+ */
+void
+record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
+ const char *host, struct sockaddr *addr);
+
+/*
+ * Records that the user has logged out. This does many thigs normally done
+ * by login(1) or init.
+ */
+void record_logout(pid_t pid, const char *ttyname);
+
+#endif
diff --git a/crypto/openssh/sshpty.c b/crypto/openssh/sshpty.c
new file mode 100644
index 000000000000..1544ac66ac8c
--- /dev/null
+++ b/crypto/openssh/sshpty.c
@@ -0,0 +1,298 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Allocating a pseudo-terminal, and making it the controlling tty.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshpty.c,v 1.1 2001/03/04 01:46:30 djm Exp $");
+RCSID("$FreeBSD$");
+
+#include <libutil.h>
+#include "sshpty.h"
+#include "log.h"
+
+/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
+#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
+#undef HAVE_DEV_PTMX
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+/*
+ * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
+ * nonzero if a pty was successfully allocated. On success, open file
+ * descriptors for the pty and tty sides and the name of the tty side are
+ * returned (the buffer must be able to hold at least 64 characters).
+ */
+
+int
+pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
+{
+#if defined(HAVE_OPENPTY) || defined(BSD4_4)
+ /* openpty(3) exists in OSF/1 and some other os'es */
+ char buf[64];
+ int i;
+
+ i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
+ if (i < 0) {
+ error("openpty: %.100s", strerror(errno));
+ return 0;
+ }
+ strlcpy(namebuf, buf, namebuflen); /* possible truncation */
+ return 1;
+#else /* HAVE_OPENPTY */
+#ifdef HAVE__GETPTY
+ /*
+ * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
+ * pty's automagically when needed
+ */
+ char *slave;
+
+ slave = _getpty(ptyfd, O_RDWR, 0622, 0);
+ if (slave == NULL) {
+ error("_getpty: %.100s", strerror(errno));
+ return 0;
+ }
+ strlcpy(namebuf, slave, namebuflen);
+ /* Open the slave side. */
+ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
+ if (*ttyfd < 0) {
+ error("%.200s: %.100s", namebuf, strerror(errno));
+ close(*ptyfd);
+ return 0;
+ }
+ return 1;
+#else /* HAVE__GETPTY */
+#ifdef HAVE_DEV_PTMX
+ /*
+ * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
+ * also has bsd-style ptys, but they simply do not work.)
+ */
+ int ptm;
+ char *pts;
+
+ ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+ if (ptm < 0) {
+ error("/dev/ptmx: %.100s", strerror(errno));
+ return 0;
+ }
+ if (grantpt(ptm) < 0) {
+ error("grantpt: %.100s", strerror(errno));
+ return 0;
+ }
+ if (unlockpt(ptm) < 0) {
+ error("unlockpt: %.100s", strerror(errno));
+ return 0;
+ }
+ pts = ptsname(ptm);
+ if (pts == NULL)
+ error("Slave pty side name could not be obtained.");
+ strlcpy(namebuf, pts, namebuflen);
+ *ptyfd = ptm;
+
+ /* Open the slave side. */
+ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
+ if (*ttyfd < 0) {
+ error("%.100s: %.100s", namebuf, strerror(errno));
+ close(*ptyfd);
+ return 0;
+ }
+ /* Push the appropriate streams modules, as described in Solaris pts(7). */
+ if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
+ error("ioctl I_PUSH ptem: %.100s", strerror(errno));
+ if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
+ error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
+ if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
+ error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
+ return 1;
+#else /* HAVE_DEV_PTMX */
+#ifdef HAVE_DEV_PTS_AND_PTC
+ /* AIX-style pty code. */
+ const char *name;
+
+ *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
+ if (*ptyfd < 0) {
+ error("Could not open /dev/ptc: %.100s", strerror(errno));
+ return 0;
+ }
+ name = ttyname(*ptyfd);
+ if (!name)
+ fatal("Open of /dev/ptc returns device for which ttyname fails.");
+ strlcpy(namebuf, name, namebuflen);
+ *ttyfd = open(name, O_RDWR | O_NOCTTY);
+ if (*ttyfd < 0) {
+ error("Could not open pty slave side %.100s: %.100s",
+ name, strerror(errno));
+ close(*ptyfd);
+ return 0;
+ }
+ return 1;
+#else /* HAVE_DEV_PTS_AND_PTC */
+ /* BSD-style pty code. */
+ char buf[64];
+ int i;
+ const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const char *ptyminors = "0123456789abcdef";
+ int num_minors = strlen(ptyminors);
+ int num_ptys = strlen(ptymajors) * num_minors;
+
+ for (i = 0; i < num_ptys; i++) {
+ snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
+ ptyminors[i % num_minors]);
+ *ptyfd = open(buf, O_RDWR | O_NOCTTY);
+ if (*ptyfd < 0)
+ continue;
+ snprintf(namebuf, namebuflen, "/dev/tty%c%c",
+ ptymajors[i / num_minors], ptyminors[i % num_minors]);
+
+ /* Open the slave side. */
+ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
+ if (*ttyfd < 0) {
+ error("%.100s: %.100s", namebuf, strerror(errno));
+ close(*ptyfd);
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+#endif /* HAVE_DEV_PTS_AND_PTC */
+#endif /* HAVE_DEV_PTMX */
+#endif /* HAVE__GETPTY */
+#endif /* HAVE_OPENPTY */
+}
+
+/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
+
+void
+pty_release(const char *ttyname)
+{
+ if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
+ error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
+ if (chmod(ttyname, (mode_t) 0666) < 0)
+ error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
+}
+
+/* Makes the tty the processes controlling tty and sets it to sane modes. */
+
+void
+pty_make_controlling_tty(int *ttyfd, const char *ttyname)
+{
+ int fd;
+
+ /* First disconnect from the old controlling tty. */
+#ifdef TIOCNOTTY
+ fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
+ if (fd >= 0) {
+ (void) ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+ }
+#endif /* TIOCNOTTY */
+ if (setsid() < 0)
+ error("setsid: %.100s", strerror(errno));
+
+ /*
+ * Verify that we are successfully disconnected from the controlling
+ * tty.
+ */
+ fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
+ if (fd >= 0) {
+ error("Failed to disconnect from controlling tty.");
+ close(fd);
+ }
+ /* Make it our controlling tty. */
+#ifdef TIOCSCTTY
+ debug("Setting controlling tty using TIOCSCTTY.");
+ if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
+ error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
+#endif /* TIOCSCTTY */
+ fd = open(ttyname, O_RDWR);
+ if (fd < 0)
+ error("%.100s: %.100s", ttyname, strerror(errno));
+ else
+ close(fd);
+
+ /* Verify that we now have a controlling tty. */
+ fd = open(_PATH_TTY, O_WRONLY);
+ if (fd < 0)
+ error("open /dev/tty failed - could not set controlling tty: %.100s",
+ strerror(errno));
+ else {
+ close(fd);
+ }
+}
+
+/* Changes the window size associated with the pty. */
+
+void
+pty_change_window_size(int ptyfd, int row, int col,
+ int xpixel, int ypixel)
+{
+ struct winsize w;
+ w.ws_row = row;
+ w.ws_col = col;
+ w.ws_xpixel = xpixel;
+ w.ws_ypixel = ypixel;
+ (void) ioctl(ptyfd, TIOCSWINSZ, &w);
+}
+
+void
+pty_setowner(struct passwd *pw, const char *ttyname)
+{
+ struct group *grp;
+ gid_t gid;
+ mode_t mode;
+ struct stat st;
+
+ /* Determine the group to make the owner of the tty. */
+ grp = getgrnam("tty");
+ if (grp) {
+ gid = grp->gr_gid;
+ mode = S_IRUSR | S_IWUSR | S_IWGRP;
+ } else {
+ gid = pw->pw_gid;
+ mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
+ }
+
+ /*
+ * Change owner and mode of the tty as required.
+ * Warn but continue if filesystem is read-only and the uids match.
+ */
+ if (stat(ttyname, &st))
+ fatal("stat(%.100s) failed: %.100s", ttyname,
+ strerror(errno));
+
+ if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
+ if (chown(ttyname, pw->pw_uid, gid) < 0) {
+ if (errno == EROFS && st.st_uid == pw->pw_uid)
+ error("chown(%.100s, %d, %d) failed: %.100s",
+ ttyname, pw->pw_uid, gid,
+ strerror(errno));
+ else
+ fatal("chown(%.100s, %d, %d) failed: %.100s",
+ ttyname, pw->pw_uid, gid,
+ strerror(errno));
+ }
+ }
+
+ if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
+ if (chmod(ttyname, mode) < 0) {
+ if (errno == EROFS &&
+ (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
+ error("chmod(%.100s, 0%o) failed: %.100s",
+ ttyname, mode, strerror(errno));
+ else
+ fatal("chmod(%.100s, 0%o) failed: %.100s",
+ ttyname, mode, strerror(errno));
+ }
+ }
+}
diff --git a/crypto/openssh/sshpty.h b/crypto/openssh/sshpty.h
new file mode 100644
index 000000000000..d7aac0f55593
--- /dev/null
+++ b/crypto/openssh/sshpty.h
@@ -0,0 +1,47 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Functions for allocating a pseudo-terminal and making it the controlling
+ * tty.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: sshpty.h,v 1.1 2001/03/04 01:46:30 djm Exp $"); */
+
+#ifndef SSHPTY_H
+#define SSHPTY_H
+
+/*
+ * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
+ * nonzero if a pty was successfully allocated. On success, open file
+ * descriptors for the pty and tty sides and the name of the tty side are
+ * returned (the buffer must be able to hold at least 64 characters).
+ */
+int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname, int ttynamelen);
+
+/*
+ * Releases the tty. Its ownership is returned to root, and permissions to
+ * 0666.
+ */
+void pty_release(const char *ttyname);
+
+/*
+ * Makes the tty the processes controlling tty and sets it to sane modes.
+ * This may need to reopen the tty to get rid of possible eavesdroppers.
+ */
+void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
+
+/* Changes the window size associated with the pty. */
+void
+pty_change_window_size(int ptyfd, int row, int col,
+ int xpixel, int ypixel);
+
+void pty_setowner(struct passwd *pw, const char *ttyname);
+
+#endif /* SSHPTY_H */
diff --git a/crypto/openssh/sshtty.c b/crypto/openssh/sshtty.c
new file mode 100644
index 000000000000..78498908fc60
--- /dev/null
+++ b/crypto/openssh/sshtty.c
@@ -0,0 +1,96 @@
+/* $OpenBSD: sshtty.c,v 1.1 2001/04/14 16:33:20 stevesk Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ * Copyright (c) 2001 Kevin Steves. 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"
+
+#include "sshtty.h"
+#include "log.h"
+
+static struct termios _saved_tio;
+static int _in_raw_mode = 0;
+
+int
+in_raw_mode(void)
+{
+ return _in_raw_mode;
+}
+
+struct termios
+get_saved_tio(void)
+{
+ return _saved_tio;
+}
+
+void
+leave_raw_mode(void)
+{
+ if (!_in_raw_mode)
+ return;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 0;
+
+ fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
+}
+
+void
+enter_raw_mode(void)
+{
+ struct termios tio;
+
+ if (tcgetattr(fileno(stdin), &tio) == -1) {
+ perror("tcgetattr");
+ return;
+ }
+ _saved_tio = tio;
+ tio.c_iflag |= IGNPAR;
+ tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+ tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+#ifdef IEXTEN
+ tio.c_lflag &= ~IEXTEN;
+#endif
+ tio.c_oflag &= ~OPOST;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 1;
+
+ fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
+}
diff --git a/crypto/openssh/sshtty.h b/crypto/openssh/sshtty.h
new file mode 100644
index 000000000000..e29385e3522e
--- /dev/null
+++ b/crypto/openssh/sshtty.h
@@ -0,0 +1,65 @@
+/* $OpenBSD: sshtty.h,v 1.1 2001/04/14 16:33:20 stevesk Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ * Copyright (c) 2001 Kevin Steves. 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.
+ */
+
+#ifndef SSHTTY_H
+#define SSHTTY_H
+
+#include <termios.h>
+
+/*
+ * Accessor function indicating whether we are in raw mode. Set by
+ * enter_raw_mode() and leave_raw_mode().
+ */
+int in_raw_mode(void);
+
+/*
+ * Return terminal modes, as saved by enter_raw_mode().
+ */
+struct termios get_saved_tio(void);
+
+/*
+ * Returns the user's terminal to normal mode if it had been
+ * put in raw mode.
+ */
+void leave_raw_mode(void);
+
+/*
+ * Puts the user's terminal in raw mode.
+ */
+void enter_raw_mode(void);
+
+#endif
diff --git a/crypto/openssh/tildexpand.h b/crypto/openssh/tildexpand.h
new file mode 100644
index 000000000000..88734f4bf5bd
--- /dev/null
+++ b/crypto/openssh/tildexpand.h
@@ -0,0 +1,19 @@
+/* $OpenBSD: tildexpand.h,v 1.2 2001/01/29 01:58:19 niklas Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * Expands tildes in the file name. Returns data allocated by xmalloc.
+ * Warning: this calls getpw*.
+ */
+char *tilde_expand_filename(const char *filename, uid_t my_uid);
diff --git a/crypto/openssh/version.c b/crypto/openssh/version.c
new file mode 100644
index 000000000000..392f5ea0a134
--- /dev/null
+++ b/crypto/openssh/version.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2001 Brian Fundakowski Feldman
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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"
+#include "version.h"
+#include "xmalloc.h"
+
+RCSID("$FreeBSD$");
+
+static char *version = NULL;
+
+const char *
+ssh_version_get(void) {
+
+ if (version == NULL)
+ version = xstrdup(SSH_VERSION_BASE " " SSH_VERSION_ADDENDUM);
+ return (version);
+}
+
+void
+ssh_version_set_addendum(const char *add) {
+ char *newvers;
+ size_t size;
+
+ if (add != NULL) {
+ size = strlen(SSH_VERSION_BASE) + 1 + strlen(add) + 1;
+ newvers = xmalloc(size);
+ snprintf(newvers, size, "%s %s", SSH_VERSION_BASE, add);
+ } else {
+ newvers = xstrdup(SSH_VERSION_BASE);
+ }
+ if (version != NULL)
+ xfree(version);
+ version = newvers;
+}