diff options
author | 2019-07-05 04:55:40 +0000 | |
---|---|---|
committer | 2019-07-05 04:55:40 +0000 | |
commit | a1ec2b370648a9a20261fda2775492e18d03841c (patch) | |
tree | ee6903eaff8541ad3b3dc4c47bbaa2c99ab7b588 /usr.bin/ssh | |
parent | make the pointer value argument name "v" instead of "value" (diff) | |
download | wireguard-openbsd-a1ec2b370648a9a20261fda2775492e18d03841c.tar.xz wireguard-openbsd-a1ec2b370648a9a20261fda2775492e18d03841c.zip |
add a local implementation of BSD realpath() for sftp-server use
ahead of OpenBSD's realpath changing to match POSIX;
ok deraadt@ (thanks for snaps testing)
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r-- | usr.bin/ssh/sftp-realpath.c | 224 | ||||
-rw-r--r-- | usr.bin/ssh/sftp-server.c | 6 | ||||
-rw-r--r-- | usr.bin/ssh/sftp-server/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/ssh/ssh-keygen.c | 3 | ||||
-rw-r--r-- | usr.bin/ssh/ssh-keygen/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/ssh/sshd/Makefile | 4 |
6 files changed, 235 insertions, 10 deletions
diff --git a/usr.bin/ssh/sftp-realpath.c b/usr.bin/ssh/sftp-realpath.c new file mode 100644 index 00000000000..0ed808f46c7 --- /dev/null +++ b/usr.bin/ssh/sftp-realpath.c @@ -0,0 +1,224 @@ +/* $OpenBSD: sftp-realpath.c,v 1.1 2019/07/05 04:55:40 djm Exp $ */ +/* + * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> + * + * 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. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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 <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <errno.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> + +#ifndef SYMLOOP_MAX +# define SYMLOOP_MAX 32 +#endif + +/* XXX rewrite sftp-server to use POSIX realpath and remove this hack */ + +char *sftp_realpath(const char *path, char *resolved); + +/* + * char *realpath(const char *path, char resolved[PATH_MAX]); + * + * Find the real name of path, by removing all ".", ".." and symlink + * components. Returns (resolved) on success, or (NULL) on failure, + * in which case the path which caused trouble is left in (resolved). + */ +char * +sftp_realpath(const char *path, char *resolved) +{ + struct stat sb; + char *p, *q, *s; + size_t left_len, resolved_len; + unsigned symlinks; + int serrno, slen, mem_allocated; + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; + + if (path[0] == '\0') { + errno = ENOENT; + return (NULL); + } + + serrno = errno; + + if (resolved == NULL) { + resolved = malloc(PATH_MAX); + if (resolved == NULL) + return (NULL); + mem_allocated = 1; + } else + mem_allocated = 0; + + symlinks = 0; + if (path[0] == '/') { + resolved[0] = '/'; + resolved[1] = '\0'; + if (path[1] == '\0') + return (resolved); + resolved_len = 1; + left_len = strlcpy(left, path + 1, sizeof(left)); + } else { + if (getcwd(resolved, PATH_MAX) == NULL) { + if (mem_allocated) + free(resolved); + else + strlcpy(resolved, ".", PATH_MAX); + return (NULL); + } + resolved_len = strlen(resolved); + left_len = strlcpy(left, path, sizeof(left)); + } + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } + + /* + * Iterate over path components in `left'. + */ + while (left_len != 0) { + /* + * Extract the next path component and adjust `left' + * and its length. + */ + p = strchr(left, '/'); + s = p ? p : left + left_len; + if (s - left >= (ptrdiff_t)sizeof(next_token)) { + errno = ENAMETOOLONG; + goto err; + } + memcpy(next_token, left, s - left); + next_token[s - left] = '\0'; + left_len -= s - left; + if (p != NULL) + memmove(left, s + 1, left_len + 1); + if (resolved[resolved_len - 1] != '/') { + if (resolved_len + 1 >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } + resolved[resolved_len++] = '/'; + resolved[resolved_len] = '\0'; + } + if (next_token[0] == '\0') + continue; + else if (strcmp(next_token, ".") == 0) + continue; + else if (strcmp(next_token, "..") == 0) { + /* + * Strip the last path component except when we have + * single "/" + */ + if (resolved_len > 1) { + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + continue; + } + + /* + * Append the next path component and lstat() it. If + * lstat() fails we still can return successfully if + * there are no more path components left. + */ + resolved_len = strlcat(resolved, next_token, PATH_MAX); + if (resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } + if (lstat(resolved, &sb) != 0) { + if (errno == ENOENT && p == NULL) { + errno = serrno; + return (resolved); + } + goto err; + } + if (S_ISLNK(sb.st_mode)) { + if (symlinks++ > SYMLOOP_MAX) { + errno = ELOOP; + goto err; + } + slen = readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) + goto err; + symlink[slen] = '\0'; + if (symlink[0] == '/') { + resolved[1] = 0; + resolved_len = 1; + } else if (resolved_len > 1) { + /* Strip the last path component. */ + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + + /* + * If there are any path components left, then + * append them to symlink. The result is placed + * in `left'. + */ + if (p != NULL) { + if (symlink[slen - 1] != '/') { + if (slen + 1 >= + (ptrdiff_t)sizeof(symlink)) { + errno = ENAMETOOLONG; + goto err; + } + symlink[slen] = '/'; + symlink[slen + 1] = 0; + } + left_len = strlcat(symlink, left, sizeof(symlink)); + if (left_len >= sizeof(symlink)) { + errno = ENAMETOOLONG; + goto err; + } + } + left_len = strlcpy(left, symlink, sizeof(left)); + } + } + + /* + * Remove trailing slash except when the resolved pathname + * is a single "/". + */ + if (resolved_len > 1 && resolved[resolved_len - 1] == '/') + resolved[resolved_len - 1] = '\0'; + return (resolved); + +err: + if (mem_allocated) + free(resolved); + return (NULL); +} diff --git a/usr.bin/ssh/sftp-server.c b/usr.bin/ssh/sftp-server.c index afb671398b8..10e43bf06bf 100644 --- a/usr.bin/ssh/sftp-server.c +++ b/usr.bin/ssh/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.116 2019/06/28 13:35:04 deraadt Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.117 2019/07/05 04:55:40 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -43,6 +43,8 @@ #include "sftp.h" #include "sftp-common.h" +char *sftp_realpath(const char *, char *); /* sftp-realpath.c */ + /* Our verbosity */ static LogLevel log_level = SYSLOG_LEVEL_ERROR; @@ -1154,7 +1156,7 @@ process_realpath(u_int32_t id) } debug3("request %u: realpath", id); verbose("realpath \"%s\"", path); - if (realpath(path, resolvedname) == NULL) { + if (sftp_realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { Stat s; diff --git a/usr.bin/ssh/sftp-server/Makefile b/usr.bin/ssh/sftp-server/Makefile index 7a0c3f87861..c2a08bf32d2 100644 --- a/usr.bin/ssh/sftp-server/Makefile +++ b/usr.bin/ssh/sftp-server/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.12 2018/07/25 17:12:35 deraadt Exp $ +# $OpenBSD: Makefile,v 1.13 2019/07/05 04:55:41 djm Exp $ .PATH: ${.CURDIR}/.. -SRCS= sftp-server.c sftp-common.c sftp-server-main.c +SRCS= sftp-server.c sftp-common.c sftp-server-main.c sftp-realpath.c SRCS+= fatal.c SRCS+= ${SRCS_BASE} ${SRCS_UTL} diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index 19909d6da15..1c32516751c 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.333 2019/06/28 13:35:04 deraadt Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.334 2019/07/05 04:55:40 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -33,7 +33,6 @@ #include "xmalloc.h" #include "sshkey.h" #include "authfile.h" -#include "uuencode.h" #include "sshbuf.h" #include "pathnames.h" #include "log.h" diff --git a/usr.bin/ssh/ssh-keygen/Makefile b/usr.bin/ssh/ssh-keygen/Makefile index 4eb9d612145..7efc2f43336 100644 --- a/usr.bin/ssh/ssh-keygen/Makefile +++ b/usr.bin/ssh/ssh-keygen/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.27 2018/07/25 17:12:35 deraadt Exp $ +# $OpenBSD: Makefile,v 1.28 2019/07/05 04:55:41 djm Exp $ .PATH: ${.CURDIR}/.. -SRCS= ssh-keygen.c moduli.c uuencode.c +SRCS= ssh-keygen.c moduli.c SRCS+= atomicio.c authfd.c cleanup.c dns.c fatal.c hmac.c hostfile.c \ readpass.c utf8.c SRCS+= ${SRCS_BASE} ${SRCS_KEY} ${SRCS_KEYP} ${SRCS_KRL} ${SRCS_UTL} \ diff --git a/usr.bin/ssh/sshd/Makefile b/usr.bin/ssh/sshd/Makefile index 09aad4c0d4b..5d8bc45217b 100644 --- a/usr.bin/ssh/sshd/Makefile +++ b/usr.bin/ssh/sshd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.99 2018/07/25 17:12:35 deraadt Exp $ +# $OpenBSD: Makefile,v 1.100 2019/07/05 04:55:41 djm Exp $ .PATH: ${.CURDIR}/.. @@ -6,7 +6,7 @@ SRCS= sshd.c auth-rhosts.c auth-passwd.c sshpty.c sshlogin.c servconf.c \ serverloop.c auth.c auth2.c auth-options.c session.c auth2-chall.c \ groupaccess.c auth-bsdauth.c auth2-hostbased.c auth2-kbdint.c \ auth2-none.c auth2-passwd.c auth2-pubkey.c monitor.c monitor_wrap.c \ - sftp-server.c sftp-common.c sandbox-pledge.c + sftp-server.c sftp-common.c sftp-realpath.c sandbox-pledge.c SRCS+= atomicio.c authfd.c compat.c dns.c fatal.c \ hostfile.c msg.c readpass.c utf8.c uidswap.c SRCS+= ${SRCS_BASE} ${SRCS_KEX} ${SRCS_KEXS} ${SRCS_KEY} ${SRCS_KEYP} \ |