Merge pull request #388 from rayhayes/L1-Prod

Merge in latest changes for scp.
This commit is contained in:
Ray Hayes 2016-10-27 13:17:00 -07:00 committed by GitHub
commit 37477b654c
8 changed files with 393 additions and 194 deletions

View File

@ -266,6 +266,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\openssl-epoint.c" />
<ClCompile Include="..\..\..\utf8.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h" />

View File

@ -294,6 +294,9 @@
<ClCompile Include="..\..\..\openssl-epoint.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\utf8.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h">

View File

@ -854,12 +854,10 @@ int
w32_ftruncate(int fd, off_t length) {
CHECK_FD(fd);
if (!SetFilePointer(w32_fd_to_handle(fd), length, 0, FILE_BEGIN))
return -1;
if (!SetEndOfFile(w32_fd_to_handle(fd)))
return -1;
if (!SetFileValidData(w32_fd_to_handle(fd), length))
return -1;
if (!SetFilePointer(w32_fd_to_handle(fd), 0, 0, FILE_BEGIN))
return -1;
return 0;
}

View File

@ -232,10 +232,45 @@ long long strtonum(const char *, long long, long long, const char **);
# define mblen(x, y) (1)
#endif
#ifndef HAVE_WCWIDTH
# define wcwidth(x) (((x) >= 0x20 && (x) <= 0x7e) ? 1 : -1)
/* force our no-op nl_langinfo and mbtowc */
# undef HAVE_NL_LANGINFO
# undef HAVE_MBTOWC
# undef HAVE_LANGINFO_H
#endif
#ifndef HAVE_NL_LANGINFO
# define nl_langinfo(x) ""
#endif
#ifndef HAVE_MBTOWC
int mbtowc(wchar_t *, const char*, size_t);
#endif
#if !defined(HAVE_VASPRINTF) || !defined(HAVE_VSNPRINTF)
# include <stdarg.h>
#endif
/*
* Some platforms unconditionally undefine va_copy() so we define VA_COPY()
* instead. This is known to be the case on at least some configurations of
* AIX with the xlc compiler.
*/
#ifndef VA_COPY
# ifdef HAVE_VA_COPY
# define VA_COPY(dest, src) va_copy(dest, src)
# else
# ifdef HAVE___VA_COPY
# define VA_COPY(dest, src) __va_copy(dest, src)
# else
# define VA_COPY(dest, src) (dest) = (src)
# endif
# endif
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **, const char *, va_list);
#endif

View File

@ -48,7 +48,7 @@
*/
#define VIS_OCTAL 0x01 /* use octal \ddd format */
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
#define VIS_ALL 0x400 /* encode all characters */
/*
* to alter set of characters encoded (default is to encode all
* non-graphic except space, tab, and newline).

214
scp.c
View File

@ -78,6 +78,7 @@
#else
#include <io.h>
#include <fcntl.h>
#include <Shlwapi.h>
#include "win32_dirent.h"
#endif
@ -104,6 +105,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <locale.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
@ -122,10 +124,8 @@
#include "log.h"
#include "misc.h"
#include "progressmeter.h"
#include "utf8.h"
#ifdef WINDOWS
#include <Shlwapi.h>
#endif
extern char *__progname;
#define COPY_BUFLEN 16384
@ -319,125 +319,6 @@ int InitForMicrosoftWindows()
return 0;
}
// start of direntry functions in Windows NT like UNIX
// opendir(), readdir(), closedir().
// NT_DIR * nt_opendir(char *name) ;
// struct nt_dirent *nt_readdir(NT_DIR *dirp);
// int nt_closedir(NT_DIR *dirp) ;
// Windows NT directory structure content
struct scp_dirent {
char *d_name ; // name of the directory entry
int d_ino; // UNIX inode
//unsigned attrib ; // its attributes
};
typedef struct {
long hFile;
struct _finddata_t c_file;
} SCPDIR;
char * fixslashes(char * str)
{
int i;
if (str == NULL)
return str;
int len = (int)strlen(str);
for (i = 0; i < len; i++)
if (str[i] == '/')
str[i] = '\\';
return str;
}
// force path separator to sep
char * forcepathsep(char * str, char sep)
{
int i;
// bail if str is null;
if (str == NULL)
return str;
// bail if sep isn't valid
if ((sep != '\\') || (sep != '/'))
return str;
char antisep = '/';
if (sep == '/')
antisep = '\\';
int len = (int)strlen(str);
for (i = 0; i < len; i++)
if (str[i] == antisep)
str[i] = sep;
return str;
}
// get the path separator character
char getpathsep(char * path)
{
char sep = '/';
char * p = strpbrk(path,"/\\");
if (p != NULL)
sep = p[0];
return sep;
}
bool getRootFrompath(char * path, char * root)
{
strcpy(root,path);
char sep = getpathsep(root);
forcepathsep(root,sep);
char * lastslash = strrchr(root,sep);
if (lastslash)
*lastslash = 0x00;
return (lastslash != NULL);
}
/*
* get option letter from argument vector
*/
char * getfilenamefrompath(char * path)
{
char * lastslash;
char * lastbackslash;
lastslash = strrchr(path,'/');
lastbackslash = strrchr(path, '\\');
if (lastslash == NULL && lastbackslash == NULL)
{
// no delimiters, just return the original string
return path;
}
else if (lastslash == NULL)
{
// no slashes, return the backslash search minus the last char
return ++lastbackslash;
}
else if (lastbackslash == NULL)
{
// no backslashes, return the slash search minus the last char
return ++lastslash;
}
else
{
// string has both slashes and backslashes. return whichever is larger
// (i.e. further down the string)
lastslash++;
lastbackslash++;
return ((lastslash > lastbackslash)?lastslash:lastbackslash);
}
return NULL;
}
#endif
#define EMSG ""
@ -526,33 +407,6 @@ sgetopt(int nargc,
return(optopt); /* dump back option letter */
}
/* Open a directory stream on NAME.
Return a SCPDIR stream on the directory, or NULL if it could not be opened. */
SCPDIR * scp_opendir(char *name)
{
struct _finddata_t c_file;
long hFile;
SCPDIR *pdir;
char searchstr[256];
sprintf_s(searchstr,sizeof(searchstr),"%s\\*.*",name); // add *.* to it for NT
if( (hFile = (long)_findfirst( searchstr, &c_file )) == -1L ) {
if ( scpverbose)
printf( "No files found for %s search.\n", name );
return (SCPDIR *) NULL;
}
else {
pdir = (SCPDIR *) malloc( sizeof(SCPDIR) );
pdir->hFile = hFile ;
pdir->c_file = c_file ;
return pdir ;
}
}
int _utimedir (char *name, struct _utimbuf *filetime)
{
int rc, chandle;
@ -579,30 +433,6 @@ int _utimedir (char *name, struct _utimbuf *filetime)
HANDLE hprocess=(HANDLE) 0; // we made it a global to stop child process(ssh) of scp
#else
/* Read a directory entry from SCPDIRP.
Return a pointer to a `struct scp_dirent' describing the entry,
or NULL for EOF or error. The storage returned may be overwritten
by a later readdir call on the same SCPDIR stream. */
struct scp_dirent *readdir(SCPDIR *dirp)
{
struct scp_dirent *pdirentry;
for (;;) {
if (_findnext(dirp->hFile, &(dirp->c_file)) == 0) {
if ((strcmp(dirp->c_file.name, ".") == 0) ||
(strcmp(dirp->c_file.name, "..") == 0)) {
continue;
}
pdirentry = (struct scp_dirent *)malloc(sizeof(struct scp_dirent));
pdirentry->d_name = dirp->c_file.name;
pdirentry->d_ino = 1; // a fictious one like UNIX to say it is nonzero
return pdirentry;
}
else {
return (struct scp_dirent *) NULL;
}
}
}
#endif
static void
@ -645,7 +475,7 @@ do_local_cmd(arglist *a)
if (verbose_mode) {
fprintf(stderr, "Executing:");
for (i = 0; i < a->num; i++)
fprintf(stderr, " %s", a->list[i]);
fmprintf(stderr, " %s", a->list[i]);
fprintf(stderr, "\n");
}
#ifdef WINDOWS
@ -941,7 +771,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
int pin[2], pout[2], reserved[2];
if (verbose_mode)
fprintf(stderr,
fmprintf(stderr,
"Executing: program %s host %s, user %s, command %s\n",
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
@ -1018,7 +848,7 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
int status;
if (verbose_mode)
fprintf(stderr,
fmprintf(stderr,
"Executing: 2nd program %s host %s, user %s, command %s\n",
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
@ -1089,12 +919,19 @@ main(int argc, char **argv)
extern int optind;
#ifdef WINDOWS
/*
* Initialize I/O wrappers.
*/
w32posix_initialize();
ConInit(STD_OUTPUT_HANDLE, TRUE);
#endif
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
setlocale(LC_CTYPE, "");
/* Copy argv, because we modify it */
newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv));
for (n = 0; n < argc; n++)
@ -1247,7 +1084,7 @@ main(int argc, char **argv)
exit(errs != 0);
}
if (tflag) {
/* Receive data. */
/* Receive data. */
sink(argc, argv);
exit(errs != 0);
}
@ -1569,9 +1406,8 @@ syserr: run_err("%s: %s", name, strerror(errno));
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
(long long)stb.st_size, last);
if (verbose_mode) {
fprintf(stderr, "Sending file modes: %s", buf);
}
if (verbose_mode)
fmprintf(stderr, "Sending file modes: %s", buf);
(void) atomicio(vwrite, remout, buf, strlen(buf));
if (response() < 0)
goto next;
@ -1607,8 +1443,6 @@ next: if (fd != -1) {
haderr = errno;
}
unset_nonblock(remout);
if (showprogress)
stop_progress_meter();
if (fd != -1) {
if (close(fd) < 0 && !haderr)
@ -1620,6 +1454,8 @@ next: if (fd != -1) {
else
run_err("%s: %s", name, strerror(haderr));
(void) response();
if (showprogress)
stop_progress_meter();
}
}
@ -1635,7 +1471,7 @@ rsource(char *name, struct stat *statp)
return;
}
last = strrchr(name, '/');
if (last == 0)
if (last == NULL)
last = name;
else
last++;
@ -1656,7 +1492,7 @@ rsource(char *name, struct stat *statp)
free(wtmp);
}
#else
fprintf(stderr, "Entering directory: %s", path);
fmprintf(stderr, "Entering directory: %s", path);
#endif
(void) atomicio(vwrite, remout, path, strlen(path));
@ -1741,7 +1577,7 @@ sink(int argc, char **argv)
free(wtmp);
}
#else
fprintf(stderr, "Sink: %s", buf);
fmprintf(stderr, "Sink: %s", buf);
#endif
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0)
@ -1922,8 +1758,6 @@ bad: run_err("%s: %s", np, strerror(errno));
}
}
unset_nonblock(remin);
if (showprogress)
stop_progress_meter();
if (count != 0 && wrerr == NO &&
atomicio(vwrite, ofd, bp->buf, count) != count) {
wrerr = YES;
@ -1962,6 +1796,8 @@ bad: run_err("%s: %s", np, strerror(errno));
wrerrno = errno;
}
(void) response();
if (showprogress)
stop_progress_meter();
if (setimes && wrerr == NO) {
setimes = 0;
if (utimes(np, tv) < 0) {
@ -2048,7 +1884,7 @@ run_err(const char *fmt,...)
if (!iamremote) {
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
vfmprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
@ -2094,7 +1930,7 @@ okname(char *cp0)
} while (*++cp);
return (1);
bad: fprintf(stderr, "%s: invalid user name\n", cp0);
bad: fmprintf(stderr, "%s: invalid user name\n", cp0);
return (0);
}

302
utf8.c Normal file
View File

@ -0,0 +1,302 @@
/* $OpenBSD: utf8.c,v 1.3 2016/05/30 12:57:21 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Utility functions for multibyte-character handling,
* in particular to sanitize untrusted strings for terminal output.
*/
#include "includes.h"
#include <sys/types.h>
#ifdef HAVE_LANGINFO_H
# include <langinfo.h>
#endif
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
# include <vis.h>
#endif
#ifdef HAVE_WCHAR_H
# include <wchar.h>
#endif
#include "utf8.h"
static int dangerous_locale(void);
static int grow_dst(char **, size_t *, size_t, char **, size_t);
static int vasnmprintf(char **, size_t, int *, const char *, va_list);
/*
* For US-ASCII and UTF-8 encodings, we can safely recover from
* encoding errors and from non-printable characters. For any
* other encodings, err to the side of caution and abort parsing:
* For state-dependent encodings, recovery is impossible.
* For arbitrary encodings, replacement of non-printable
* characters would be non-trivial and too fragile.
*/
static int
dangerous_locale(void) {
#ifndef WINDOWS
char *loc;
#ifdef HAVE_LANGINFO_H
loc = nl_langinfo(CODESET);
#endif
return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8");
#else
wchar_t loc[LOCALE_NAME_MAX_LENGTH];
GetSystemDefaultLocaleName(loc, LOCALE_NAME_MAX_LENGTH);
return wcscmp(loc, L"US-ASCII") && wcscmp(loc, L"UTF-8");
#endif
}
static int
grow_dst(char **dst, size_t *sz, size_t maxsz, char **dp, size_t need)
{
char *tp;
size_t tsz;
if (*dp + need < *dst + *sz)
return 0;
tsz = *sz + 128;
if (tsz > maxsz)
tsz = maxsz;
if ((tp = realloc(*dst, tsz)) == NULL)
return -1;
*dp = tp + (*dp - *dst);
*dst = tp;
*sz = tsz;
return 0;
}
/*
* The following two functions limit the number of bytes written,
* including the terminating '\0', to sz. Unless wp is NULL,
* they limit the number of display columns occupied to *wp.
* Whichever is reached first terminates the output string.
* To stay close to the standard interfaces, they return the number of
* non-NUL bytes that would have been written if both were unlimited.
* If wp is NULL, newline, carriage return, and tab are allowed;
* otherwise, the actual number of columns occupied by what was
* written is returned in *wp.
*/
static int
vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
{
char *src; /* Source string returned from vasprintf. */
char *sp; /* Pointer into src. */
char *dst; /* Destination string to be returned. */
char *dp; /* Pointer into dst. */
char *tp; /* Temporary pointer for dst. */
size_t sz; /* Number of bytes allocated for dst. */
wchar_t wc; /* Wide character at sp. */
int len; /* Number of bytes in the character at sp. */
int ret; /* Number of bytes needed to format src. */
int width; /* Display width of the character wc. */
int total_width, max_width, print;
src = NULL;
if ((ret = vasprintf(&src, fmt, ap)) <= 0)
goto fail;
sz = strlen(src) + 1;
if ((dst = malloc(sz)) == NULL) {
free(src);
goto fail;
}
if (maxsz > INT_MAX)
maxsz = INT_MAX;
sp = src;
dp = dst;
ret = 0;
print = 1;
total_width = 0;
max_width = wp == NULL ? INT_MAX : *wp;
while (*sp != '\0') {
if ((len = mbtowc(&wc, sp, MB_CUR_MAX)) == -1) {
(void)mbtowc(NULL, NULL, MB_CUR_MAX);
if (dangerous_locale()) {
ret = -1;
break;
}
len = 1;
width = -1;
} else if (wp == NULL &&
(wc == L'\n' || wc == L'\r' || wc == L'\t')) {
/*
* Don't use width uninitialized; the actual
* value doesn't matter because total_width
* is only returned for wp != NULL.
*/
width = 0;
} else if ((width = wcwidth(wc)) == -1 &&
dangerous_locale()) {
ret = -1;
break;
}
/* Valid, printable character. */
if (width >= 0) {
if (print && (dp - dst >= (int)maxsz - len ||
total_width > max_width - width))
print = 0;
if (print) {
if (grow_dst(&dst, &sz, maxsz,
&dp, len) == -1) {
ret = -1;
break;
}
total_width += width;
memcpy(dp, sp, len);
dp += len;
}
sp += len;
if (ret >= 0)
ret += len;
continue;
}
/* Escaping required. */
while (len > 0) {
if (print && (dp - dst >= (int)maxsz - 4 ||
total_width > max_width - 4))
print = 0;
if (print) {
if (grow_dst(&dst, &sz, maxsz,
&dp, 4) == -1) {
ret = -1;
break;
}
tp = vis(dp, *sp, VIS_OCTAL | VIS_ALL, 0);
width = tp - dp;
total_width += width;
dp = tp;
} else
width = 4;
len--;
sp++;
if (ret >= 0)
ret += width;
}
if (len > 0)
break;
}
free(src);
*dp = '\0';
*str = dst;
if (wp != NULL)
*wp = total_width;
/*
* If the string was truncated by the width limit but
* would have fit into the size limit, the only sane way
* to report the problem is using the return value, such
* that the usual idiom "if (ret < 0 || ret >= sz) error"
* works as expected.
*/
if (ret < (int)maxsz && !print)
ret = -1;
return ret;
fail:
if (wp != NULL)
*wp = 0;
if (ret == 0) {
*str = src;
return 0;
} else {
*str = NULL;
return -1;
}
}
int
snmprintf(char *str, size_t sz, int *wp, const char *fmt, ...)
{
va_list ap;
char *cp;
int ret;
va_start(ap, fmt);
ret = vasnmprintf(&cp, sz, wp, fmt, ap);
va_end(ap);
if (cp != NULL) {
(void)strlcpy(str, cp, sz);
free(cp);
} else
*str = '\0';
return ret;
}
/*
* To stay close to the standard interfaces, the following functions
* return the number of non-NUL bytes written.
*/
int
vfmprintf(FILE *stream, const char *fmt, va_list ap)
{
char *str;
int ret;
if ((ret = vasnmprintf(&str, INT_MAX, NULL, fmt, ap)) < 0)
return -1;
if (fputs(str, stream) == EOF)
ret = -1;
free(str);
return ret;
}
int
fmprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vfmprintf(stream, fmt, ap);
va_end(ap);
return ret;
}
int
mprintf(const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vfmprintf(stdout, fmt, ap);
va_end(ap);
return ret;
}

24
utf8.h Normal file
View File

@ -0,0 +1,24 @@
/* $OpenBSD: utf8.h,v 1.1 2016/05/25 23:48:45 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
int mprintf(const char *, ...)
__attribute__((format(printf, 1, 2)));
int fmprintf(FILE *, const char *, ...)
__attribute__((format(printf, 2, 3)));
int vfmprintf(FILE *, const char *, va_list);
int snmprintf(char *, size_t, int *, const char *, ...)
__attribute__((format(printf, 4, 5)));