diff options
Diffstat (limited to 'usr/src')
27 files changed, 3701 insertions, 2319 deletions
diff --git a/usr/src/cmd/ssh/include/atomicio.h b/usr/src/cmd/ssh/include/atomicio.h index 13c9d4b4e6..e1ba7b21e6 100644 --- a/usr/src/cmd/ssh/include/atomicio.h +++ b/usr/src/cmd/ssh/include/atomicio.h @@ -1,16 +1,5 @@ -/* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $ */ - -#ifndef _ATOMICIO_H -#define _ATOMICIO_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - - /* + * Copyright (c) 2006 Damien Miller. All rights reserved. * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * All rights reserved. * @@ -35,11 +24,30 @@ extern "C" { * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _ATOMICIO_H +#define _ATOMICIO_H + +/* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + /* * Ensure all of data on socket comes through. f==read || f==write */ ssize_t atomicio(ssize_t (*)(), int, void *, size_t); +#define vwrite (ssize_t (*)(int, void *, size_t))write + +/* + * ensure all of data on socket comes through. f==readv || f==writev + */ +size_t atomiciov(ssize_t (*)(int, const struct iovec *, int), + int, const struct iovec *, int); + #ifdef __cplusplus } #endif diff --git a/usr/src/cmd/ssh/include/buffer.h b/usr/src/cmd/ssh/include/buffer.h index 1d09c6335f..4a6c7ad5e1 100644 --- a/usr/src/cmd/ssh/include/buffer.h +++ b/usr/src/cmd/ssh/include/buffer.h @@ -30,9 +30,6 @@ typedef struct { u_int end; /* Offset of last byte containing data. */ } Buffer; -#define BUFFER_MAX_CHUNK 0x100000 -#define BUFFER_MAX_LEN 0xa00000 - void buffer_init(Buffer *); void buffer_clear(Buffer *); void buffer_free(Buffer *); @@ -43,6 +40,8 @@ void *buffer_ptr(Buffer *); void buffer_append(Buffer *, const void *, u_int); void *buffer_append_space(Buffer *, u_int); +int buffer_check_alloc(Buffer *, u_int); + void buffer_get(Buffer *, void *, u_int); void buffer_consume(Buffer *, u_int); diff --git a/usr/src/cmd/ssh/include/config.h b/usr/src/cmd/ssh/include/config.h index 0441e64951..a2a524204b 100644 --- a/usr/src/cmd/ssh/include/config.h +++ b/usr/src/cmd/ssh/include/config.h @@ -2,7 +2,7 @@ /* config.h.in. Generated from configure.ac by autoheader. */ /* $Id: acconfig.h,v 1.145 2002/09/26 00:38:48 tim Exp $ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -409,6 +409,9 @@ extern "C" { /* Define if you want smartcard support using sectok */ /* #undef USE_SECTOK */ +/* Use libedit for sftp */ +#undef USE_LIBEDIT + /* Define if you want smartcard support using OpenSC */ /* #undef USE_OPENSC */ @@ -434,6 +437,9 @@ extern "C" { /* Define to 1 if you have the `arc4random' function. */ /* #undef HAVE_ARC4RANDOM */ +/* Define to 1 if you have the `asprintf' function. */ +/* #undef HAVE_ASPRINTF */ + /* Define to 1 if you have the `b64_ntop' function. */ /* #undef HAVE_B64_NTOP */ @@ -904,6 +910,9 @@ extern "C" { /* Define to 1 if you have the <utmp.h> header file. */ #define HAVE_UTMP_H 1 +/* Define to 1 if you have the `vasprintf' function. */ +/* #undef HAVE_VASPRINTF */ + /* Define to 1 if you have the `vhangup' function. */ #define HAVE_VHANGUP 1 diff --git a/usr/src/cmd/ssh/include/defines.h b/usr/src/cmd/ssh/include/defines.h index 690037ce6b..4b8bbebed6 100644 --- a/usr/src/cmd/ssh/include/defines.h +++ b/usr/src/cmd/ssh/include/defines.h @@ -1,5 +1,28 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 1999-2003 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. + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -403,6 +426,10 @@ struct winsize { # define __attribute__(x) #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ +#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) +# define __bounded__(x, y, z) +#endif + /* *-*-nto-qnx doesn't define this macro in the system headers */ #ifdef MISSING_HOWMANY # define howmany(x,y) (((x)+((y)-1))/(y)) diff --git a/usr/src/cmd/ssh/include/misc.h b/usr/src/cmd/ssh/include/misc.h index 4951d42013..20937646df 100644 --- a/usr/src/cmd/ssh/include/misc.h +++ b/usr/src/cmd/ssh/include/misc.h @@ -1,15 +1,3 @@ -/* $OpenBSD: misc.h,v 1.12 2002/03/19 10:49:35 markus Exp $ */ - -#ifndef _MISC_H -#define _MISC_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - - /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -26,6 +14,17 @@ extern "C" { * Use is subject to license terms. */ +#ifndef _MISC_H +#define _MISC_H + +/* $OpenBSD: misc.h,v 1.12 2002/03/19 10:49:35 markus Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + char *chop(char *); char *strdelim(char **); void set_nonblock(int); @@ -36,6 +35,7 @@ char *cleanhostname(char *); char *colon(char *); long convtime(const char *); char *tohex(const void *, size_t); +void sanitise_stdfd(void); int get_yes_no_flag(int *option, const char *arg, const char *filename, int linenum, int active); @@ -49,12 +49,28 @@ struct arglist { int nalloc; }; void addargs(arglist *, char *, ...) __attribute__((format(printf, 2, 3))); +void replacearg(arglist *, u_int, char *, ...) + __attribute__((format(printf, 3, 4))); void freeargs(arglist *); /* wrapper for signal interface */ typedef void (*mysig_t)(int); mysig_t mysignal(int sig, mysig_t act); +/* Functions to extract or store big-endian words of various sizes */ +u_int64_t get_u64(const void *) + __attribute__((__bounded__( __minbytes__, 1, 8))); +u_int32_t get_u32(const void *) + __attribute__((__bounded__( __minbytes__, 1, 4))); +u_int16_t get_u16(const void *) + __attribute__((__bounded__( __minbytes__, 1, 2))); +void put_u64(void *, u_int64_t) + __attribute__((__bounded__( __minbytes__, 1, 8))); +void put_u32(void *, u_int32_t) + __attribute__((__bounded__( __minbytes__, 1, 4))); +void put_u16(void *, u_int16_t) + __attribute__((__bounded__( __minbytes__, 1, 2))); + #ifdef __cplusplus } #endif diff --git a/usr/src/cmd/ssh/include/openbsd-compat.h b/usr/src/cmd/ssh/include/openbsd-compat.h index 7520851248..2cdd3952ab 100644 --- a/usr/src/cmd/ssh/include/openbsd-compat.h +++ b/usr/src/cmd/ssh/include/openbsd-compat.h @@ -1,8 +1,34 @@ -/* $Id: openbsd-compat.h,v 1.17 2002/09/12 00:33:02 djm Exp $ */ +/* + * Copyright (c) 1999-2003 Damien Miller. All rights reserved. + * Copyright (c) 2003 Ben Lindstrom. All rights reserved. + * Copyright (c) 2002 Tim Rice. 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 _OPENBSD_COMPAT_H #define _OPENBSD_COMPAT_H +/* $Id: openbsd-compat.h,v 1.17 2002/09/12 00:33:02 djm Exp $ */ + #pragma ident "%Z%%M% %I% %E% SMI" #ifdef __cplusplus @@ -50,6 +76,10 @@ extern "C" { #include "port-irix.h" #include "port-aix.h" +#ifndef HAVE_VASPRINTF +int vasprintf(char **, const char *, va_list); +#endif + #ifdef __cplusplus } #endif diff --git a/usr/src/cmd/ssh/include/sftp-int.h b/usr/src/cmd/ssh/include/progressmeter.h index e02c314206..d8a3bc6737 100644 --- a/usr/src/cmd/ssh/include/sftp-int.h +++ b/usr/src/cmd/ssh/include/progressmeter.h @@ -1,17 +1,5 @@ -/* $OpenBSD: sftp-int.h,v 1.5 2002/02/13 00:59:23 djm Exp $ */ - -#ifndef _SFTP_INT_H -#define _SFTP_INT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - - /* - * Copyright (c) 2001,2002 Damien Miller. All rights reserved. + * Copyright (c) 2002 Nils Nordman. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,10 +22,22 @@ extern "C" { * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -void interactive_loop(int, int, char *, char *); +#ifndef _PROGRESSMETER_H +#define _PROGRESSMETER_H + +/* $OpenBSD: progressmeter.h,v 1.2 2006/03/25 22:22:43 djm Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +void start_progress_meter(char *, off_t, off_t *); +void stop_progress_meter(void); #ifdef __cplusplus } #endif -#endif /* _SFTP_INT_H */ +#endif /* _PROGRESSMETER_H */ diff --git a/usr/src/cmd/ssh/include/sftp-client.h b/usr/src/cmd/ssh/include/sftp-client.h index 9703c69770..1927e3df16 100644 --- a/usr/src/cmd/ssh/include/sftp-client.h +++ b/usr/src/cmd/ssh/include/sftp-client.h @@ -1,7 +1,23 @@ -/* $OpenBSD: sftp-client.h,v 1.11 2002/09/11 22:41:50 djm Exp $ */ +/* + * Copyright (c) 2001-2004 Damien Miller <djm@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. + */ + +#ifndef _SFTP_CLIENT_H +#define _SFTP_CLIENT_H -#ifndef _SFTP_CLIENT_H -#define _SFTP_CLIENT_H +/* $OpenBSD: sftp-client.h,v 1.14 2005/04/26 12:59:02 jmc Exp $ */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -9,31 +25,6 @@ extern "C" { #endif - -/* - * Copyright (c) 2001,2002 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; @@ -45,8 +36,8 @@ struct SFTP_DIRENT { }; /* - * Initialiase a SSH filexfer connection. Returns -1 on error or - * protocol version on success. + * Initialise a SSH filexfer connection. Returns NULL on error or + * a pointer to a initialized sftp_conn struct on success. */ struct sftp_conn *do_init(int, int, u_int, u_int); diff --git a/usr/src/cmd/ssh/include/sftp-common.h b/usr/src/cmd/ssh/include/sftp-common.h index 98481cd2a7..86225bc175 100644 --- a/usr/src/cmd/ssh/include/sftp-common.h +++ b/usr/src/cmd/ssh/include/sftp-common.h @@ -1,15 +1,3 @@ -/* $OpenBSD: sftp-common.h,v 1.4 2002/09/11 22:41:50 djm Exp $ */ - -#ifndef _SFTP_COMMON_H -#define _SFTP_COMMON_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - - /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Damien Miller. All rights reserved. @@ -35,6 +23,20 @@ extern "C" { * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _SFTP_COMMON_H +#define _SFTP_COMMON_H + +/* $OpenBSD: sftp-common.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Maximum packet that we are willing to send/accept */ +#define SFTP_MAX_MSG_LENGTH (256 * 1024) + typedef struct Attrib Attrib; /* File attributes */ @@ -49,11 +51,11 @@ struct Attrib { }; void attrib_clear(Attrib *); -void stat_to_attrib(struct stat *, Attrib *); -void attrib_to_stat(Attrib *, struct stat *); +void stat_to_attrib(const struct stat *, Attrib *); +void attrib_to_stat(const Attrib *, struct stat *); Attrib *decode_attrib(Buffer *); -void encode_attrib(Buffer *, Attrib *); -char *ls_file(char *, struct stat *, int); +void encode_attrib(Buffer *, const Attrib *); +char *ls_file(const char *, const struct stat *, int); const char *fx2txt(int); diff --git a/usr/src/cmd/ssh/include/sftp-glob.h b/usr/src/cmd/ssh/include/sftp-glob.h deleted file mode 100644 index 9d835899ee..0000000000 --- a/usr/src/cmd/ssh/include/sftp-glob.h +++ /dev/null @@ -1,48 +0,0 @@ -/* $OpenBSD: sftp-glob.h,v 1.8 2002/09/11 22:41:50 djm Exp $ */ - -#ifndef _SFTP_GLOB_H -#define _SFTP_GLOB_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * Copyright (c) 2001,2002 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 */ - -#include "sftp-client.h" - -int remote_glob(struct sftp_conn *, const char *, int, - int (*)(const char *, int), glob_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _SFTP_GLOB_H */ diff --git a/usr/src/cmd/ssh/libopenbsd-compat/Makefile.com b/usr/src/cmd/ssh/libopenbsd-compat/Makefile.com index 4528402b14..eb665e83da 100644 --- a/usr/src/cmd/ssh/libopenbsd-compat/Makefile.com +++ b/usr/src/cmd/ssh/libopenbsd-compat/Makefile.com @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -19,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -27,69 +26,70 @@ # cmd/ssh/libopenbsd-compat/Makefile.com # -LIBRARY= libopenbsd-compat.a -VERS= .1 +LIBRARY = libopenbsd-compat.a +VERS = .1 -OBJECTS= \ - bsd-arc4random.o \ - bsd-cray.o \ - bsd-cygwin_util.o \ - bsd-getpeereid.o \ - bsd-misc.o \ - bsd-nextstep.o \ - bsd-snprintf.o \ - bsd-waitpid.o \ - fake-getaddrinfo.o \ - fake-getnameinfo.o \ - xmmap.o \ - base64.o \ - bindresvport.o \ - daemon.o \ - dirname.o \ - getcwd.o \ - getgrouplist.o \ - getopt.o \ - glob.o \ - inet_aton.o \ - inet_ntoa.o \ - inet_ntop.o \ - mktemp.o \ - readpassphrase.o \ - realpath.o \ - rresvport.o \ - setenv.o \ - setproctitle.o \ - sigact.o \ - strlcat.o \ - strlcpy.o \ - strmode.o \ - strsep.o \ - port-irix.o \ - port-aix.o +OBJECTS = \ + bsd-arc4random.o \ + bsd-cray.o \ + bsd-cygwin_util.o \ + bsd-getpeereid.o \ + bsd-misc.o \ + bsd-nextstep.o \ + bsd-asprintf.o \ + bsd-snprintf.o \ + bsd-waitpid.o \ + fake-getaddrinfo.o \ + fake-getnameinfo.o \ + xmmap.o \ + base64.o \ + bindresvport.o \ + daemon.o \ + dirname.o \ + getcwd.o \ + getgrouplist.o \ + getopt.o \ + glob.o \ + inet_aton.o \ + inet_ntoa.o \ + inet_ntop.o \ + mktemp.o \ + readpassphrase.o \ + realpath.o \ + rresvport.o \ + setenv.o \ + setproctitle.o \ + sigact.o \ + strlcat.o \ + strlcpy.o \ + strmode.o \ + strsep.o \ + port-irix.o \ + port-aix.o include $(SRC)/lib/Makefile.lib -BUILD.AR= $(RM) $@ ; $(AR) $(ARFLAGS) $@ $(AROBJS) +BUILD.AR = $(RM) $@ ; $(AR) $(ARFLAGS) $@ $(AROBJS) -SRCDIR= ../common -SRCS= $(OBJECTS:%.o=../common/%.c) +SRCDIR = ../common +SRCS = $(OBJECTS:%.o=../common/%.c) LIBS = $(LIBRARY) $(LINTLIB) -$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) -POFILE_DIR= ../.. +POFILE_DIR = ../.. .KEEP_STATE: -all: $(LIBS) +all: $(LIBS) # lint requires the (non-installed) lint library -lint: $(LINTLIB) .WAIT lintcheck +lint: $(LINTLIB) .WAIT lintcheck include $(SRC)/lib/Makefile.targ -objs/%.o: $(SRCDIR)/%.c +objs/%.o: $(SRCDIR)/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) diff --git a/usr/src/cmd/ssh/libopenbsd-compat/common/bsd-asprintf.c b/usr/src/cmd/ssh/libopenbsd-compat/common/bsd-asprintf.c new file mode 100644 index 0000000000..f06e7415de --- /dev/null +++ b/usr/src/cmd/ssh/libopenbsd-compat/common/bsd-asprintf.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004 Darren Tucker. + * + * Based originally on asprintf.c from OpenBSD: + * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> + * + * 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. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "includes.h" + +#ifndef HAVE_VASPRINTF + +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> + +#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 + +#define INIT_SZ 128 + +int +vasprintf(char **str, const char *fmt, va_list ap) +{ + int ret = -1; + va_list ap2; + char *string, *newstr; + size_t len; + + VA_COPY(ap2, ap); + if ((string = malloc(INIT_SZ)) == NULL) + goto fail; + + ret = vsnprintf(string, INIT_SZ, fmt, ap2); + if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */ + *str = string; + } else if (ret == INT_MAX || ret < 0) { /* Bad length */ + free(string); + goto fail; + } else { /* bigger than initial, realloc allowing for nul */ + len = (size_t)ret + 1; + if ((newstr = realloc(string, len)) == NULL) { + free(string); + goto fail; + } else { + va_end(ap2); + VA_COPY(ap2, ap); + ret = vsnprintf(newstr, len, fmt, ap2); + if (ret >= 0 && (size_t)ret < len) { + *str = newstr; + } else { /* failed with realloc'ed string, give up */ + free(newstr); + goto fail; + } + } + } + va_end(ap2); + return (ret); + +fail: + *str = NULL; + errno = ENOMEM; + va_end(ap2); + return (-1); +} +#endif + +#ifndef HAVE_ASPRINTF +int +asprintf(char **str, const char *fmt, ...) +{ + va_list ap; + int ret; + + *str = NULL; + va_start(ap, fmt); + ret = vasprintf(str, fmt, ap); + va_end(ap); + + return (ret); +} +#endif diff --git a/usr/src/cmd/ssh/libssh/Makefile.com b/usr/src/cmd/ssh/libssh/Makefile.com index b8f4d30de9..ed02ab1de2 100644 --- a/usr/src/cmd/ssh/libssh/Makefile.com +++ b/usr/src/cmd/ssh/libssh/Makefile.com @@ -24,94 +24,95 @@ # ident "%Z%%M% %I% %E% SMI" # -LIBRARY= libssh.a -VERS= .1 +LIBRARY = libssh.a +VERS = .1 -OBJECTS= \ - atomicio.o \ - authfd.o \ - authfile.o \ - bufaux.o \ - buffer.o \ - canohost.o \ - channels.o \ - cipher.o \ - cipher-ctr.o \ - compat.o \ - compress.o \ - crc32.o \ - deattack.o \ - dh.o \ - dispatch.o \ - fatal.o \ - g11n.o \ - mac.o \ - msg.o \ - hostfile.o \ - key.o \ - kex.o \ - kexdh.o \ - kexdhc.o \ - kexdhs.o \ - kexgex.o \ - kexgexc.o \ - kexgexs.o \ - kexgssc.o \ - kexgsss.o \ - log.o \ - match.o \ - misc.o \ - mpaux.o \ - nchan.o \ - packet.o \ - radix.o \ - entropy.o \ - readpass.o \ - rsa.o \ - scard.o \ - scard-opensc.o \ - ssh-dss.o \ - ssh-gss.o \ - ssh-rsa.o \ - tildexpand.o \ - ttymodes.o \ - uidswap.o \ - uuencode.o \ - xlist.o \ - xmalloc.o \ - monitor_wrap.o \ - monitor_fdpass.o \ - readconf.o \ - sftp-common.o \ - proxy-io.o +OBJECTS = \ + atomicio.o \ + authfd.o \ + authfile.o \ + bufaux.o \ + buffer.o \ + canohost.o \ + channels.o \ + cipher.o \ + cipher-ctr.o \ + compat.o \ + compress.o \ + crc32.o \ + deattack.o \ + dh.o \ + dispatch.o \ + fatal.o \ + g11n.o \ + mac.o \ + msg.o \ + hostfile.o \ + key.o \ + kex.o \ + kexdh.o \ + kexdhc.o \ + kexdhs.o \ + kexgex.o \ + kexgexc.o \ + kexgexs.o \ + kexgssc.o \ + kexgsss.o \ + log.o \ + match.o \ + misc.o \ + mpaux.o \ + nchan.o \ + packet.o \ + progressmeter.o \ + radix.o \ + entropy.o \ + readpass.o \ + rsa.o \ + scard.o \ + scard-opensc.o \ + ssh-dss.o \ + ssh-gss.o \ + ssh-rsa.o \ + tildexpand.o \ + ttymodes.o \ + uidswap.o \ + uuencode.o \ + xlist.o \ + xmalloc.o \ + monitor_wrap.o \ + monitor_fdpass.o \ + readconf.o \ + sftp-common.o \ + proxy-io.o include $(SRC)/lib/Makefile.lib -BUILD.AR= $(RM) $@ ; $(AR) $(ARFLAGS) $@ $(AROBJS) +BUILD.AR = $(RM) $@ ; $(AR) $(ARFLAGS) $@ $(AROBJS) -SRCDIR= ../common -SRCS= $(OBJECTS:%.o=../common/%.c) +SRCDIR = ../common +SRCS = $(OBJECTS:%.o=../common/%.c) LIBS = $(LIBRARY) $(LINTLIB) # definitions for lint # Until libz is compiled against unsigned uid/gid ON bits. -#LINTFLAGS += $(OPENSSL_LDFLAGS) -lcrypto -lz -lsocket -lnsl -lc -LINTFLAGS += $(OPENSSL_LDFLAGS) -lcrypto -lsocket -lnsl -lc -$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) +#LINTFLAGS += $(OPENSSL_LDFLAGS) -lcrypto -lz -lsocket -lnsl -lc +LINTFLAGS += $(OPENSSL_LDFLAGS) -lcrypto -lsocket -lnsl -lc +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) -POFILE_DIR= ../.. +POFILE_DIR = ../.. .KEEP_STATE: -all: $(LIBS) +all: $(LIBS) # lint requires the (not installed) lint library -lint: $(LINTLIB) .WAIT lintcheck +lint: $(LINTLIB) .WAIT lintcheck include $(SRC)/lib/Makefile.targ -objs/%.o: $(SRCDIR)/%.c +objs/%.o: $(SRCDIR)/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) diff --git a/usr/src/cmd/ssh/libssh/common/atomicio.c b/usr/src/cmd/ssh/libssh/common/atomicio.c index 806876e24e..f4a7945702 100644 --- a/usr/src/cmd/ssh/libssh/common/atomicio.c +++ b/usr/src/cmd/ssh/libssh/common/atomicio.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * All rights reserved. * @@ -62,3 +64,55 @@ atomicio(f, fd, _s, n) } return (pos); } + +/* + * ensure all of data on socket comes through. f==readv || f==writev + */ +size_t +atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, + const struct iovec *_iov, int iovcnt) +{ + size_t pos = 0, rem; + ssize_t res; + struct iovec iov_array[IOV_MAX], *iov = iov_array; + + if (iovcnt > IOV_MAX) { + errno = EINVAL; + return 0; + } + /* Make a copy of the iov array because we may modify it below */ + memcpy(iov, _iov, iovcnt * sizeof(*_iov)); + + for (; iovcnt > 0 && iov[0].iov_len > 0;) { + res = (f) (fd, iov, iovcnt); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + return 0; + case 0: + errno = EPIPE; + return pos; + default: + rem = (size_t)res; + pos += rem; + /* skip completed iov entries */ + while (iovcnt > 0 && rem >= iov[0].iov_len) { + rem -= iov[0].iov_len; + iov++; + iovcnt--; + } + /* This shouldn't happen... */ + if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { + errno = EFAULT; + return 0; + } + if (iovcnt == 0) + break; + /* update pointer in partially complete iov */ + iov[0].iov_base = ((char *)iov[0].iov_base) + rem; + iov[0].iov_len -= rem; + } + } + return pos; +} diff --git a/usr/src/cmd/ssh/libssh/common/buffer.c b/usr/src/cmd/ssh/libssh/common/buffer.c index 9d95851d68..45d6860157 100644 --- a/usr/src/cmd/ssh/libssh/common/buffer.c +++ b/usr/src/cmd/ssh/libssh/common/buffer.c @@ -11,15 +11,20 @@ * called by a name other than "ssh" or "Secure Shell". */ -#include "includes.h" -RCSID("$OpenBSD: buffer.c,v 1.23 2005/03/14 11:46:56 markus Exp $"); +/* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt Exp $ */ #pragma ident "%Z%%M% %I% %E% SMI" +#include "includes.h" + #include "xmalloc.h" #include "buffer.h" #include "log.h" +#define BUFFER_MAX_CHUNK 0x100000 +#define BUFFER_MAX_LEN 0xa00000 +#define BUFFER_ALLOCSZ 0x008000 + /* Initializes the buffer structure. */ void @@ -68,6 +73,23 @@ buffer_append(Buffer *buffer, const void *data, u_int len) memcpy(p, data, len); } +static int +buffer_compact(Buffer *buffer) +{ + /* + * If the buffer is quite empty, but all data is at the end, move the + * data to the beginning. + */ + if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { + memmove(buffer->buf, buffer->buf + buffer->offset, + buffer->end - buffer->offset); + buffer->end -= buffer->offset; + buffer->offset = 0; + return (1); + } + return (0); +} + /* * Appends space to the buffer, expanding the buffer if necessary. This does * not actually copy the data into the buffer, but instead returns a pointer @@ -95,20 +117,13 @@ restart: buffer->end += len; return p; } - /* - * If the buffer is quite empty, but all data is at the end, move the - * data to the beginning and retry. - */ - if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { - memmove(buffer->buf, buffer->buf + buffer->offset, - buffer->end - buffer->offset); - buffer->end -= buffer->offset; - buffer->offset = 0; + + /* Compact data back to the start of the buffer if necessary */ + if (buffer_compact(buffer)) goto restart; - } + /* Increase the size of the buffer and retry. */ - - newlen = buffer->alloc + len + 32768; + newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); if (newlen > BUFFER_MAX_LEN) fatal("buffer_append_space: alloc %u not supported", newlen); @@ -118,6 +133,27 @@ restart: /* NOTREACHED */ } +/* + * Check whether an allocation of 'len' will fit in the buffer + * This must follow the same math as buffer_append_space + */ +int +buffer_check_alloc(Buffer *buffer, u_int len) +{ + if (buffer->offset == buffer->end) { + buffer->offset = 0; + buffer->end = 0; + } + restart: + if (buffer->end + len < buffer->alloc) + return (1); + if (buffer_compact(buffer)) + goto restart; + if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN) + return (1); + return (0); +} + /* Returns the number of bytes of data in the buffer. */ u_int diff --git a/usr/src/cmd/ssh/libssh/common/llib-lssh b/usr/src/cmd/ssh/libssh/common/llib-lssh index 321ed7d2e3..f827580891 100644 --- a/usr/src/cmd/ssh/libssh/common/llib-lssh +++ b/usr/src/cmd/ssh/libssh/common/llib-lssh @@ -5,9 +5,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -22,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -110,8 +109,6 @@ #include <setproctitle.h> #include <sftp-common.h> #include <sftp.h> -#include <sftp-int.h> -#include <sftp-glob.h> #include <sftp-client.h> #include <sigact.h> #include <ssh1.h> diff --git a/usr/src/cmd/ssh/libssh/common/misc.c b/usr/src/cmd/ssh/libssh/common/misc.c index 9fe8d8c1b8..21b683c3cd 100644 --- a/usr/src/cmd/ssh/libssh/common/misc.c +++ b/usr/src/cmd/ssh/libssh/common/misc.c @@ -363,6 +363,26 @@ addargs(arglist *args, char *fmt, ...) } void +replacearg(arglist *args, u_int which, char *fmt, ...) +{ + va_list ap; + char *cp; + int r; + + va_start(ap, fmt); + r = vasprintf(&cp, fmt, ap); + va_end(ap); + if (r == -1) + fatal("replacearg: argument too long"); + + if (which >= args->num) + fatal("replacearg: tried to replace invalid arg %d >= %d", + which, args->num); + xfree(args->list[which]); + args->list[which] = cp; +} + +void freeargs(arglist *args) { u_int i; @@ -376,6 +396,32 @@ freeargs(arglist *args) } } +/* + * Ensure that file descriptors 0, 1 and 2 are open or directed to /dev/null, + * do not touch those that are already open. + */ +void +sanitise_stdfd(void) +{ + int nullfd, dupfd; + + if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { + fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); + exit(1); + } + while (++dupfd <= 2) { + /* Only clobber closed fds */ + if (fcntl(dupfd, F_GETFL, 0) >= 0) + continue; + if (dup2(nullfd, dupfd) == -1) { + fprintf(stderr, "dup2: %s", strerror(errno)); + exit(1); + } + } + if (nullfd > 2) + close(nullfd); +} + char * tohex(const void *vp, size_t l) { @@ -395,6 +441,86 @@ tohex(const void *vp, size_t l) return (r); } +u_int64_t +get_u64(const void *vp) +{ + const u_char *p = (const u_char *)vp; + u_int64_t v; + + v = (u_int64_t)p[0] << 56; + v |= (u_int64_t)p[1] << 48; + v |= (u_int64_t)p[2] << 40; + v |= (u_int64_t)p[3] << 32; + v |= (u_int64_t)p[4] << 24; + v |= (u_int64_t)p[5] << 16; + v |= (u_int64_t)p[6] << 8; + v |= (u_int64_t)p[7]; + + return (v); +} + +u_int32_t +get_u32(const void *vp) +{ + const u_char *p = (const u_char *)vp; + u_int32_t v; + + v = (u_int32_t)p[0] << 24; + v |= (u_int32_t)p[1] << 16; + v |= (u_int32_t)p[2] << 8; + v |= (u_int32_t)p[3]; + + return (v); +} + +u_int16_t +get_u16(const void *vp) +{ + const u_char *p = (const u_char *)vp; + u_int16_t v; + + v = (u_int16_t)p[0] << 8; + v |= (u_int16_t)p[1]; + + return (v); +} + +void +put_u64(void *vp, u_int64_t v) +{ + u_char *p = (u_char *)vp; + + p[0] = (u_char)(v >> 56) & 0xff; + p[1] = (u_char)(v >> 48) & 0xff; + p[2] = (u_char)(v >> 40) & 0xff; + p[3] = (u_char)(v >> 32) & 0xff; + p[4] = (u_char)(v >> 24) & 0xff; + p[5] = (u_char)(v >> 16) & 0xff; + p[6] = (u_char)(v >> 8) & 0xff; + p[7] = (u_char)v & 0xff; +} + +void +put_u32(void *vp, u_int32_t v) +{ + u_char *p = (u_char *)vp; + + p[0] = (u_char)(v >> 24) & 0xff; + p[1] = (u_char)(v >> 16) & 0xff; + p[2] = (u_char)(v >> 8) & 0xff; + p[3] = (u_char)v & 0xff; +} + + +void +put_u16(void *vp, u_int16_t v) +{ + u_char *p = (u_char *)vp; + + p[0] = (u_char)(v >> 8) & 0xff; + p[1] = (u_char)v & 0xff; +} + mysig_t mysignal(int sig, mysig_t act) { diff --git a/usr/src/cmd/ssh/libssh/common/progressmeter.c b/usr/src/cmd/ssh/libssh/common/progressmeter.c new file mode 100644 index 0000000000..65d28fb596 --- /dev/null +++ b/usr/src/cmd/ssh/libssh/common/progressmeter.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2003 Nils Nordman. 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. + */ + +/* $OpenBSD: progressmeter.c,v 1.37 2006/08/03 03:34:42 deraadt Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "includes.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/uio.h> + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "progressmeter.h" +#include "atomicio.h" +#include "misc.h" + +#define DEFAULT_WINSIZE 80 +#define MAX_WINSIZE 512 +#define PADDING 1 /* padding between the progress indicators */ +#define UPDATE_INTERVAL 1 /* update the progress meter every second */ +#define STALL_TIME 5 /* we're stalled after this many seconds */ + +/* determines whether we can output to the terminal */ +static int can_output(void); + +/* formats and inserts the specified size into the given buffer */ +static void format_size(char *, int, off_t); +static void format_rate(char *, int, off_t); + +/* window resizing */ +static void sig_winch(int); +static void setscreensize(void); + +/* updates the progressmeter to reflect the current state of the transfer */ +void refresh_progress_meter(void); + +/* signal handler for updating the progress meter */ +static void update_progress_meter(int); + +static time_t start; /* start progress */ +static time_t last_update; /* last progress update */ +static char *file; /* name of the file being transferred */ +static off_t end_pos; /* ending position of transfer */ +static off_t cur_pos; /* transfer position as of last refresh */ +static volatile off_t *counter; /* progress counter */ +static long stalled; /* how long we have been stalled */ +static int bytes_per_second; /* current speed in bytes per second */ +static int win_size; /* terminal window size */ +static volatile sig_atomic_t win_resized; /* for window resizing */ + +/* units for format_size */ +static const char unit[] = " KMGT"; + +static int +can_output(void) +{ + return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); +} + +static void +format_rate(char *buf, int size, off_t bytes) +{ + int i; + + bytes *= 100; + for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++) + bytes = (bytes + 512) / 1024; + if (i == 0) { + i++; + bytes = (bytes + 512) / 1024; + } + snprintf(buf, size, "%3lld.%1lld%c%s", + (long long) (bytes + 5) / 100, + (long long) (bytes + 5) / 10 % 10, + unit[i], + i ? "B" : " "); +} + +static void +format_size(char *buf, int size, off_t bytes) +{ + int i; + + for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) + bytes = (bytes + 512) / 1024; + snprintf(buf, size, "%4lld%c%s", + (long long) bytes, + unit[i], + i ? "B" : " "); +} + +void +refresh_progress_meter(void) +{ + char buf[MAX_WINSIZE + 1]; + time_t now; + off_t transferred; + double elapsed; + int percent; + off_t bytes_left; + int cur_speed; + int hours, minutes, seconds; + int i, len; + int file_len; + + transferred = *counter - cur_pos; + cur_pos = *counter; + now = time(NULL); + bytes_left = end_pos - cur_pos; + + if (bytes_left > 0) + elapsed = now - last_update; + else { + elapsed = now - start; + /* Calculate true total speed when done */ + transferred = end_pos; + bytes_per_second = 0; + } + + /* calculate speed */ + if (elapsed != 0) + cur_speed = (int)(transferred / elapsed); + else + cur_speed = transferred; + +#define AGE_FACTOR 0.9 + if (bytes_per_second != 0) { + bytes_per_second = (int)((bytes_per_second * AGE_FACTOR) + + (cur_speed * (1.0 - AGE_FACTOR))); + } else + bytes_per_second = cur_speed; + + /* filename */ + buf[0] = '\0'; + file_len = win_size - 35; + if (file_len > 0) { + len = snprintf(buf, file_len + 1, "\r%s", file); + if (len < 0) + len = 0; + if (len >= file_len + 1) + len = file_len; + for (i = len; i < file_len; i++) + buf[i] = ' '; + buf[file_len] = '\0'; + } + + /* percent of transfer done */ + if (end_pos != 0) + percent = (int)(((float)cur_pos / end_pos) * 100); + else + percent = 100; + snprintf(buf + strlen(buf), win_size - strlen(buf), + " %3d%% ", percent); + + /* amount transferred */ + format_size(buf + strlen(buf), win_size - strlen(buf), + cur_pos); + strlcat(buf, " ", win_size); + + /* bandwidth usage */ + format_rate(buf + strlen(buf), win_size - strlen(buf), + (off_t)bytes_per_second); + strlcat(buf, "/s ", win_size); + + /* ETA */ + if (!transferred) + stalled += elapsed; + else + stalled = 0; + + if (stalled >= STALL_TIME) + strlcat(buf, "- stalled -", win_size); + else if (bytes_per_second == 0 && bytes_left) + strlcat(buf, " --:-- ETA", win_size); + else { + if (bytes_left > 0) + seconds = bytes_left / bytes_per_second; + else + seconds = (int)elapsed; + + hours = seconds / 3600; + seconds -= hours * 3600; + minutes = seconds / 60; + seconds -= minutes * 60; + + if (hours != 0) + snprintf(buf + strlen(buf), win_size - strlen(buf), + "%d:%02d:%02d", hours, minutes, seconds); + else + snprintf(buf + strlen(buf), win_size - strlen(buf), + " %02d:%02d", minutes, seconds); + + if (bytes_left > 0) + strlcat(buf, " ETA", win_size); + else + strlcat(buf, " ", win_size); + } + + atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); + last_update = now; +} + +/*ARGSUSED*/ +static void +update_progress_meter(int ignore) +{ + int save_errno; + + save_errno = errno; + + if (win_resized) { + setscreensize(); + win_resized = 0; + } + if (can_output()) + refresh_progress_meter(); + + signal(SIGALRM, update_progress_meter); + alarm(UPDATE_INTERVAL); + errno = save_errno; +} + +void +start_progress_meter(char *f, off_t filesize, off_t *ctr) +{ + start = last_update = time(NULL); + file = f; + end_pos = filesize; + cur_pos = 0; + counter = ctr; + stalled = 0; + bytes_per_second = 0; + + setscreensize(); + if (can_output()) + refresh_progress_meter(); + + signal(SIGALRM, update_progress_meter); + signal(SIGWINCH, sig_winch); + alarm(UPDATE_INTERVAL); +} + +void +stop_progress_meter(void) +{ + alarm(0); + + if (!can_output()) + return; + + /* Ensure we complete the progress */ + if (cur_pos != end_pos) + refresh_progress_meter(); + + atomicio(vwrite, STDOUT_FILENO, "\n", 1); +} + +/*ARGSUSED*/ +static void +sig_winch(int sig) +{ + win_resized = 1; +} + +static void +setscreensize(void) +{ + struct winsize winsize; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && + winsize.ws_col != 0) { + if (winsize.ws_col > MAX_WINSIZE) + win_size = MAX_WINSIZE; + else + win_size = winsize.ws_col; + } else + win_size = DEFAULT_WINSIZE; + win_size += 1; /* trailing \0 */ +} diff --git a/usr/src/cmd/ssh/libssh/common/sftp-common.c b/usr/src/cmd/ssh/libssh/common/sftp-common.c index 7cbe72c44c..ead9e2406f 100644 --- a/usr/src/cmd/ssh/libssh/common/sftp-common.c +++ b/usr/src/cmd/ssh/libssh/common/sftp-common.c @@ -23,15 +23,27 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "includes.h" -RCSID("$OpenBSD: sftp-common.c,v 1.7 2002/09/11 22:41:50 djm Exp $"); +/* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */ #pragma ident "%Z%%M% %I% %E% SMI" +#include "includes.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <stdarg.h> + +#include "xmalloc.h" #include "buffer.h" #include "bufaux.h" #include "log.h" -#include "xmalloc.h" #include "sftp.h" #include "sftp-common.h" @@ -51,7 +63,7 @@ attrib_clear(Attrib *a) /* Convert from struct stat to filexfer attribs */ void -stat_to_attrib(struct stat *st, Attrib *a) +stat_to_attrib(const struct stat *st, Attrib *a) { attrib_clear(a); a->flags = 0; @@ -69,7 +81,7 @@ stat_to_attrib(struct stat *st, Attrib *a) /* Convert from filexfer attribs to struct stat */ void -attrib_to_stat(Attrib *a, struct stat *st) +attrib_to_stat(const Attrib *a, struct stat *st) { memset(st, 0, sizeof(*st)); @@ -126,7 +138,7 @@ decode_attrib(Buffer *b) /* Encode attributes to buffer */ void -encode_attrib(Buffer *b, Attrib *a) +encode_attrib(Buffer *b, const Attrib *a) { buffer_put_int(b, a->flags); if (a->flags & SSH2_FILEXFER_ATTR_SIZE) @@ -149,25 +161,25 @@ fx2txt(int status) { switch (status) { case SSH2_FX_OK: - return("No error"); + return(gettext("No error")); case SSH2_FX_EOF: - return("End of file"); + return(gettext("End of file")); case SSH2_FX_NO_SUCH_FILE: - return("No such file or directory"); + return(gettext("No such file or directory")); case SSH2_FX_PERMISSION_DENIED: - return("Permission denied"); + return(gettext("Permission denied")); case SSH2_FX_FAILURE: - return("Failure"); + return(gettext("Failure")); case SSH2_FX_BAD_MESSAGE: - return("Bad message"); + return(gettext("Bad message")); case SSH2_FX_NO_CONNECTION: - return("No connection"); + return(gettext("No connection")); case SSH2_FX_CONNECTION_LOST: - return("Connection lost"); + return(gettext("Connection lost")); case SSH2_FX_OP_UNSUPPORTED: - return("Operation unsupported"); + return(gettext("Operation unsupported")); default: - return("Unknown status"); + return(gettext("Unknown status")); } /* NOTREACHED */ } @@ -176,7 +188,7 @@ fx2txt(int status) * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh */ char * -ls_file(char *name, struct stat *st, int remote) +ls_file(const char *name, const struct stat *st, int remote) { int ulen, glen, sz = 0; struct passwd *pw; @@ -208,8 +220,8 @@ ls_file(char *name, struct stat *st, int remote) tbuf[0] = '\0'; ulen = MAX(strlen(user), 8); glen = MAX(strlen(group), 8); - snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode, - st->st_nlink, ulen, user, glen, group, - (u_int64_t)st->st_size, tbuf, name); + snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, + (u_int)st->st_nlink, ulen, user, glen, group, + (unsigned long long)st->st_size, tbuf, name); return xstrdup(buf); } diff --git a/usr/src/cmd/ssh/sftp-server/Makefile b/usr/src/cmd/ssh/sftp-server/Makefile index 491b0f44b2..4743387ab4 100644 --- a/usr/src/cmd/ssh/sftp-server/Makefile +++ b/usr/src/cmd/ssh/sftp-server/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -19,43 +18,43 @@ # # CDDL HEADER END # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # cmd/ssh/sftp-server/Makefile -PROG= sftp-server +PROG = sftp-server -OBJS = sftp-server.o -SRCS = $(OBJS:.o=.c) +OBJS = sftp-server.o +SRCS = $(OBJS:.o=.c) include ../../Makefile.cmd include ../Makefile.ssh-common -LDLIBS += $(SSH_COMMON_LDLIBS) $(OPENSSL_LDFLAGS) -lcrypto +LDLIBS += $(SSH_COMMON_LDLIBS) -lsocket $(OPENSSL_LDFLAGS) -lcrypto -DYNFLAGS += $(OPENSSL_DYNFLAGS) +DYNFLAGS += $(OPENSSL_DYNFLAGS) -POFILE_DIR= .. +POFILE_DIR = .. .KEEP_STATE: -.PARALLEL: $(OBJS) +.PARALLEL: $(OBJS) -all: $(PROG) +all: $(PROG) -$(PROG): $(OBJS) ../libssh/$(MACH)/libssh.a ../libopenbsd-compat/$(MACH)/libopenbsd-compat.a +$(PROG): $(OBJS) ../libssh/$(MACH)/libssh.a ../libopenbsd-compat/$(MACH)/libopenbsd-compat.a $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS) $(POST_PROCESS) -install: all $(ROOTLIBSSHPROG) $(ROOTLIBSSH) +install: all $(ROOTLIBSSHPROG) $(ROOTLIBSSH) clean: $(RM) -f $(OBJS) $(PROG) -lint: lint_SRCS +lint: lint_SRCS include ../Makefile.msg.targ include ../../Makefile.targ diff --git a/usr/src/cmd/ssh/sftp-server/sftp-server.c b/usr/src/cmd/ssh/sftp-server/sftp-server.c index 6897c1c930..aeef13d013 100644 --- a/usr/src/cmd/ssh/sftp-server/sftp-server.c +++ b/usr/src/cmd/ssh/sftp-server/sftp-server.c @@ -1,57 +1,74 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. + * Copyright (c) 2000-2004 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. + * 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. * - * 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. + * 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. */ -#include "includes.h" -RCSID("$OpenBSD: sftp-server.c,v 1.38 2002/09/11 22:41:50 djm Exp $"); + +/* $OpenBSD: sftp-server.c,v 1.71 2007/01/03 07:22:36 stevesk Exp $ */ #pragma ident "%Z%%M% %I% %E% SMI" +#include "includes.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <pwd.h> +#include <time.h> +#include <unistd.h> +#include <stdarg.h> + +#include "xmalloc.h" #include "buffer.h" #include "bufaux.h" -#include "getput.h" #include "log.h" -#include "xmalloc.h" +#include "misc.h" +#include "uidswap.h" #include "sftp.h" #include "sftp-common.h" -/* helper */ -#define get_int64() buffer_get_int64(&iqueue); -#define get_int() buffer_get_int(&iqueue); -#define get_string(lenp) buffer_get_string(&iqueue, lenp); -#define TRACE debug - #ifdef HAVE___PROGNAME extern char *__progname; #else char *__progname; #endif +/* helper */ +#define get_int64() buffer_get_int64(&iqueue); +#define get_int() buffer_get_int(&iqueue); +#define get_string(lenp) buffer_get_string(&iqueue, lenp); + +static void cleanup_exit(int i); + +/* Our verbosity */ +LogLevel log_level = SYSLOG_LEVEL_ERROR; + +/* Our client */ +struct passwd *pw = NULL; +char *client_addr = NULL; + /* input and output queue */ Buffer iqueue; Buffer oqueue; @@ -59,7 +76,7 @@ Buffer oqueue; /* Version of client */ int version; -/* portable attibutes, etc. */ +/* portable attributes, etc. */ typedef struct Stat Stat; @@ -122,6 +139,33 @@ flags_from_portable(int pflags) return flags; } +static const char * +string_from_portable(int pflags) +{ + static char ret[128]; + + *ret = '\0'; + +#define PAPPEND(str) { \ + if (*ret != '\0') \ + strlcat(ret, ",", sizeof(ret)); \ + strlcat(ret, str, sizeof(ret)); \ + } + + if (pflags & SSH2_FXF_READ) + PAPPEND("READ") + if (pflags & SSH2_FXF_WRITE) + PAPPEND("WRITE") + if (pflags & SSH2_FXF_CREAT) + PAPPEND("CREATE") + if (pflags & SSH2_FXF_TRUNC) + PAPPEND("TRUNCATE") + if (pflags & SSH2_FXF_EXCL) + PAPPEND("EXCL") + + return ret; +} + static Attrib * get_attrib(void) { @@ -136,6 +180,7 @@ struct Handle { DIR *dirp; int fd; char *name; + u_int64_t bytes_read, bytes_write; }; enum { @@ -149,23 +194,24 @@ Handle handles[100]; static void handle_init(void) { - int i; + u_int i; for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) handles[i].use = HANDLE_UNUSED; } static int -handle_new(int use, char *name, int fd, DIR *dirp) +handle_new(int use, const char *name, int fd, DIR *dirp) { - int i; + u_int i; for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) { if (handles[i].use == HANDLE_UNUSED) { handles[i].use = use; handles[i].dirp = dirp; handles[i].fd = fd; - handles[i].name = name; + handles[i].name = xstrdup(name); + handles[i].bytes_read = handles[i].bytes_write = 0; return i; } } @@ -175,7 +221,7 @@ handle_new(int use, char *name, int fd, DIR *dirp) static int handle_is_ok(int i, int type) { - return i >= 0 && i < sizeof(handles)/sizeof(Handle) && + return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) && handles[i].use == type; } @@ -185,19 +231,19 @@ handle_to_string(int handle, char **stringp, int *hlenp) if (stringp == NULL || hlenp == NULL) return -1; *stringp = xmalloc(sizeof(int32_t)); - PUT_32BIT(*stringp, handle); + put_u32(*stringp, handle); *hlenp = sizeof(int32_t); return 0; } static int -handle_from_string(char *handle, u_int hlen) +handle_from_string(const char *handle, u_int hlen) { int val; if (hlen != sizeof(int32_t)) return -1; - val = GET_32BIT(handle); + val = get_u32(handle); if (handle_is_ok(val, HANDLE_FILE) || handle_is_ok(val, HANDLE_DIR)) return val; @@ -229,6 +275,36 @@ handle_to_fd(int handle) return -1; } +static void +handle_update_read(int handle, ssize_t bytes) +{ + if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0) + handles[handle].bytes_read += bytes; +} + +static void +handle_update_write(int handle, ssize_t bytes) +{ + if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0) + handles[handle].bytes_write += bytes; +} + +static u_int64_t +handle_bytes_read(int handle) +{ + if (handle_is_ok(handle, HANDLE_FILE)) + return (handles[handle].bytes_read); + return 0; +} + +static u_int64_t +handle_bytes_write(int handle) +{ + if (handle_is_ok(handle, HANDLE_FILE)) + return (handles[handle].bytes_write); + return 0; +} + static int handle_close(int handle) { @@ -237,15 +313,43 @@ handle_close(int handle) if (handle_is_ok(handle, HANDLE_FILE)) { ret = close(handles[handle].fd); handles[handle].use = HANDLE_UNUSED; + xfree(handles[handle].name); } else if (handle_is_ok(handle, HANDLE_DIR)) { ret = closedir(handles[handle].dirp); handles[handle].use = HANDLE_UNUSED; + xfree(handles[handle].name); } else { errno = ENOENT; } return ret; } +static void +handle_log_close(int handle, char *emsg) +{ + if (handle_is_ok(handle, HANDLE_FILE)) { + log("%s%sclose \"%s\" bytes read %llu written %llu", + emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ", + handle_to_name(handle), + (unsigned long long)handle_bytes_read(handle), + (unsigned long long)handle_bytes_write(handle)); + } else { + log("%s%sclosedir \"%s\"", + emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ", + handle_to_name(handle)); + } +} + +static void +handle_log_exit(void) +{ + u_int i; + + for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) + if (handles[i].use != HANDLE_UNUSED) + handle_log_close(i, "forced"); +} + static int get_handle(void) { @@ -272,10 +376,9 @@ send_msg(Buffer *m) buffer_consume(m, mlen); } -static void -send_status(u_int32_t id, u_int32_t error) +static const char * +status_to_message(u_int32_t status) { - Buffer msg; const char *status_messages[] = { "Success", /* SSH_FX_OK */ "End of file", /* SSH_FX_EOF */ @@ -288,22 +391,31 @@ send_status(u_int32_t id, u_int32_t error) "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ "Unknown error" /* Others */ }; + return (status_messages[MIN(status,SSH2_FX_MAX)]); +} + +static void +send_status(u_int32_t id, u_int32_t status) +{ + Buffer msg; - TRACE("sent status id %u error %u", id, error); + debug3("request %u: sent status %u", id, status); + if (log_level > SYSLOG_LEVEL_VERBOSE || + (status != SSH2_FX_OK && status != SSH2_FX_EOF)) + log("sent status %s", status_to_message(status)); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_STATUS); buffer_put_int(&msg, id); - buffer_put_int(&msg, error); + buffer_put_int(&msg, status); if (version >= 3) { - buffer_put_cstring(&msg, - status_messages[MIN(error,SSH2_FX_MAX)]); + buffer_put_cstring(&msg, status_to_message(status)); buffer_put_cstring(&msg, ""); } send_msg(&msg); buffer_free(&msg); } static void -send_data_or_handle(char type, u_int32_t id, char *data, int dlen) +send_data_or_handle(char type, u_int32_t id, const char *data, int dlen) { Buffer msg; @@ -316,9 +428,9 @@ send_data_or_handle(char type, u_int32_t id, char *data, int dlen) } static void -send_data(u_int32_t id, char *data, int dlen) +send_data(u_int32_t id, const char *data, int dlen) { - TRACE("sent data id %u len %d", id, dlen); + debug("request %u: sent data len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); } @@ -329,13 +441,13 @@ send_handle(u_int32_t id, int handle) int hlen; handle_to_string(handle, &string, &hlen); - TRACE("sent handle id %u handle %d", id, handle); + debug("request %u: sent handle handle %d", id, handle); send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); xfree(string); } static void -send_names(u_int32_t id, int count, Stat *stats) +send_names(u_int32_t id, int count, const Stat *stats) { Buffer msg; int i; @@ -344,7 +456,7 @@ send_names(u_int32_t id, int count, Stat *stats) buffer_put_char(&msg, SSH2_FXP_NAME); buffer_put_int(&msg, id); buffer_put_int(&msg, count); - TRACE("sent names id %u count %d", id, count); + debug("request %u: sent names count %d", id, count); for (i = 0; i < count; i++) { buffer_put_cstring(&msg, stats[i].name); buffer_put_cstring(&msg, stats[i].long_name); @@ -355,11 +467,11 @@ send_names(u_int32_t id, int count, Stat *stats) } static void -send_attrib(u_int32_t id, Attrib *a) +send_attrib(u_int32_t id, const Attrib *a) { Buffer msg; - TRACE("sent attrib id %u have 0x%x", id, a->flags); + debug("request %u: sent attrib have 0x%x", id, a->flags); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_ATTRS); buffer_put_int(&msg, id); @@ -376,7 +488,7 @@ process_init(void) Buffer msg; version = get_int(); - TRACE("client version %d", version); + verbose("received client version %d", version); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_VERSION); buffer_put_int(&msg, SSH2_FILEXFER_VERSION); @@ -395,15 +507,17 @@ process_open(void) id = get_int(); name = get_string(NULL); pflags = get_int(); /* portable flags */ + debug3("request %u: open flags %d", id, pflags); a = get_attrib(); flags = flags_from_portable(pflags); mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; - TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); + log("open \"%s\" flags %s mode 0%o", + name, string_from_portable(pflags), mode); fd = open(name, flags, mode); if (fd < 0) { status = errno_to_portable(errno); } else { - handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL); + handle = handle_new(HANDLE_FILE, name, fd, NULL); if (handle < 0) { close(fd); } else { @@ -424,7 +538,8 @@ process_close(void) id = get_int(); handle = get_handle(); - TRACE("close id %u handle %d", id, handle); + debug3("request %u: close handle %u", id, handle); + handle_log_close(handle, NULL); ret = handle_close(handle); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -443,11 +558,11 @@ process_read(void) off = get_int64(); len = get_int(); - TRACE("read id %u handle %d off %llu len %d", id, handle, - (u_int64_t)off, len); + debug("request %u: read \"%s\" (handle %d) off %llu len %d", + id, handle_to_name(handle), handle, (unsigned long long)off, len); if (len > sizeof buf) { len = sizeof buf; - log("read change len %d", len); + debug2("read change len %d", len); } fd = handle_to_fd(handle); if (fd >= 0) { @@ -463,6 +578,7 @@ process_read(void) } else { send_data(id, buf, ret); status = SSH2_FX_OK; + handle_update_read(handle, ret); } } } @@ -484,8 +600,8 @@ process_write(void) off = get_int64(); data = get_string(&len); - TRACE("write id %u handle %d off %llu len %d", id, handle, - (u_int64_t)off, len); + debug("request %u: write \"%s\" (handle %d) off %llu len %d", + id, handle_to_name(handle), handle, (unsigned long long)off, len); fd = handle_to_fd(handle); if (fd >= 0) { if (lseek(fd, off, SEEK_SET) < 0) { @@ -494,13 +610,14 @@ process_write(void) } else { /* XXX ATOMICIO ? */ ret = write(fd, data, len); - if (ret == -1) { + if (ret < 0) { error("process_write: write failed"); status = errno_to_portable(errno); - } else if (ret == len) { + } else if ((size_t)ret == len) { status = SSH2_FX_OK; + handle_update_write(handle, ret); } else { - log("nothing at all written"); + debug2("nothing at all written"); } } } @@ -519,7 +636,8 @@ process_do_stat(int do_lstat) id = get_int(); name = get_string(NULL); - TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); + debug3("request %u: %sstat", id, do_lstat ? "l" : ""); + verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name); ret = do_lstat ? lstat(name, &st) : stat(name, &st); if (ret < 0) { status = errno_to_portable(errno); @@ -555,9 +673,10 @@ process_fstat(void) id = get_int(); handle = get_handle(); - TRACE("fstat id %u handle %d", id, handle); + debug("request %u: fstat \"%s\" (handle %u)", + id, handle_to_name(handle), handle); fd = handle_to_fd(handle); - if (fd >= 0) { + if (fd >= 0) { ret = fstat(fd, &st); if (ret < 0) { status = errno_to_portable(errno); @@ -572,7 +691,7 @@ process_fstat(void) } static struct timeval * -attrib_to_tv(Attrib *a) +attrib_to_tv(const Attrib *a) { static struct timeval tv[2]; @@ -594,23 +713,34 @@ process_setstat(void) id = get_int(); name = get_string(NULL); a = get_attrib(); - TRACE("setstat id %u name %s", id, name); + debug("request %u: setstat name \"%s\"", id, name); if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + log("set \"%s\" size %llu", + name, (unsigned long long)a->size); ret = truncate(name, a->size); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + log("set \"%s\" mode %04o", name, a->perm); ret = chmod(name, a->perm & 0777); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + char buf[64]; + time_t t = a->mtime; + + strftime(buf, sizeof(buf), "%Y" "%m%d-%H:%M:%S", + localtime(&t)); + log("set \"%s\" modtime %s", name, buf); ret = utimes(name, attrib_to_tv(a)); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + log("set \"%s\" owner %lu group %lu", name, + (u_long)a->uid, (u_long)a->gid); ret = chown(name, a->uid, a->gid); if (ret == -1) status = errno_to_portable(errno); @@ -626,23 +756,26 @@ process_fsetstat(void) u_int32_t id; int handle, fd, ret; int status = SSH2_FX_OK; - char *name; id = get_int(); handle = get_handle(); a = get_attrib(); - TRACE("fsetstat id %u handle %d", id, handle); + debug("request %u: fsetstat handle %d", id, handle); fd = handle_to_fd(handle); - name = handle_to_name(handle); - if (fd < 0 || name == NULL) { + if (fd < 0) { status = SSH2_FX_FAILURE; } else { + char *name = handle_to_name(handle); + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + log("set \"%s\" size %llu", + name, (unsigned long long)a->size); ret = ftruncate(fd, a->size); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + log("set \"%s\" mode %04o", name, a->perm); #ifdef HAVE_FCHMOD ret = fchmod(fd, a->perm & 0777); #else @@ -652,6 +785,12 @@ process_fsetstat(void) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + char buf[64]; + time_t t = a->mtime; + + strftime(buf, sizeof(buf), "%Y" "%m%d-%H:%M:%S", + localtime(&t)); + log("set \"%s\" modtime %s", name, buf); #ifdef HAVE_FUTIMES ret = futimes(fd, attrib_to_tv(a)); #else @@ -661,6 +800,8 @@ process_fsetstat(void) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + log("set \"%s\" owner %lu group %lu", name, + (u_long)a->uid, (u_long)a->gid); #ifdef HAVE_FCHOWN ret = fchown(fd, a->uid, a->gid); #else @@ -683,12 +824,13 @@ process_opendir(void) id = get_int(); path = get_string(NULL); - TRACE("opendir id %u path %s", id, path); + debug3("request %u: opendir", id); + log("opendir \"%s\"", path); dirp = opendir(path); if (dirp == NULL) { status = errno_to_portable(errno); } else { - handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); + handle = handle_new(HANDLE_DIR, path, 0, dirp); if (handle < 0) { closedir(dirp); } else { @@ -713,18 +855,19 @@ process_readdir(void) id = get_int(); handle = get_handle(); - TRACE("readdir id %u handle %d", id, handle); + debug("request %u: readdir \"%s\" (handle %d)", id, + handle_to_name(handle), handle); dirp = handle_to_dir(handle); path = handle_to_name(handle); if (dirp == NULL || path == NULL) { send_status(id, SSH2_FX_FAILURE); } else { struct stat st; - char pathname[1024]; + char pathname[MAXPATHLEN]; Stat *stats; int nstats = 10, count = 0, i; - stats = xmalloc(nstats * sizeof(Stat)); + stats = xcalloc(nstats, sizeof(Stat)); while ((dp = readdir(dirp)) != NULL) { if (count >= nstats) { nstats *= 2; @@ -767,7 +910,8 @@ process_remove(void) id = get_int(); name = get_string(NULL); - TRACE("remove id %u name %s", id, name); + debug3("request %u: remove", id); + log("remove name \"%s\"", name); ret = unlink(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -787,7 +931,8 @@ process_mkdir(void) a = get_attrib(); mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm & 0777 : 0777; - TRACE("mkdir id %u name %s mode 0%o", id, name, mode); + debug3("request %u: mkdir", id); + log("mkdir name \"%s\" mode 0%o", name, mode); ret = mkdir(name, mode); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -803,7 +948,8 @@ process_rmdir(void) id = get_int(); name = get_string(NULL); - TRACE("rmdir id %u name %s", id, name); + debug3("request %u: rmdir", id); + log("rmdir name \"%s\"", name); ret = rmdir(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -823,7 +969,8 @@ process_realpath(void) xfree(path); path = xstrdup("."); } - TRACE("realpath id %u path %s", id, path); + debug3("request %u: realpath", id); + verbose("realpath \"%s\"", path); if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { @@ -839,18 +986,53 @@ static void process_rename(void) { u_int32_t id; - struct stat st; char *oldpath, *newpath; - int ret, status = SSH2_FX_FAILURE; + int status; + struct stat sb; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); - TRACE("rename id %u old %s new %s", id, oldpath, newpath); - /* fail if 'newpath' exists */ - if (stat(newpath, &st) == -1) { - ret = rename(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + debug3("request %u: rename", id); + log("rename old \"%s\" new \"%s\"", oldpath, newpath); + status = SSH2_FX_FAILURE; + if (lstat(oldpath, &sb) == -1) + status = errno_to_portable(errno); + else if (S_ISREG(sb.st_mode)) { + /* Race-free rename of regular files */ + if (link(oldpath, newpath) == -1) { + if (errno == EOPNOTSUPP +#ifdef LINK_OPNOTSUPP_ERRNO + || errno == LINK_OPNOTSUPP_ERRNO +#endif + ) { + struct stat st; + + /* + * fs doesn't support links, so fall back to + * stat+rename. This is racy. + */ + if (stat(newpath, &st) == -1) { + if (rename(oldpath, newpath) == -1) + status = + errno_to_portable(errno); + else + status = SSH2_FX_OK; + } + } else { + status = errno_to_portable(errno); + } + } else if (unlink(oldpath) == -1) { + status = errno_to_portable(errno); + /* clean spare link */ + unlink(newpath); + } else + status = SSH2_FX_OK; + } else if (stat(newpath, &sb) == -1) { + if (rename(oldpath, newpath) == -1) + status = errno_to_portable(errno); + else + status = SSH2_FX_OK; } send_status(id, status); xfree(oldpath); @@ -862,20 +1044,21 @@ process_readlink(void) { u_int32_t id; int len; - char link[MAXPATHLEN]; + char buf[MAXPATHLEN]; char *path; id = get_int(); path = get_string(NULL); - TRACE("readlink id %u path %s", id, path); - if ((len = readlink(path, link, sizeof(link) - 1)) == -1) + debug3("request %u: readlink", id); + verbose("readlink \"%s\"", path); + if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) send_status(id, errno_to_portable(errno)); else { Stat s; - link[len] = '\0'; + buf[len] = '\0'; attrib_clear(&s.attrib); - s.name = s.long_name = link; + s.name = s.long_name = buf; send_names(id, 1, &s); } xfree(path); @@ -885,19 +1068,17 @@ static void process_symlink(void) { u_int32_t id; - struct stat st; char *oldpath, *newpath; - int ret, status = SSH2_FX_FAILURE; + int ret, status; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); - TRACE("symlink id %u old %s new %s", id, oldpath, newpath); - /* fail if 'newpath' exists */ - if (stat(newpath, &st) == -1) { - ret = symlink(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; - } + debug3("request %u: symlink", id); + log("symlink old \"%s\" new \"%s\"", oldpath, newpath); + /* this will fail if 'newpath' exists */ + ret = symlink(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(oldpath); xfree(newpath); @@ -930,10 +1111,11 @@ process(void) if (buf_len < 5) return; /* Incomplete message. */ cp = buffer_ptr(&iqueue); - msg_len = GET_32BIT(cp); - if (msg_len > 256 * 1024) { - error("bad message "); - exit(11); + msg_len = get_u32(cp); + if (msg_len > SFTP_MAX_MSG_LENGTH) { + error("bad message from %s local user %s", + client_addr, pw->pw_name); + cleanup_exit(11); } if (buf_len < msg_len + 4) return; @@ -1007,7 +1189,7 @@ process(void) } /* discard the remaining bytes from the current packet */ if (buf_len < buffer_len(&iqueue)) - fatal("iqueue grows"); + fatal("iqueue grew unexpectedly"); consumed = buf_len - buffer_len(&iqueue); if (msg_len < consumed) fatal("msg_len %d < consumed %d", msg_len, consumed); @@ -1015,24 +1197,93 @@ process(void) buffer_consume(&iqueue, msg_len - consumed); } +/* Cleanup handler that logs active handles upon normal exit */ +static void +cleanup_exit(int i) +{ + if (pw != NULL && client_addr != NULL) { + handle_log_exit(); + log("session closed for local user %s from [%s]", + pw->pw_name, client_addr); + } + _exit(i); +} + +static void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname); + exit(1); +} + int -main(int ac, char **av) +main(int argc, char **argv) { fd_set *rset, *wset; - int in, out, max; + int in, out, max, ch, skipargs = 0, log_stderr = 0; ssize_t len, olen, set_size; + SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; + char *cp, buf[4*4096]; - /* XXX should use getopt */ + extern char *optarg; - __progname = get_progname(av[0]); + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ + sanitise_stdfd(); + + __progname = get_progname(argv[0]); (void) g11n_setlocale(LC_ALL, ""); - handle_init(); + log_init(__progname, log_level, log_facility, log_stderr); + + while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) { + switch (ch) { + case 'c': + /* + * Ignore all arguments if we are invoked as a + * shell using "sftp-server -c command" + */ + skipargs = 1; + break; + case 'e': + log_stderr = 1; + break; + case 'l': + log_level = log_level_number(optarg); + if (log_level == SYSLOG_LEVEL_NOT_SET) + error("Invalid log level \"%s\"", optarg); + break; + case 'f': + log_facility = log_facility_number(optarg); + if (log_facility == SYSLOG_FACILITY_NOT_SET) + error("Invalid log facility \"%s\"", optarg); + break; + case 'h': + default: + usage(); + } + } -#ifdef DEBUG_SFTP_SERVER - log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); -#endif + log_init(__progname, log_level, log_facility, log_stderr); + + if ((cp = getenv("SSH_CONNECTION")) != NULL) { + client_addr = xstrdup(cp); + if ((cp = strchr(client_addr, ' ')) == NULL) + fatal("Malformed SSH_CONNECTION variable: \"%s\"", + getenv("SSH_CONNECTION")); + *cp = '\0'; + } else + client_addr = xstrdup("UNKNOWN"); + + if ((pw = getpwuid(getuid())) == NULL) + fatal("No user found for uid %lu", (u_long)getuid()); + pw = pwcopy(pw); + + log("session opened for local user %s from [%s]", + pw->pw_name, client_addr); + + handle_init(); in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO); @@ -1059,7 +1310,15 @@ main(int ac, char **av) memset(rset, 0, set_size); memset(wset, 0, set_size); - FD_SET(in, rset); + /* + * Ensure that we can read a full buffer and handle + * the worst-case length packet it can generate, + * otherwise apply backpressure by stopping reads. + */ + if (buffer_check_alloc(&iqueue, sizeof(buf)) && + buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH)) + FD_SET(in, rset); + olen = buffer_len(&oqueue); if (olen > 0) FD_SET(out, wset); @@ -1067,19 +1326,19 @@ main(int ac, char **av) if (select(max+1, rset, wset, NULL, NULL) < 0) { if (errno == EINTR) continue; - return (2); + error("select: %s", strerror(errno)); + cleanup_exit(2); } /* copy stdin to iqueue */ if (FD_ISSET(in, rset)) { - char buf[4*4096]; len = read(in, buf, sizeof buf); if (len == 0) { debug("read eof"); - return (0); + cleanup_exit(0); } else if (len < 0) { - error("read error"); - return (1); + error("read: %s", strerror(errno)); + cleanup_exit(1); } else { buffer_append(&iqueue, buf, len); } @@ -1088,13 +1347,22 @@ main(int ac, char **av) if (FD_ISSET(out, wset)) { len = write(out, buffer_ptr(&oqueue), olen); if (len < 0) { - error("write error"); - return (1); + error("write: %s", strerror(errno)); + cleanup_exit(1); } else { buffer_consume(&oqueue, len); } } - /* process requests from client */ - process(); + + /* + * Process requests from client if we can fit the results + * into the output buffer, otherwise stop processing input + * and let the output queue drain. + */ + if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH)) + process(); } + + /* NOTREACHED */ + return (0); } diff --git a/usr/src/cmd/ssh/sftp/Makefile b/usr/src/cmd/ssh/sftp/Makefile index c91fe3f9cc..f99b2b7c03 100644 --- a/usr/src/cmd/ssh/sftp/Makefile +++ b/usr/src/cmd/ssh/sftp/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -19,47 +18,47 @@ # # CDDL HEADER END # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # cmd/ssh/sftp/Makefile -PROG= sftp +PROG = sftp -OBJS = \ - sftp.o \ - sftp-client.o \ - sftp-int.o \ - sftp-glob.o -SRCS = $(OBJS:.o=.c) +OBJS = \ + sftp.o \ + sftp-client.o \ + sftp-glob.o + +SRCS = $(OBJS:.o=.c) include ../../Makefile.cmd include ../Makefile.ssh-common -LDLIBS += $(SSH_COMMON_LDLIBS) -lsocket $(OPENSSL_LDFLAGS) -lcrypto +LDLIBS += $(SSH_COMMON_LDLIBS) -lsocket $(OPENSSL_LDFLAGS) -lcrypto -DYNFLAGS += $(OPENSSL_DYNFLAGS) +DYNFLAGS += $(OPENSSL_DYNFLAGS) -POFILE_DIR= .. +POFILE_DIR = .. .KEEP_STATE: -.PARALLEL: $(OBJS) +.PARALLEL: $(OBJS) all: $(PROG) -$(PROG): $(OBJS) ../libssh/$(MACH)/libssh.a ../libopenbsd-compat/$(MACH)/libopenbsd-compat.a +$(PROG): $(OBJS) ../libssh/$(MACH)/libssh.a ../libopenbsd-compat/$(MACH)/libopenbsd-compat.a $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS) $(POST_PROCESS) -install: all $(ROOTPROG) +install: all $(ROOTPROG) clean: $(RM) -f $(OBJS) $(PROG) -lint: lint_SRCS +lint: lint_SRCS include ../Makefile.msg.targ include ../../Makefile.targ diff --git a/usr/src/cmd/ssh/sftp/sftp-client.c b/usr/src/cmd/ssh/sftp/sftp-client.c index 420384476e..4c5f823e2f 100644 --- a/usr/src/cmd/ssh/sftp/sftp-client.c +++ b/usr/src/cmd/ssh/sftp/sftp-client.c @@ -1,55 +1,65 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright (c) 2001,2002 Damien Miller. All rights reserved. + * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * - * 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. + * 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. * - * 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. + * 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. */ +/* $OpenBSD: sftp-client.c,v 1.76 2007/01/22 11:32:50 djm Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + /* XXX: memleaks */ /* XXX: signed vs unsigned */ /* XXX: remove all logging, only return status codes */ /* XXX: copy between two remote sites */ #include "includes.h" -RCSID("$OpenBSD: sftp-client.c,v 1.35 2002/09/11 22:41:49 djm Exp $"); - -#pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/types.h> +#include <sys/param.h> #include "sys-queue.h" +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#include <sys/uio.h> + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "xmalloc.h" #include "buffer.h" #include "bufaux.h" -#include "getput.h" -#include "xmalloc.h" #include "log.h" #include "atomicio.h" +#include "progressmeter.h" +#include "misc.h" #include "sftp.h" #include "sftp-common.h" #include "sftp-client.h" -/* Minimum amount of data to read at at time */ +extern volatile sig_atomic_t interrupted; +extern int showprogress; + +/* Minimum amount of data to read at a time */ #define MIN_READ_SIZE 512 struct sftp_conn { @@ -64,47 +74,48 @@ struct sftp_conn { static void send_msg(int fd, Buffer *m) { - int mlen = buffer_len(m); - int len; - Buffer oqueue; + char mlen[4]; + struct iovec iov[2]; - buffer_init(&oqueue); - buffer_put_int(&oqueue, mlen); - buffer_append(&oqueue, buffer_ptr(m), mlen); - buffer_consume(m, mlen); + if (buffer_len(m) > SFTP_MAX_MSG_LENGTH) + fatal("Outbound message too long %u", buffer_len(m)); - len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue)); - if (len <= 0) + /* Send length first */ + put_u32(mlen, buffer_len(m)); + iov[0].iov_base = mlen; + iov[0].iov_len = sizeof(mlen); + iov[1].iov_base = buffer_ptr(m); + iov[1].iov_len = buffer_len(m); + + if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen)) fatal("Couldn't send packet: %s", strerror(errno)); - buffer_free(&oqueue); + buffer_clear(m); } static void get_msg(int fd, Buffer *m) { - u_int len, msg_len; - unsigned char buf[4096]; + u_int msg_len; - len = atomicio(read, fd, buf, 4); - if (len == 0) - fatal("Connection closed"); - else if (len == (u_int) -1) - fatal("Couldn't read packet: %s", strerror(errno)); + buffer_append_space(m, 4); + if (atomicio(read, fd, buffer_ptr(m), 4) != 4) { + if (errno == EPIPE) + fatal("Connection closed"); + else + fatal("Couldn't read packet: %s", strerror(errno)); + } - msg_len = GET_32BIT(buf); - if (msg_len > 256 * 1024) + msg_len = buffer_get_int(m); + if (msg_len > SFTP_MAX_MSG_LENGTH) fatal("Received message too long %u", msg_len); - while (msg_len) { - len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf))); - if (len == 0) + buffer_append_space(m, msg_len); + if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) { + if (errno == EPIPE) fatal("Connection closed"); - else if (len == (u_int) -1) - fatal("Couldn't read packet: %s", strerror(errno)); - - msg_len -= len; - buffer_append(m, buf, len); + else + fatal("Read packet: %s", strerror(errno)); } } @@ -182,6 +193,7 @@ get_handle(int fd, u_int expected_id, u_int *len) int status = buffer_get_int(&msg); error("Couldn't get handle: %s", fx2txt(status)); + buffer_free(&msg); return(NULL); } else if (type != SSH2_FXP_HANDLE) fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", @@ -216,6 +228,7 @@ get_decode_stat(int fd, u_int expected_id, int quiet) debug("Couldn't stat remote file: %s", fx2txt(status)); else error("Couldn't stat remote file: %s", fx2txt(status)); + buffer_free(&msg); return(NULL); } else if (type != SSH2_FXP_ATTRS) { fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", @@ -318,7 +331,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, SFTP_DIRENT ***dir) { Buffer msg; - u_int type, id, handle_len, i, expected_id, ents = 0; + u_int count, type, id, handle_len, i, expected_id, ents = 0; char *handle; id = conn->msg_id++; @@ -341,9 +354,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, (*dir)[0] = NULL; } - for (;;) { - int count; - + for (; !interrupted;) { id = expected_id = conn->msg_id++; debug3("Sending SSH2_FXP_READDIR I:%u", id); @@ -377,6 +388,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, error("Couldn't read directory: %s", fx2txt(status)); do_close(conn, handle, handle_len); + xfree(handle); return(status); } } else if (type != SSH2_FXP_NAME) @@ -399,8 +411,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, printf("%s\n", longname); if (dir) { - *dir = xrealloc(*dir, sizeof(**dir) * - (ents + 2)); + *dir = xrealloc(*dir, (ents + 2) * sizeof(**dir)); (*dir)[ents] = xmalloc(sizeof(***dir)); (*dir)[ents]->filename = xstrdup(filename); (*dir)[ents]->longname = xstrdup(longname); @@ -417,6 +428,13 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, do_close(conn, handle, handle_len); xfree(handle); + /* Don't return partial matches on interrupt */ + if (interrupted && dir != NULL && *dir != NULL) { + free_sftp_dirents(*dir); + *dir = xmalloc(sizeof(**dir)); + **dir = NULL; + } + return(0); } @@ -520,6 +538,7 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) return(get_decode_stat(conn->fd_in, id, quiet)); } +/* this is never used so hush the lint */ #if 0 Attrib * do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) @@ -574,6 +593,8 @@ do_realpath(struct sftp_conn *conn, char *path) Buffer msg; u_int type, expected_id, count, id; char *filename, *longname; + /* LINTED */ + Attrib *a; expected_id = id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, @@ -603,7 +624,7 @@ do_realpath(struct sftp_conn *conn, char *path) filename = buffer_get_string(&msg, NULL); longname = buffer_get_string(&msg, NULL); - (void) decode_attrib(&msg); + a = decode_attrib(&msg); debug3("SSH_FXP_REALPATH %s -> %s", path, filename); @@ -654,7 +675,7 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) buffer_init(&msg); - /* Send rename request */ + /* Send symlink request */ id = conn->msg_id++; buffer_put_char(&msg, SSH2_FXP_SYMLINK); buffer_put_int(&msg, id); @@ -667,12 +688,13 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) - error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, + error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, newpath, fx2txt(status)); return(status); } +/* this is never used so hush the lint */ #if 0 char * do_readlink(struct sftp_conn *conn, char *path) @@ -680,6 +702,7 @@ do_readlink(struct sftp_conn *conn, char *path) Buffer msg; u_int type, expected_id, count, id; char *filename, *longname; + Attrib *a; expected_id = id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, @@ -709,7 +732,7 @@ do_readlink(struct sftp_conn *conn, char *path) filename = buffer_get_string(&msg, NULL); longname = buffer_get_string(&msg, NULL); - (void) decode_attrib(&msg); + a = decode_attrib(&msg); debug3("SSH_FXP_READLINK %s -> %s", path, filename); @@ -745,10 +768,11 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, Attrib junk, *a; Buffer msg; char *handle; - int local_fd, status, num_req, max_req, write_error; + int local_fd, status = 0, write_error; int read_error, write_errno; u_int64_t offset, size; - u_int handle_len, mode, type, id, buflen; + u_int handle_len, mode, type, id, buflen, num_req, max_req; + off_t progress_counter; struct request { u_int id; u_int len; @@ -766,13 +790,13 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, /* XXX: should we preserve set[ug]id? */ if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) - mode = S_IWRITE | (a->perm & 0777); + mode = a->perm & 0777; else mode = 0666; if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && - S_ISDIR(a->perm)) { - error("Cannot download a directory: %s", remote_path); + (!S_ISREG(a->perm))) { + error("Cannot download non-regular file: %s", remote_path); return(-1); } @@ -801,7 +825,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, return(-1); } - local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); + local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, + mode | S_IWRITE); if (local_fd == -1) { error("Couldn't open local file \"%s\" for writing: %s", local_path, strerror(errno)); @@ -813,10 +838,25 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, /* Read from remote and write to local */ write_error = read_error = write_errno = num_req = offset = 0; max_req = 1; + progress_counter = 0; + + if (showprogress && size != 0) + start_progress_meter(remote_path, size, &progress_counter); + while (num_req > 0 || max_req > 0) { char *data; u_int len; + /* + * Simulate EOF on interrupt: stop sending new requests and + * allow outstanding requests to drain gracefully + */ + if (interrupted) { + if (num_req == 0) /* If we haven't started yet... */ + break; + max_req = 0; + } + /* Send some more requests */ while (num_req < max_req) { debug3("Request range %llu -> %llu (%d/%d)", @@ -841,7 +881,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, debug3("Received reply T:%u I:%u R:%d", type, id, max_req); /* Find the request in our queue */ - for(req = TAILQ_FIRST(&requests); + for (req = TAILQ_FIRST(&requests); req != NULL && req->id != id; req = TAILQ_NEXT(req, tq)) ; @@ -865,14 +905,15 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, (unsigned long long)req->offset + len - 1); if (len > req->len) fatal("Received more data than asked for " - "%u > %u", len, req->len); + "%u > %u", len, req->len); if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || - atomicio(write, local_fd, data, len) != len) && + atomicio(vwrite, local_fd, data, len) != len) && !write_error) { write_errno = errno; write_error = 1; max_req = 0; } + progress_counter += len; xfree(data); if (len == req->len) { @@ -903,8 +944,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, (unsigned long long)offset, num_req); max_req = 1; - } - else if (max_req < conn->num_requests + 1) { + } else if (max_req <= conn->num_requests) { ++max_req; } } @@ -915,6 +955,9 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, } } + if (showprogress && size) + stop_progress_meter(); + /* Sanity check */ if (TAILQ_FIRST(&requests) != NULL) fatal("Transfer complete, but requests still in queue"); @@ -934,11 +977,11 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, /* Override umask and utimes if asked */ #ifdef HAVE_FCHMOD if (pflag && fchmod(local_fd, mode) == -1) -#else +#else if (pflag && chmod(local_path, mode) == -1) #endif /* HAVE_FCHMOD */ error("Couldn't set mode on \"%s\": %s", local_path, - strerror(errno)); + strerror(errno)); if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { struct timeval tv[2]; tv[0].tv_sec = a->atime; @@ -946,7 +989,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 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)); + local_path, strerror(errno)); } } close(local_fd); @@ -976,7 +1019,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, TAILQ_ENTRY(outstanding_ack) tq; }; TAILQ_HEAD(ackhead, outstanding_ack) acks; - struct outstanding_ack *ack; + struct outstanding_ack *ack = NULL; TAILQ_INIT(&acks); @@ -991,6 +1034,11 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, close(local_fd); return(-1); } + if (!S_ISREG(sb.st_mode)) { + error("%s is not a regular file", local_path); + close(local_fd); + return(-1); + } stat_to_attrib(&sb, &a); a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; @@ -1025,14 +1073,21 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, /* Read from local and write to remote */ offset = 0; + if (showprogress) + start_progress_meter(local_path, sb.st_size, (off_t *)&offset); + for (;;) { int len; /* - * Can't use atomicio here because it returns 0 on EOF, thus losing - * the last block of the file + * Can't use atomicio here because it returns 0 on EOF, + * thus losing the last block of the file. + * Simulate an EOF on interrupt, allowing ACKs from the + * server to drain. */ - do + if (interrupted) + len = 0; + else do len = read(local_fd, data, conn->transfer_buflen); while ((len == -1) && (errno == EINTR || errno == EAGAIN)); @@ -1055,7 +1110,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, buffer_put_string(&msg, data, len); send_msg(conn->fd_out, &msg); debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", - id, (unsigned long long)offset, len); + id, (unsigned long long)offset, len); } else if (TAILQ_FIRST(&acks) == NULL) break; @@ -1079,7 +1134,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, debug3("SSH2_FXP_STATUS %d", status); /* Find the request in our queue */ - for(ack = TAILQ_FIRST(&acks); + for (ack = TAILQ_FIRST(&acks); ack != NULL && ack->id != r_id; ack = TAILQ_NEXT(ack, tq)) ; @@ -1089,18 +1144,25 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, if (status != SSH2_FX_OK) { error("Couldn't write to remote file \"%s\": %s", - remote_path, fx2txt(status)); + remote_path, fx2txt(status)); + if (showprogress) + stop_progress_meter(); do_close(conn, handle, handle_len); close(local_fd); + xfree(data); + xfree(ack); + status = -1; goto done; } debug3("In write loop, ack for %u %u bytes at %llu", - ack->id, ack->len, (unsigned long long)ack->offset); + ack->id, ack->len, (unsigned long long)ack->offset); ++ackid; xfree(ack); } offset += len; } + if (showprogress) + stop_progress_meter(); xfree(data); if (close(local_fd) == -1) { diff --git a/usr/src/cmd/ssh/sftp/sftp-glob.c b/usr/src/cmd/ssh/sftp/sftp-glob.c index 2d2d18e64f..856b3a2635 100644 --- a/usr/src/cmd/ssh/sftp/sftp-glob.c +++ b/usr/src/cmd/ssh/sftp/sftp-glob.c @@ -1,45 +1,41 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright (c) 2001,2002 Damien Miller. All rights reserved. + * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * - * 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. + * 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. * - * 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. + * 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. */ -#include "includes.h" -RCSID("$OpenBSD: sftp-glob.c,v 1.13 2002/09/11 22:41:50 djm Exp $"); +/* $OpenBSD: sftp-glob.c,v 1.22 2006/08/03 03:34:42 deraadt Exp $ */ #pragma ident "%Z%%M% %I% %E% SMI" -#include "buffer.h" -#include "bufaux.h" -#include "xmalloc.h" -#include "log.h" +#include "includes.h" +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif + +#include <dirent.h> +#include <string.h> + +#include "xmalloc.h" #include "sftp.h" +#include "buffer.h" #include "sftp-common.h" #include "sftp-client.h" -#include "sftp-glob.h" + +int remote_glob(struct sftp_conn *, const char *, int, + int (*)(const char *, int), glob_t *); struct SFTP_OPENDIR { SFTP_DIRENT **dir; @@ -79,7 +75,7 @@ fudge_readdir(struct SFTP_OPENDIR *od) #ifdef __GNU_LIBRARY__ static int inum = 1; #endif /* __GNU_LIBRARY__ */ - + if (od->dir[od->offset] == NULL) return(NULL); @@ -98,7 +94,7 @@ fudge_readdir(struct SFTP_OPENDIR *od) #ifdef __GNU_LIBRARY__ /* * Idiot glibc uses extensions to struct dirent for readdir with - * ALTDIRFUNCs. Not that this is documented anywhere but the + * ALTDIRFUNCs. Not that this is documented anywhere but the * source... Fake an inode number to appease it. */ ret->d_ino = inum++; diff --git a/usr/src/cmd/ssh/sftp/sftp-int.c b/usr/src/cmd/ssh/sftp/sftp-int.c deleted file mode 100644 index 8c7d375752..0000000000 --- a/usr/src/cmd/ssh/sftp/sftp-int.c +++ /dev/null @@ -1,1098 +0,0 @@ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright (c) 2001,2002 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: recursive operations */ - -#include "includes.h" -RCSID("$OpenBSD: sftp-int.c,v 1.49 2002/09/12 00:13:06 djm Exp $"); - -#pragma ident "%Z%%M% %I% %E% SMI" - -#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; - -/* Size of buffer used when copying files */ -extern size_t copy_buffer_len; - -/* Number of concurrent outstanding requests */ -extern int num_requests; - -/* 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[] = { - { "bye", I_QUIT }, - { "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} -}; - -static void -help(void) -{ - printf(gettext("Available commands:\n" - "cd path Change remote directory to 'path'\n" - "lcd path Change local directory to 'path'\n" - "chgrp grp path Change group of file 'path' " - "to 'grp'\n" - "chmod mode path Change permissions of file " - "'path' to 'mode'\n" - "chown own path Change owner of file 'path' " - "to 'own'\n" - "help Display this help text\n" - "get remote-path [local-path] Download file\n" - "lls [ls-options [path]] Display local directory listing\n" - "ln oldpath newpath Symlink remote file\n" - "lmkdir path Create local directory\n" - "lpwd Print local working directory\n" - "ls [path] Display remote directory listing\n" - "lumask umask Set local umask to 'umask'\n" - "mkdir path Create remote directory\n" - "put local-path [remote-path] Upload file\n" - "pwd Display remote working directory\n" - "exit Quit sftp\n" - "quit Quit sftp\n" - "rename oldpath newpath Rename remote file\n" - "rmdir path Remove remote directory\n" - "rm path Delete remote file\n" - "symlink oldpath newpath Symlink remote file\n" - "version Show SFTP version\n" - "!command Execute 'command' in local shell\n" - "! Escape to local shell\n" - "? Synonym for help\n")); -} - -static 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, (char *)NULL); - } else { - debug3("Executing %s", shell); - execl(shell, shell, (char *)NULL); - } - fprintf(stderr, gettext("Couldn't execute \"%s\": %s\n"), shell, - strerror(errno)); - _exit(1); - } - while (waitpid(pid, &status, 0) == -1) - if (errno != EINTR) - fatal("Couldn't wait for child: %s", strerror(errno)); - if (!WIFEXITED(status)) - error("Shell exited abnormally"); - else if (WEXITSTATUS(status)) - error("Shell exited with status %d", WEXITSTATUS(status)); -} - -static 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); - } -} - -/* Strip one path (usually the pwd) from the start of another */ -static char * -path_strip(char *path, char *strip) -{ - size_t len; - - if (strip == NULL) - return (xstrdup(path)); - - len = strlen(strip); - if (strip != NULL && strncmp(path, strip, len) == 0) { - if (strip[len - 1] != '/' && path[len] == '/') - len++; - return (xstrdup(path + len)); - } - - return (xstrdup(path)); -} - -static char * -path_append(char *p1, char *p2) -{ - char *ret; - int len = strlen(p1) + strlen(p2) + 2; - - ret = xmalloc(len); - strlcpy(ret, p1, len); - if (p1[strlen(p1) - 1] != '/') - strlcat(ret, "/", len); - strlcat(ret, p2, len); - - return(ret); -} - -static 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); -} - -static 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); -} - -static 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); -} - -static int -parse_ls_flags(const char **cpp, int *lflag) -{ - const char *cp = *cpp; - - /* Check for flags */ - if (cp++[0] == '-') { - for(; strchr(WHITESPACE, *cp) == NULL; cp++) { - switch (*cp) { - case 'l': - *lflag = 1; - break; - default: - error("Invalid flag -%c", *cp); - return(-1); - } - } - *cpp = cp + strspn(cp, WHITESPACE); - } - - return(0); -} - -static 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); -} - -static int -is_dir(char *path) -{ - struct stat sb; - - /* XXX: report errors? */ - if (stat(path, &sb) == -1) - return(0); - - return (S_ISDIR(sb.st_mode)); -} - -static int -remote_is_dir(struct sftp_conn *conn, char *path) -{ - Attrib *a; - - /* XXX: report errors? */ - if ((a = do_stat(conn, path, 1)) == NULL) - return(0); - if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) - return(0); - return (S_ISDIR(a->perm)); -} - -static int -process_get(struct sftp_conn *conn, 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(conn, 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(gettext("Fetching %s to %s\n"), g.gl_pathv[0], abs_dst); - err = do_download(conn, 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(gettext("Fetching %s to %s\n"), g.gl_pathv[i], abs_dst); - if (do_download(conn, 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); -} - -static int -process_put(struct sftp_conn *conn, 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(conn, 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(gettext("Uploading %s to %s\n"), g.gl_pathv[0], abs_dst); - err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag); - goto out; - } - - /* Multiple matches, dst may be directory or unspecified */ - if (tmp_dst && !remote_is_dir(conn, 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(gettext("Uploading %s to %s\n"), g.gl_pathv[i], abs_dst); - if (do_upload(conn, 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); -} - -static int -sdirent_comp(const void *aa, const void *bb) -{ - SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; - SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; - - return (strcmp(a->filename, b->filename)); -} - -/* sftp ls.1 replacement for directories */ -static int -do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) -{ - int n; - SFTP_DIRENT **d; - - if ((n = do_readdir(conn, path, &d)) != 0) - return (n); - - /* Count entries for sort */ - for (n = 0; d[n] != NULL; n++) - ; - - qsort(d, n, sizeof(*d), sdirent_comp); - - for (n = 0; d[n] != NULL; n++) { - char *tmp, *fname; - - tmp = path_append(path, d[n]->filename); - fname = path_strip(tmp, strip_path); - xfree(tmp); - - if (lflag) { - char *lname; - struct stat sb; - - memset(&sb, 0, sizeof(sb)); - attrib_to_stat(&d[n]->a, &sb); - lname = ls_file(fname, &sb, 1); - printf("%s\n", lname); - xfree(lname); - } else { - /* XXX - multicolumn display would be nice here */ - printf("%s\n", fname); - } - - xfree(fname); - } - - free_sftp_dirents(d); - return (0); -} - -/* sftp ls.1 replacement which handles path globs */ -static int -do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, - int lflag) -{ - glob_t g; - int i; - Attrib *a; - struct stat sb; - - memset(&g, 0, sizeof(g)); - - if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, - NULL, &g)) { - error("Can't ls: \"%s\" not found", path); - return (-1); - } - - /* - * If the glob returns a single match, which is the same as the - * input glob, and it is a directory, then just list its contents - */ - if (g.gl_pathc == 1 && - strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) { - if ((a = do_lstat(conn, path, 1)) == NULL) { - globfree(&g); - return (-1); - } - if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && - S_ISDIR(a->perm)) { - globfree(&g); - return (do_ls_dir(conn, path, strip_path, lflag)); - } - } - - for (i = 0; g.gl_pathv[i]; i++) { - char *fname, *lname; - - fname = path_strip(g.gl_pathv[i], strip_path); - - if (lflag) { - /* - * XXX: this is slow - 1 roundtrip per path - * A solution to this is to fork glob() and - * build a sftp specific version which keeps the - * attribs (which currently get thrown away) - * that the server returns as well as the filenames. - */ - memset(&sb, 0, sizeof(sb)); - a = do_lstat(conn, g.gl_pathv[i], 1); - if (a != NULL) - attrib_to_stat(a, &sb); - lname = ls_file(fname, &sb, 1); - printf("%s\n", lname); - xfree(lname); - } else { - /* XXX - multicolumn display would be nice here */ - printf("%s\n", fname); - } - xfree(fname); - } - - if (g.gl_pathc) - globfree(&g); - - return (0); -} - -static int -parse_args(const char **cpp, int *pflag, int *lflag, - 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 */ - *lflag = *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: - if (parse_ls_flags(&cp, lflag)) - return(-1); - /* 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; - /* FALLTHROUGH */ - case I_CHMOD: - base = 8; - /* FALLTHROUGH */ - 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); -} - -static int -parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) -{ - char *path1, *path2, *tmp; - int pflag, lflag, 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, &lflag, &n_arg, - &path1, &path2); - - memset(&g, 0, sizeof(g)); - - /* Perform command */ - switch (cmdnum) { - case -1: - break; - case I_GET: - err = process_get(conn, path1, path2, *pwd, pflag); - break; - case I_PUT: - err = process_put(conn, path1, path2, *pwd, pflag); - break; - case I_RENAME: - path1 = make_absolute(path1, *pwd); - path2 = make_absolute(path2, *pwd); - err = do_rename(conn, path1, path2); - break; - case I_SYMLINK: - path2 = make_absolute(path2, *pwd); - err = do_symlink(conn, path1, path2); - break; - case I_RM: - path1 = make_absolute(path1, *pwd); - remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); - for (i = 0; g.gl_pathv[i]; i++) { - printf(gettext("Removing %s\n"), g.gl_pathv[i]); - if (do_rm(conn, 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(conn, path1, &a); - break; - case I_RMDIR: - path1 = make_absolute(path1, *pwd); - err = do_rmdir(conn, path1); - break; - case I_CHDIR: - path1 = make_absolute(path1, *pwd); - if ((tmp = do_realpath(conn, path1)) == NULL) { - err = 1; - break; - } - if ((aa = do_stat(conn, 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_globbed_ls(conn, *pwd, *pwd, lflag); - break; - } - - /* Strip pwd off beginning of non-absolute paths */ - tmp = NULL; - if (*path1 != '/') - tmp = *pwd; - - path1 = make_absolute(path1, *pwd); - - do_globbed_ls(conn, path1, tmp, lflag); - 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(gettext("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(conn, path1, GLOB_NOCHECK, NULL, &g); - for (i = 0; g.gl_pathv[i]; i++) { - printf(gettext("Changing mode on %s\n"), g.gl_pathv[i]); - do_setstat(conn, g.gl_pathv[i], &a); - } - break; - case I_CHOWN: - path1 = make_absolute(path1, *pwd); - remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); - for (i = 0; g.gl_pathv[i]; i++) { - if (!(aa = do_stat(conn, 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(gettext("Changing owner on %s\n"), - g.gl_pathv[i]); - aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; - aa->uid = n_arg; - do_setstat(conn, g.gl_pathv[i], aa); - } - break; - case I_CHGRP: - path1 = make_absolute(path1, *pwd); - remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); - for (i = 0; g.gl_pathv[i]; i++) { - if (!(aa = do_stat(conn, 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(gettext("Changing group on %s\n"), - g.gl_pathv[i]); - aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; - aa->gid = n_arg; - do_setstat(conn, g.gl_pathv[i], aa); - } - break; - case I_PWD: - printf(gettext("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(gettext("Local working directory: %s\n"), - path_buf); - break; - case I_QUIT: - return(-1); - case I_HELP: - help(); - break; - case I_VERSION: - printf(gettext("SFTP protocol version %u\n"), - sftp_proto_version(conn)); - 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]; - struct sftp_conn *conn; - - conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); - if (conn == NULL) - fatal("Couldn't initialise connection to server"); - - pwd = do_realpath(conn, "."); - if (pwd == NULL) - fatal("Need cwd"); - - if (file1 != NULL) { - dir = xstrdup(file1); - dir = make_absolute(dir, pwd); - - if (remote_is_dir(conn, dir) && file2 == NULL) { - printf(gettext("Changing to: %s\n"), dir); - snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); - parse_dispatch_command(conn, 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(conn, cmd, &pwd); - xfree(dir); - return; - } - xfree(dir); - } -#if HAVE_SETVBUF - setvbuf(stdout, NULL, _IOLBF, 0); - setvbuf(infile, NULL, _IOLBF, 0); -#else - setlinebuf(stdout); - setlinebuf(infile); -#endif - - 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(conn, cmd, &pwd)) - break; - } - xfree(pwd); -} diff --git a/usr/src/cmd/ssh/sftp/sftp.c b/usr/src/cmd/ssh/sftp/sftp.c index 0f2f04638d..a0a2c83879 100644 --- a/usr/src/cmd/ssh/sftp/sftp.c +++ b/usr/src/cmd/ssh/sftp/sftp.c @@ -1,49 +1,60 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright (c) 2001,2002 Damien Miller. All rights reserved. + * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * - * 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. + * 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. * - * 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. + * 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. */ +/* $OpenBSD: sftp.c,v 1.96 2007/01/03 04:09:15 stevesk Exp $ */ + +#pragma ident "%Z%%M% %I% %E% SMI" + #include "includes.h" -RCSID("$OpenBSD: sftp.c,v 1.31 2002/07/25 01:16:59 mouring Exp $"); +#include <sys/types.h> +#include <sys/ioctl.h> +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/wait.h> -#pragma ident "%Z%%M% %I% %E% SMI" +#include <errno.h> -/* XXX: short-form remote directory listings (like 'ls -C') */ +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif +#ifdef USE_LIBEDIT +#include <histedit.h> +#else +typedef void EditLine; +#endif +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> -#include "buffer.h" #include "xmalloc.h" #include "log.h" #include "pathnames.h" #include "misc.h" #include "sftp.h" +#include "buffer.h" #include "sftp-common.h" #include "sftp-client.h" -#include "sftp-int.h" #ifdef HAVE___PROGNAME extern char *__progname; @@ -51,12 +62,1349 @@ extern char *__progname; char *__progname; #endif + +/* File to read commands from */ FILE* infile; + +/* Are we in batchfile mode? */ +int batchmode = 0; + +/* Size of buffer used when copying files */ size_t copy_buffer_len = 32768; + +/* Number of concurrent outstanding requests */ size_t num_requests = 16; +/* PID of ssh transport process */ +static pid_t sshpid = -1; + +/* This is set to 0 if the progressmeter is not desired. */ +int showprogress = 1; + +/* SIGINT received during command processing */ +volatile sig_atomic_t interrupted = 0; + +/* I wish qsort() took a separate ctx for the comparison function...*/ +int sort_flag; + +int remote_glob(struct sftp_conn *, const char *, int, + int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ + +/* Separators for interactive commands */ +#define WHITESPACE " \t\r\n" + +/* ls flags */ +#define LS_LONG_VIEW 0x01 /* Full view ala ls -l */ +#define LS_SHORT_VIEW 0x02 /* Single row view ala ls -1 */ +#define LS_NUMERIC_VIEW 0x04 /* Long view with numeric uid/gid */ +#define LS_NAME_SORT 0x08 /* Sort by name (default) */ +#define LS_TIME_SORT 0x10 /* Sort by mtime */ +#define LS_SIZE_SORT 0x20 /* Sort by file size */ +#define LS_REVERSE_SORT 0x40 /* Reverse sort order */ +#define LS_SHOW_ALL 0x80 /* Don't skip filenames starting with '.' */ + +#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW) +#define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) + +/* 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 +#define I_PROGRESS 23 + +struct CMD { + const char *c; + const int n; +}; + +static const struct CMD cmds[] = { + { "bye", I_QUIT }, + { "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 }, + { "progress", I_PROGRESS }, + { "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} +}; + +int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); + +/* ARGSUSED */ +static void +killchild(int signo) +{ + if (sshpid > 1) { + kill(sshpid, SIGTERM); + waitpid(sshpid, NULL, 0); + } + + _exit(1); +} + +/* ARGSUSED */ +static void +cmd_interrupt(int signo) +{ + const char msg[] = "\rInterrupt \n"; + int olderrno = errno; + + write(STDERR_FILENO, msg, sizeof(msg) - 1); + interrupted = 1; + errno = olderrno; +} + +static void +help(void) +{ + printf(gettext("Available commands:\n" + "cd path Change remote directory to 'path'\n" + "lcd path Change local directory to 'path'\n" + "chgrp grp path Change group of file 'path' to 'grp'\n" + "chmod mode path Change permissions of file 'path' to 'mode'\n" + "chown own path Change owner of file 'path' to 'own'\n" + "help Display this help text\n" + "get remote-path [local-path] Download file\n" + "lls [ls-options [path]] Display local directory listing\n" + "ln oldpath newpath Symlink remote file\n" + "lmkdir path Create local directory\n" + "lpwd Print local working directory\n" + "ls [path] Display remote directory listing\n" + "lumask umask Set local umask to 'umask'\n" + "mkdir path Create remote directory\n" + "progress Toggle display of progress meter\n" + "put local-path [remote-path] Upload file\n" + "pwd Display remote working directory\n" + "exit Quit sftp\n" + "quit Quit sftp\n" + "rename oldpath newpath Rename remote file\n" + "rmdir path Remove remote directory\n" + "rm path Delete remote file\n" + "symlink oldpath newpath Symlink remote file\n" + "version Show SFTP version\n" + "!command Execute 'command' in local shell\n" + "! Escape to local shell\n" + "? Synonym for help\n")); +} + +static 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, (char *)NULL); + } else { + debug3("Executing %s", shell); + execl(shell, shell, (char *)NULL); + } + fprintf(stderr, gettext("Couldn't execute \"%s\": %s\n"), shell, + strerror(errno)); + _exit(1); + } + while (waitpid(pid, &status, 0) == -1) + if (errno != EINTR) + fatal("Couldn't wait for child: %s", strerror(errno)); + if (!WIFEXITED(status)) + error("Shell exited abnormally"); + else if (WEXITSTATUS(status)) + error("Shell exited with status %d", WEXITSTATUS(status)); +} + +static 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); + } +} + +/* Strip one path (usually the pwd) from the start of another */ +static char * +path_strip(char *path, char *strip) +{ + size_t len; + + if (strip == NULL) + return (xstrdup(path)); + + len = strlen(strip); + if (strncmp(path, strip, len) == 0) { + if (strip[len - 1] != '/' && path[len] == '/') + len++; + return (xstrdup(path + len)); + } + + return (xstrdup(path)); +} + +static char * +path_append(char *p1, char *p2) +{ + char *ret; + size_t len = strlen(p1) + strlen(p2) + 2; + + ret = xmalloc(len); + strlcpy(ret, p1, len); + if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') + strlcat(ret, "/", len); + strlcat(ret, p2, len); + + return(ret); +} + +static char * +make_absolute(char *p, char *pwd) +{ + char *abs_str; + + /* Derelativise */ + if (p && p[0] != '/') { + abs_str = path_append(pwd, p); + xfree(p); + return(abs_str); + } else + return(p); +} + +static 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); +} + +static 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); +} + +static int +parse_ls_flags(const char **cpp, int *lflag) +{ + const char *cp = *cpp; + + /* Defaults */ + *lflag = LS_NAME_SORT; + + /* Check for flags */ + if (cp++[0] == '-') { + for (; strchr(WHITESPACE, *cp) == NULL; cp++) { + switch (*cp) { + case 'l': + *lflag &= ~VIEW_FLAGS; + *lflag |= LS_LONG_VIEW; + break; + case '1': + *lflag &= ~VIEW_FLAGS; + *lflag |= LS_SHORT_VIEW; + break; + case 'n': + *lflag &= ~VIEW_FLAGS; + *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; + break; + case 'S': + *lflag &= ~SORT_FLAGS; + *lflag |= LS_SIZE_SORT; + break; + case 't': + *lflag &= ~SORT_FLAGS; + *lflag |= LS_TIME_SORT; + break; + case 'r': + *lflag |= LS_REVERSE_SORT; + break; + case 'f': + *lflag &= ~SORT_FLAGS; + break; + case 'a': + *lflag |= LS_SHOW_ALL; + break; + default: + error("Invalid flag -%c", *cp); + return(-1); + } + } + *cpp = cp + strspn(cp, WHITESPACE); + } + + return(0); +} + +static int +get_pathname(const char **cpp, char **path) +{ + const char *cp = *cpp, *end; + char quot; + u_int i, j; + + cp += strspn(cp, WHITESPACE); + if (!*cp) { + *cpp = cp; + *path = NULL; + return (0); + } + + *path = xmalloc(strlen(cp) + 1); + + /* Check for quoted filenames */ + if (*cp == '\"' || *cp == '\'') { + quot = *cp++; + + /* Search for terminating quote, unescape some chars */ + for (i = j = 0; i <= strlen(cp); i++) { + if (cp[i] == quot) { /* Found quote */ + i++; + (*path)[j] = '\0'; + break; + } + if (cp[i] == '\0') { /* End of string */ + error("Unterminated quote"); + goto fail; + } + if (cp[i] == '\\') { /* Escaped characters */ + i++; + if (cp[i] != '\'' && cp[i] != '\"' && + cp[i] != '\\') { + error("Bad escaped character '\\%c'", + cp[i]); + goto fail; + } + } + (*path)[j++] = cp[i]; + } + + if (j == 0) { + error("Empty quotes"); + goto fail; + } + *cpp = cp + i + strspn(cp + i, WHITESPACE); + } else { + /* Read to end of filename */ + end = strpbrk(cp, WHITESPACE); + if (end == NULL) + end = strchr(cp, '\0'); + *cpp = end + strspn(end, WHITESPACE); + + memcpy(*path, cp, end - cp); + (*path)[end - cp] = '\0'; + } + return (0); + + fail: + xfree(*path); + *path = NULL; + return (-1); +} + +static int +is_dir(char *path) +{ + struct stat sb; + + /* XXX: report errors? */ + if (stat(path, &sb) == -1) + return(0); + + return(S_ISDIR(sb.st_mode)); +} + +static int +is_reg(char *path) +{ + struct stat sb; + + if (stat(path, &sb) == -1) + fatal("stat %s: %s", path, strerror(errno)); + + return(S_ISREG(sb.st_mode)); +} + +static int +remote_is_dir(struct sftp_conn *conn, char *path) +{ + Attrib *a; + + /* XXX: report errors? */ + if ((a = do_stat(conn, path, 1)) == NULL) + return(0); + if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) + return(0); + return(S_ISDIR(a->perm)); +} + +static int +process_get(struct sftp_conn *conn, 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(conn, abs_src, 0, NULL, &g)) { + error("File \"%s\" not found.", abs_src); + err = -1; + goto out; + } + + /* If multiple matches, dst must be a directory or unspecified */ + if (g.gl_matchc > 1 && 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] && !interrupted; i++) { + if (infer_path(g.gl_pathv[i], &tmp)) { + err = -1; + goto out; + } + + if (g.gl_matchc == 1 && dst) { + /* If directory specified, append filename */ + xfree(tmp); + 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 (dst) { + abs_dst = path_append(dst, tmp); + xfree(tmp); + } else + abs_dst = tmp; + + printf(gettext("Fetching %s to %s\n"), g.gl_pathv[i], abs_dst); + if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) + err = -1; + xfree(abs_dst); + abs_dst = NULL; + } + +out: + xfree(abs_src); + globfree(&g); + return(err); +} + +static int +process_put(struct sftp_conn *conn, 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; + } + + /* If multiple matches, dst may be directory or unspecified */ + if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, 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] && !interrupted; i++) { + if (!is_reg(g.gl_pathv[i])) { + error("skipping non-regular file %s", + g.gl_pathv[i]); + continue; + } + if (infer_path(g.gl_pathv[i], &tmp)) { + err = -1; + goto out; + } + + if (g.gl_matchc == 1 && tmp_dst) { + /* If directory specified, append filename */ + if (remote_is_dir(conn, 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 (tmp_dst) { + abs_dst = path_append(tmp_dst, tmp); + xfree(tmp); + } else + abs_dst = make_absolute(tmp, pwd); + + printf(gettext("Uploading %s to %s\n"), g.gl_pathv[i], abs_dst); + if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1) + err = -1; + } + +out: + if (abs_dst) + xfree(abs_dst); + if (tmp_dst) + xfree(tmp_dst); + globfree(&g); + return(err); +} + +static int +sdirent_comp(const void *aa, const void *bb) +{ + SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; + SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; + int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; + +#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) + if (sort_flag & LS_NAME_SORT) + return (rmul * strcmp(a->filename, b->filename)); + else if (sort_flag & LS_TIME_SORT) + return (rmul * NCMP(a->a.mtime, b->a.mtime)); + else if (sort_flag & LS_SIZE_SORT) + return (rmul * NCMP(a->a.size, b->a.size)); + + fatal("Unknown ls sort type"); + + /* NOTREACHED */ + return (0); +} + +/* sftp ls.1 replacement for directories */ +static int +do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) +{ + int n; + u_int c = 1, colspace = 0, columns = 1; + SFTP_DIRENT **d; + + if ((n = do_readdir(conn, path, &d)) != 0) + return (n); + + if (!(lflag & LS_SHORT_VIEW)) { + u_int m = 0, width = 80; + struct winsize ws; + char *tmp; + + /* Count entries for sort and find longest filename */ + for (n = 0; d[n] != NULL; n++) { + if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) + m = MAX(m, strlen(d[n]->filename)); + } + + /* Add any subpath that also needs to be counted */ + tmp = path_strip(path, strip_path); + m += strlen(tmp); + xfree(tmp); + + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) + width = ws.ws_col; + + columns = width / (m + 2); + columns = MAX(columns, 1); + colspace = width / columns; + colspace = MIN(colspace, width); + } + + if (lflag & SORT_FLAGS) { + for (n = 0; d[n] != NULL; n++) + ; /* count entries */ + sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); + qsort(d, n, sizeof(*d), sdirent_comp); + } + + for (n = 0; d[n] != NULL && !interrupted; n++) { + char *tmp, *fname; + + if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) + continue; + + tmp = path_append(path, d[n]->filename); + fname = path_strip(tmp, strip_path); + xfree(tmp); + + if (lflag & LS_LONG_VIEW) { + if (lflag & LS_NUMERIC_VIEW) { + char *lname; + struct stat sb; + + memset(&sb, 0, sizeof(sb)); + attrib_to_stat(&d[n]->a, &sb); + lname = ls_file(fname, &sb, 1); + printf("%s\n", lname); + xfree(lname); + } else + printf("%s\n", d[n]->longname); + } else { + printf("%-*s", colspace, fname); + if (c >= columns) { + printf("\n"); + c = 1; + } else + c++; + } + + xfree(fname); + } + + if (!(lflag & LS_LONG_VIEW) && (c != 1)) + printf("\n"); + + free_sftp_dirents(d); + return (0); +} + +/* sftp ls.1 replacement which handles path globs */ +static int +do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, + int lflag) +{ + glob_t g; + u_int i, c = 1, colspace = 0, columns = 1; + Attrib *a = NULL; + + memset(&g, 0, sizeof(g)); + + if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, + NULL, &g) || (g.gl_pathc && !g.gl_matchc)) { + if (g.gl_pathc) + globfree(&g); + error("Can't ls: \"%s\" not found", path); + return (-1); + } + + if (interrupted) + goto out; + + /* + * If the glob returns a single match and it is a directory, + * then just list its contents. + */ + if (g.gl_matchc == 1) { + if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) { + globfree(&g); + return (-1); + } + if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && + S_ISDIR(a->perm)) { + int err; + + err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); + globfree(&g); + return (err); + } + } + + if (!(lflag & LS_SHORT_VIEW)) { + u_int m = 0, width = 80; + struct winsize ws; + + /* Count entries for sort and find longest filename */ + for (i = 0; g.gl_pathv[i]; i++) + m = MAX(m, strlen(g.gl_pathv[i])); + + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) + width = ws.ws_col; + + columns = width / (m + 2); + columns = MAX(columns, 1); + colspace = width / columns; + } + + for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) { + char *fname; + + fname = path_strip(g.gl_pathv[i], strip_path); + + if (lflag & LS_LONG_VIEW) { + char *lname; + struct stat sb; + + /* + * XXX: this is slow - 1 roundtrip per path + * A solution to this is to fork glob() and + * build a sftp specific version which keeps the + * attribs (which currently get thrown away) + * that the server returns as well as the filenames. + */ + memset(&sb, 0, sizeof(sb)); + if (a == NULL) + a = do_lstat(conn, g.gl_pathv[i], 1); + if (a != NULL) + attrib_to_stat(a, &sb); + lname = ls_file(fname, &sb, 1); + printf("%s\n", lname); + xfree(lname); + } else { + printf("%-*s", colspace, fname); + if (c >= columns) { + printf("\n"); + c = 1; + } else + c++; + } + xfree(fname); + } + + if (!(lflag & LS_LONG_VIEW) && (c != 1)) + printf("\n"); + + out: + if (g.gl_pathc) + globfree(&g); + + return (0); +} + +static int +parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, + 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 and lines which begin with comment '#' char */ + if (*cp == '\0' || *cp == '#') + return (0); + + /* Check for leading '-' (disable error processing) */ + *iflag = 0; + if (*cp == '-') { + *iflag = 1; + cp++; + } + + /* 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 */ + *lflag = *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: + if (parse_ls_flags(&cp, lflag)) + return(-1); + /* 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; + /* FALLTHRU */ + case I_CHMOD: + base = 8; + /* FALLTHRU */ + case I_CHOWN: + case I_CHGRP: + /* Get numeric arg (mandatory) */ + errno = 0; + 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: + case I_PROGRESS: + break; + default: + fatal("Command not implemented"); + } + + *cpp = cp; + return(cmdnum); +} + +static int +parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, + int err_abort) +{ + char *path1, *path2, *tmp; + int pflag, lflag, iflag, 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, &lflag, &iflag, &n_arg, + &path1, &path2); + + if (iflag != 0) + err_abort = 0; + + memset(&g, 0, sizeof(g)); + + /* Perform command */ + switch (cmdnum) { + case 0: + /* Blank line */ + break; + case -1: + /* Unrecognized command */ + err = -1; + break; + case I_GET: + err = process_get(conn, path1, path2, *pwd, pflag); + break; + case I_PUT: + err = process_put(conn, path1, path2, *pwd, pflag); + break; + case I_RENAME: + path1 = make_absolute(path1, *pwd); + path2 = make_absolute(path2, *pwd); + err = do_rename(conn, path1, path2); + break; + case I_SYMLINK: + path2 = make_absolute(path2, *pwd); + err = do_symlink(conn, path1, path2); + break; + case I_RM: + path1 = make_absolute(path1, *pwd); + remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + printf(gettext("Removing %s\n"), g.gl_pathv[i]); + err = do_rm(conn, g.gl_pathv[i]); + if (err != 0 && err_abort) + break; + } + break; + case I_MKDIR: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = 0777; + err = do_mkdir(conn, path1, &a); + break; + case I_RMDIR: + path1 = make_absolute(path1, *pwd); + err = do_rmdir(conn, path1); + break; + case I_CHDIR: + path1 = make_absolute(path1, *pwd); + if ((tmp = do_realpath(conn, path1)) == NULL) { + err = 1; + break; + } + if ((aa = do_stat(conn, 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_globbed_ls(conn, *pwd, *pwd, lflag); + break; + } + + /* Strip pwd off beginning of non-absolute paths */ + tmp = NULL; + if (*path1 != '/') + tmp = *pwd; + + path1 = make_absolute(path1, *pwd); + err = do_globbed_ls(conn, path1, tmp, lflag); + 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(gettext("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(conn, path1, GLOB_NOCHECK, NULL, &g); + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + printf(gettext("Changing mode on %s\n"), g.gl_pathv[i]); + err = do_setstat(conn, g.gl_pathv[i], &a); + if (err != 0 && err_abort) + break; + } + break; + case I_CHOWN: + case I_CHGRP: + path1 = make_absolute(path1, *pwd); + remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { + if (err != 0 && err_abort) + break; + else + continue; + } + if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { + error("Can't get current ownership of " + "remote file \"%s\"", g.gl_pathv[i]); + if (err != 0 && err_abort) + break; + else + continue; + } + aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; + if (cmdnum == I_CHOWN) { + printf(gettext("Changing owner on %s\n"), g.gl_pathv[i]); + aa->uid = n_arg; + } else { + printf(gettext("Changing group on %s\n"), g.gl_pathv[i]); + aa->gid = n_arg; + } + err = do_setstat(conn, g.gl_pathv[i], aa); + if (err != 0 && err_abort) + break; + } + break; + case I_PWD: + printf(gettext("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)); + err = -1; + break; + } + printf(gettext("Local working directory: %s\n"), path_buf); + break; + case I_QUIT: + /* Processed below */ + break; + case I_HELP: + help(); + break; + case I_VERSION: + printf(gettext("SFTP protocol version %u\n"), sftp_proto_version(conn)); + break; + case I_PROGRESS: + showprogress = !showprogress; + if (showprogress) + printf("Progress meter enabled\n"); + else + printf("Progress meter disabled\n"); + break; + default: + fatal("%d is not implemented", cmdnum); + } + + if (g.gl_pathc) + globfree(&g); + if (path1) + xfree(path1); + if (path2) + xfree(path2); + + /* If an unignored error occurs in batch mode we should abort. */ + if (err_abort && err != 0) + return (-1); + else if (cmdnum == I_QUIT) + return (1); + + return (0); +} + +#ifdef USE_LIBEDIT +static char * +prompt(EditLine *el) +{ + return ("sftp> "); +} +#endif + +int +interactive_loop(int fd_in, int fd_out, char *file1, char *file2) +{ + char *pwd; + char *dir = NULL; + char cmd[2048]; + struct sftp_conn *conn; + int err, interactive; + EditLine *el = NULL; +#ifdef USE_LIBEDIT + History *hl = NULL; + HistEvent hev; + + if (!batchmode && isatty(STDIN_FILENO)) { + if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) + fatal("Couldn't initialise editline"); + if ((hl = history_init()) == NULL) + fatal("Couldn't initialise editline history"); + history(hl, &hev, H_SETSIZE, 100); + el_set(el, EL_HIST, history, hl); + + el_set(el, EL_PROMPT, prompt); + el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_TERMINAL, NULL); + el_set(el, EL_SIGNAL, 1); + el_source(el, NULL); + } +#endif /* USE_LIBEDIT */ + + conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); + if (conn == NULL) + fatal("Couldn't initialise connection to server"); + + pwd = do_realpath(conn, "."); + if (pwd == NULL) + fatal("Need cwd"); + + if (file1 != NULL) { + dir = xstrdup(file1); + dir = make_absolute(dir, pwd); + + if (remote_is_dir(conn, dir) && file2 == NULL) { + printf(gettext("Changing to: %s\n"), dir); + snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); + if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) { + xfree(dir); + xfree(pwd); + xfree(conn); + return (-1); + } + } else { + if (file2 == NULL) + snprintf(cmd, sizeof cmd, "get %s", dir); + else + snprintf(cmd, sizeof cmd, "get %s %s", dir, + file2); + + err = parse_dispatch_command(conn, cmd, &pwd, 1); + xfree(dir); + xfree(pwd); + xfree(conn); + return (err); + } + xfree(dir); + } + +#if defined(HAVE_SETVBUF) && !defined(BROKEN_SETVBUF) + setvbuf(stdout, NULL, _IOLBF, 0); + setvbuf(infile, NULL, _IOLBF, 0); +#else + setlinebuf(stdout); + setlinebuf(infile); +#endif + + interactive = !batchmode && isatty(STDIN_FILENO); + err = 0; + for (;;) { + char *cp; + + signal(SIGINT, SIG_IGN); + + if (el == NULL) { + if (interactive) + printf("sftp> "); + if (fgets(cmd, sizeof(cmd), infile) == NULL) { + if (interactive) + printf("\n"); + break; + } + if (!interactive) { /* Echo command */ + printf("sftp> %s", cmd); + if (strlen(cmd) > 0 && + cmd[strlen(cmd) - 1] != '\n') + printf("\n"); + } + } +#ifdef USE_LIBEDIT + else { + const char *line; + int count = 0; + + if ((line = el_gets(el, &count)) == NULL || count <= 0) { + printf("\n"); + break; + } + history(hl, &hev, H_ENTER, line); + if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { + fprintf(stderr, gettext("Error: input line too long\n")); + continue; + } + } +#endif /* USE_LIBEDIT */ + + cp = strrchr(cmd, '\n'); + if (cp) + *cp = '\0'; + + /* Handle user interrupts gracefully during commands */ + interrupted = 0; + signal(SIGINT, cmd_interrupt); + + err = parse_dispatch_command(conn, cmd, &pwd, batchmode); + if (err != 0) + break; + } + xfree(pwd); + xfree(conn); + +#ifdef USE_LIBEDIT + if (el != NULL) + el_end(el); +#endif /* USE_LIBEDIT */ + + /* err == 1 signifies normal "quit" exit */ + return (err >= 0 ? 0 : -1); +} + static void -connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) +connect_to_server(char *path, char **args, int *in, int *out) { int c_in, c_out; @@ -78,23 +1426,34 @@ connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) c_in = c_out = inout[1]; #endif /* USE_PIPES */ - if ((*sshpid = fork()) == -1) + if ((sshpid = fork()) == -1) fatal("fork: %s", strerror(errno)); - else if (*sshpid == 0) { + 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); + _exit(1); } close(*in); close(*out); close(c_in); close(c_out); - execv(path, args); + + /* + * The underlying ssh is in the same process group, so we must + * ignore SIGINT if we want to gracefully abort commands, + * otherwise the signal will make it to the ssh process and + * kill it too + */ + signal(SIGINT, SIG_IGN); + execvp(path, args); fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); - exit(1); + _exit(1); } + signal(SIGTERM, killchild); + signal(SIGINT, killchild); + signal(SIGHUP, killchild); close(c_in); close(c_out); } @@ -102,24 +1461,20 @@ connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) static void usage(void) { - extern char *__progname; - fprintf(stderr, - gettext("Usage: %s [-vC1] [-b batchfile] [-o option] " - "[-s subsystem|path]\n" - " [-F config] [-P direct server path] [-S program] " - "[-B buffer_size]\n" - " [-R num_requests] [user@]host[:file [file]]\n"), - __progname); + gettext("Usage: %s [-1Cv] [-b batchfile] [-B buffer_size]\n" + " [-F ssh_config] [-o ssh_option] [-P sftp_server_path]\n" + " [-R num_requests] [-s subsystem | sftp_server]\n" + " [-S program] [user@]host[:dir[/] | :file [file]]\n"), + __progname, __progname, __progname, __progname); exit(1); } int main(int argc, char **argv) { - int in, out, ch; - pid_t sshpid; - char *host, *userhost, *cp, *file2; + int in, out, ch, err; + char *host, *userhost, *cp, *file2 = NULL; int debug_level = 0, sshver = 2; char *file1 = NULL, *sftp_server = NULL; char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; @@ -128,16 +1483,22 @@ main(int argc, char **argv) extern int optind; extern char *optarg; + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ + sanitise_stdfd(); + __progname = get_progname(argv[0]); (void) g11n_setlocale(LC_ALL, ""); + + memset(&args, '\0', sizeof(args)); args.list = NULL; - addargs(&args, "ssh"); /* overwritten with ssh_program */ + addargs(&args, "%s", ssh_program); addargs(&args, "-oForwardX11 no"); addargs(&args, "-oForwardAgent no"); addargs(&args, "-oClearAllForwardings yes"); + ll = SYSLOG_LEVEL_INFO; - infile = stdin; /* Read from STDIN unless changed by -b */ + infile = stdin; while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { switch (ch) { @@ -165,14 +1526,19 @@ main(int argc, char **argv) break; case 'S': ssh_program = optarg; + replacearg(&args, 0, "%s", ssh_program); break; case 'b': - if (infile == stdin) { - infile = fopen(optarg, "r"); - if (infile == NULL) - fatal("%s (%s).", strerror(errno), optarg); - } else - fatal("Filename already specified."); + if (batchmode) + fatal("Batch file already specified."); + + /* Allow "-" as stdin */ + if (strcmp(optarg, "-") != 0 && + (infile = fopen(optarg, "r")) == NULL) + fatal("%s (%s).", strerror(errno), optarg); + showprogress = 0; + batchmode = 1; + addargs(&args, "-obatchmode yes"); break; case 'P': sftp_direct = optarg; @@ -194,6 +1560,9 @@ main(int argc, char **argv) } } + if (!isatty(STDERR_FILENO)) + showprogress = 0; + log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); if (sftp_direct == NULL) { @@ -203,12 +1572,7 @@ main(int argc, char **argv) userhost = xstrdup(argv[optind]); file2 = argv[optind+1]; - if ((cp = colon(userhost)) != NULL) { - *cp++ = '\0'; - file1 = cp; - } - - if ((host = strchr(userhost, '@')) == NULL) + if ((host = strrchr(userhost, '@')) == NULL) host = userhost; else { *host++ = '\0'; @@ -216,7 +1580,12 @@ main(int argc, char **argv) fprintf(stderr, gettext("Missing username\n")); usage(); } - addargs(&args, "-l%s",userhost); + addargs(&args, "-l%s", userhost); + } + + if ((cp = colon(host)) != NULL) { + *cp++ = '\0'; + file1 = cp; } host = cleanhostname(host); @@ -234,21 +1603,21 @@ main(int argc, char **argv) addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); - args.list[0] = ssh_program; - fprintf(stderr, gettext("Connecting to %s...\n"), host); - connect_to_server(ssh_program, args.list, &in, &out, - &sshpid); + if (!batchmode) + fprintf(stderr, gettext("Connecting to %s...\n"), host); + connect_to_server(ssh_program, args.list, &in, &out); } else { args.list = NULL; addargs(&args, "sftp-server"); - fprintf(stderr, gettext("Attaching to %s...\n"), sftp_direct); - connect_to_server(sftp_direct, args.list, &in, &out, - &sshpid); + if (!batchmode) + fprintf(stderr, gettext("Attaching to %s...\n"), sftp_direct); + connect_to_server(sftp_direct, args.list, &in, &out); } + freeargs(&args); - interactive_loop(in, out, file1, file2); + err = interactive_loop(in, out, file1, file2); #if !defined(USE_PIPES) shutdown(in, SHUT_RDWR); @@ -257,7 +1626,7 @@ main(int argc, char **argv) close(in); close(out); - if (infile != stdin) + if (batchmode) fclose(infile); while (waitpid(sshpid, NULL, 0) == -1) @@ -265,5 +1634,5 @@ main(int argc, char **argv) fatal("Couldn't wait for ssh process: %s", strerror(errno)); - return (0); + return (err == 0 ? 0 : 1); } diff --git a/usr/src/cmd/ssh/ssh.po b/usr/src/cmd/ssh/ssh.po index ff264a13ca..0bb056d810 100644 --- a/usr/src/cmd/ssh/ssh.po +++ b/usr/src/cmd/ssh/ssh.po @@ -4,6 +4,7 @@ # #pragma ident "%Z%%M% %I% %E% SMI" # + # # File: ../common/bsd-arc4random.c, line: 76 #, c-format @@ -239,34 +240,34 @@ msgstr "" msgid "buffer_get_char: buffer error" msgstr "" # -# File: ../common/buffer.c, line: 86 +# File: ../common/buffer.c, line: 107 #, c-format msgid "buffer_append_space: len %u not supported" msgstr "" # -# File: ../common/buffer.c, line: 116 +# File: ../common/buffer.c, line: 129 #, c-format msgid "buffer_append_space: alloc %u not supported" msgstr "" # -# File: ../common/buffer.c, line: 138 +# File: ../common/buffer.c, line: 173 #, c-format msgid "buffer_get_ret: trying to get more bytes %d than in buffer %d" msgstr "" # -# File: ../common/buffer.c, line: 151 +# File: ../common/buffer.c, line: 186 msgid "buffer_get: buffer error" msgstr "" # -# File: ../common/buffer.c, line: 160 +# File: ../common/buffer.c, line: 195 msgid "buffer_consume_ret: trying to get more bytes than in buffer" msgstr "" # -# File: ../common/buffer.c, line: 171 +# File: ../common/buffer.c, line: 206 msgid "buffer_consume: buffer error" msgstr "" # -# File: ../common/buffer.c, line: 189 +# File: ../common/buffer.c, line: 224 msgid "buffer_consume_end: trying to get more bytes than in buffer" msgstr "" # @@ -289,97 +290,123 @@ msgstr "" msgid "get_sock_port: getnameinfo NI_NUMERICSERV failed" msgstr "" # -# File: ../common/channels.c, line: 196 +# File: ../common/channels.c, line: 197 #, c-format msgid "channel %d: wfd %d is not a tty?" msgstr "" # -# File: ../common/channels.c, line: 247 +# File: ../common/channels.c, line: 248 #, c-format msgid "channel_new: internal error: channels_alloc %d too big." msgstr "" # -# File: ../common/channels.c, line: 467 +# File: ../common/channels.c, line: 468 msgid "cannot happen: SSH_CHANNEL_LARVAL" msgstr "" # -# File: ../common/channels.c, line: 476 -# File: ../common/channels.c, line: 516 +# File: ../common/channels.c, line: 477 +# File: ../common/channels.c, line: 517 msgid "cannot happen: OUT_DRAIN" msgstr "" # -# File: ../common/channels.c, line: 479 +# File: ../common/channels.c, line: 480 #, c-format msgid "channel_still_open: bad channel type %d" msgstr "" # -# File: ../common/channels.c, line: 519 +# File: ../common/channels.c, line: 520 #, c-format msgid "channel_find_open: bad channel type %d" msgstr "" # -# File: ../common/channels.c, line: 574 +# File: ../common/channels.c, line: 575 #, c-format msgid "channel_open_message: bad channel type %d" msgstr "" # -# File: ../common/channels.c, line: 669 +# File: ../common/channels.c, line: 670 #, c-format msgid "channel_activate for non-larval channel %d." msgstr "" # -# File: ../common/channels.c, line: 685 +# File: ../common/channels.c, line: 686 #, c-format msgid "channel_set_wait_for_exit for non-open channel %d." msgstr "" # -# File: ../common/channels.c, line: 835 +# File: ../common/channels.c, line: 836 #, c-format msgid "X11 fake_data_len %d != saved_data_len %d" msgstr "" # -# File: ../common/channels.c, line: 947 +# File: ../common/channels.c, line: 948 #, c-format msgid "channel %d: decode socks4: len %d > have %d" msgstr "" # +# File: ../common/channels.c, line: 1013 +#, c-format +msgid "channel %d: socks5 authentication methods not implemented" +msgstr "" +# +# File: ../common/channels.c, line: 1015 +#, c-format +msgid "" +"channel %d: forwarding failed: SSH_SOCKS5_NOAUTH method not found" +msgstr "" +# # File: ../common/channels.c, line: 1034 -# File: ../common/channels.c, line: 1158 +#, c-format +msgid "channel %d: forwarding failed: only socks5 connect is supported" +msgstr "" +# +# File: ../common/channels.c, line: 1052 +#, c-format +msgid "channel %d: forwarding failed: bad socks5 atyp %d" +msgstr "" +# +# File: ../common/channels.c, line: 1117 +#, c-format +msgid "channel %d: forwarding failed: unknown socks version 0x%02X" +msgstr "" +# +# File: ../common/channels.c, line: 1156 +# File: ../common/channels.c, line: 1280 # File: sshd.c, line: 1489 #, c-format msgid "accept: %.100s" msgstr "" # -# File: ../common/channels.c, line: 1202 +# File: ../common/channels.c, line: 1324 #, c-format msgid "accept from auth socket: %.100s" msgstr "" # -# File: ../common/channels.c, line: 1233 +# File: ../common/channels.c, line: 1355 msgid "getsockopt SO_ERROR failed" msgstr "" # -# File: ../common/channels.c, line: 1685 +# File: ../common/channels.c, line: 1807 msgid "cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3" msgstr "" # -# File: ../common/channels.c, line: 1738 +# File: ../common/channels.c, line: 1860 #, c-format msgid "Received data for nonexistent channel %d." msgstr "" # -# File: ../common/channels.c, line: 1765 -# File: ../common/channels.c, line: 1803 -# File: ../common/channels.c, line: 1823 -# File: ../common/channels.c, line: 1846 -# File: ../common/channels.c, line: 1886 -# File: ../common/channels.c, line: 1898 -# File: ../common/channels.c, line: 1936 -# File: ../common/channels.c, line: 1981 -# File: ../common/channels.c, line: 2006 -# File: ../common/channels.c, line: 2028 -# File: ../common/channels.c, line: 2634 -# File: ../common/channels.c, line: 2777 +# File: ../common/channels.c, line: 1887 +# File: ../common/channels.c, line: 1925 +# File: ../common/channels.c, line: 1945 +# File: ../common/channels.c, line: 1968 +# File: ../common/channels.c, line: 2008 +# File: ../common/channels.c, line: 2020 +# File: ../common/channels.c, line: 2058 +# File: ../common/channels.c, line: 2103 +# File: ../common/channels.c, line: 2128 +# File: ../common/channels.c, line: 2150 +# File: ../common/channels.c, line: 2756 +# File: ../common/channels.c, line: 2895 # File: ../common/kex.c, line: 175 # File: ../common/kex.c, line: 248 # File: ../common/kexdhc.c, line: 88 @@ -389,37 +416,15 @@ msgstr "" # File: ../common/kexgexs.c, line: 81 # File: ../common/kexgexs.c, line: 111 # File: ../common/packet.c, line: 807 -# File: ssh.c, line: 993 -# File: ssh.c, line: 1041 -# File: sshconnect1.c, line: 122 -# File: sshconnect1.c, line: 260 -# File: sshconnect1.c, line: 377 -# File: sshconnect1.c, line: 437 -# File: sshconnect1.c, line: 560 -# File: sshconnect2.c, line: 326 -# File: sshconnect2.c, line: 439 -# File: sshconnect2.c, line: 473 -# File: sshconnect2.c, line: 646 -# File: sshconnect2.c, line: 698 -# File: sshconnect2.c, line: 781 -# File: sshconnect2.c, line: 806 -# File: sshconnect2.c, line: 1372 -# File: clientloop.c, line: 1147 -# File: clientloop.c, line: 1157 -# File: clientloop.c, line: 1166 -# File: clientloop.c, line: 1193 -# File: clientloop.c, line: 1233 -# File: clientloop.c, line: 1348 -# File: sshd.c, line: 2043 # File: altprivsep.c, line: 568 # File: altprivsep.c, line: 655 +# File: auth-rsa.c, line: 146 # File: auth1.c, line: 139 # File: auth1.c, line: 170 # File: auth1.c, line: 188 # File: auth1.c, line: 207 # File: auth1.c, line: 240 # File: auth1.c, line: 331 -# File: auth2.c, line: 139 # File: auth2-chall.c, line: 280 # File: auth2-gss.c, line: 87 # File: auth2-gss.c, line: 137 @@ -429,11 +434,17 @@ msgstr "" # File: auth2-gss.c, line: 353 # File: auth2-kbdint.c, line: 53 # File: auth2-none.c, line: 107 -# File: auth2-passwd.c, line: 58 # File: auth2-pam.c, line: 378 +# File: auth2-passwd.c, line: 58 # File: auth2-pubkey.c, line: 130 # File: auth2-pubkey.c, line: 163 -# File: auth-rsa.c, line: 146 +# File: auth2.c, line: 139 +# File: clientloop.c, line: 1294 +# File: clientloop.c, line: 1304 +# File: clientloop.c, line: 1313 +# File: clientloop.c, line: 1340 +# File: clientloop.c, line: 1380 +# File: clientloop.c, line: 1495 # File: serverloop.c, line: 1024 # File: serverloop.c, line: 1040 # File: serverloop.c, line: 1053 @@ -449,218 +460,234 @@ msgstr "" # File: session.c, line: 1717 # File: session.c, line: 1727 # File: session.c, line: 1737 +# File: ssh.c, line: 929 +# File: ssh.c, line: 977 +# File: sshconnect1.c, line: 122 +# File: sshconnect1.c, line: 260 +# File: sshconnect1.c, line: 377 +# File: sshconnect1.c, line: 437 +# File: sshconnect1.c, line: 560 +# File: sshconnect2.c, line: 327 +# File: sshconnect2.c, line: 449 +# File: sshconnect2.c, line: 483 +# File: sshconnect2.c, line: 656 +# File: sshconnect2.c, line: 708 +# File: sshconnect2.c, line: 791 +# File: sshconnect2.c, line: 816 +# File: sshconnect2.c, line: 1382 +# File: sshd.c, line: 2043 msgid "Packet integrity error." msgstr "" # -# File: ../common/channels.c, line: 1783 +# File: ../common/channels.c, line: 1905 #, c-format msgid "Received extended_data for bad channel %d." msgstr "" # -# File: ../common/channels.c, line: 1792 +# File: ../common/channels.c, line: 1914 #, c-format msgid "Received extended_data after EOF on channel %d." msgstr "" # -# File: ../common/channels.c, line: 1826 +# File: ../common/channels.c, line: 1948 #, c-format msgid "Received ieof for nonexistent channel %d." msgstr "" # -# File: ../common/channels.c, line: 1849 +# File: ../common/channels.c, line: 1971 #, c-format msgid "Received close for nonexistent channel %d." msgstr "" # -# File: ../common/channels.c, line: 1888 +# File: ../common/channels.c, line: 2010 #, c-format msgid "Received oclose for nonexistent channel %d." msgstr "" # -# File: ../common/channels.c, line: 1900 +# File: ../common/channels.c, line: 2022 #, c-format msgid "Received close confirmation for out-of-range channel %d." msgstr "" # -# File: ../common/channels.c, line: 1903 +# File: ../common/channels.c, line: 2025 #, c-format msgid "Received close confirmation for non-closed channel %d (type %d)." msgstr "" # -# File: ../common/channels.c, line: 1918 +# File: ../common/channels.c, line: 2040 #, c-format msgid "Received open confirmation for non-opening channel %d." msgstr "" # -# File: ../common/channels.c, line: 1966 +# File: ../common/channels.c, line: 2088 #, c-format msgid "Received open failure for non-opening channel %d." msgstr "" # -# File: ../common/channels.c, line: 2068 +# File: ../common/channels.c, line: 2190 msgid "No forward host name." msgstr "" # -# File: ../common/channels.c, line: 2072 +# File: ../common/channels.c, line: 2194 msgid "Forward host name too long." msgstr "" # -# File: ../common/channels.c, line: 2087 +# File: ../common/channels.c, line: 2209 msgid "getaddrinfo: fatal error" msgstr "" # -# File: ../common/channels.c, line: 2094 +# File: ../common/channels.c, line: 2216 msgid "channel_setup_fwd_listener: getnameinfo failed" msgstr "" # -# File: ../common/channels.c, line: 2101 -# File: ../common/channels.c, line: 2327 -# File: ../common/channels.c, line: 2427 -# File: ../common/channels.c, line: 2502 +# File: ../common/channels.c, line: 2223 +# File: ../common/channels.c, line: 2449 +# File: ../common/channels.c, line: 2549 +# File: ../common/channels.c, line: 2624 +# File: session.c, line: 203 # File: sshconnect.c, line: 206 # File: sshd.c, line: 1343 -# File: session.c, line: 203 #, c-format msgid "socket: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2111 +# File: ../common/channels.c, line: 2233 # File: sshd.c, line: 1358 #, c-format msgid "setsockopt SO_REUSEADDR: %s" msgstr "" # -# File: ../common/channels.c, line: 2119 -# File: ../common/channels.c, line: 2121 +# File: ../common/channels.c, line: 2241 +# File: ../common/channels.c, line: 2243 # File: session.c, line: 211 #, c-format msgid "bind: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2128 -# File: ../common/channels.c, line: 2473 -# File: sshd.c, line: 1376 +# File: ../common/channels.c, line: 2250 +# File: ../common/channels.c, line: 2595 # File: session.c, line: 218 +# File: sshd.c, line: 1376 #, c-format msgid "listen: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2142 +# File: ../common/channels.c, line: 2264 #, c-format msgid "channel_setup_fwd_listener: cannot listen to port: %d" msgstr "" # -# File: ../common/channels.c, line: 2180 -# File: ../common/channels.c, line: 2277 +# File: ../common/channels.c, line: 2302 +# File: ../common/channels.c, line: 2399 msgid "channel_request_remote_forwarding: too many forwards" msgstr "" # -# File: ../common/channels.c, line: 2213 +# File: ../common/channels.c, line: 2335 #, c-format msgid "Protocol error for port forward request:received packet type %d." msgstr "" # -# File: ../common/channels.c, line: 2250 +# File: ../common/channels.c, line: 2372 #, c-format msgid "Requested forwarding of port %d but user is not root." msgstr "" # -# File: ../common/channels.c, line: 2313 +# File: ../common/channels.c, line: 2435 #, c-format msgid "connect_to %.100s: unknown host (%s)" msgstr "" # -# File: ../common/channels.c, line: 2322 +# File: ../common/channels.c, line: 2444 msgid "connect_to: getnameinfo failed" msgstr "" # -# File: ../common/channels.c, line: 2331 +# File: ../common/channels.c, line: 2453 #, c-format msgid "connect_to: F_SETFL: %s" msgstr "" # -# File: ../common/channels.c, line: 2334 +# File: ../common/channels.c, line: 2456 #, c-format msgid "connect_to %.100s port %s: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2344 +# File: ../common/channels.c, line: 2466 #, c-format msgid "connect_to %.100s port %d: failed." msgstr "" # -# File: ../common/channels.c, line: 2362 +# File: ../common/channels.c, line: 2484 #, c-format msgid "WARNING: Server requests forwarding for unknown listen_port %d" msgstr "" # -# File: ../common/channels.c, line: 2418 +# File: ../common/channels.c, line: 2540 #, c-format msgid "getaddrinfo: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2439 +# File: ../common/channels.c, line: 2561 #, c-format msgid "setsockopt IPV6_V6ONLY: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2466 +# File: ../common/channels.c, line: 2588 msgid "Failed to allocate internet-domain X11 display socket." msgstr "" # -# File: ../common/channels.c, line: 2509 +# File: ../common/channels.c, line: 2631 #, c-format msgid "connect %.100s: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2526 +# File: ../common/channels.c, line: 2648 msgid "DISPLAY not set." msgstr "" # -# File: ../common/channels.c, line: 2544 -# File: ../common/channels.c, line: 2570 +# File: ../common/channels.c, line: 2666 +# File: ../common/channels.c, line: 2692 #, c-format msgid "Could not parse display number from DISPLAY: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2564 +# File: ../common/channels.c, line: 2686 #, c-format msgid "Could not find ':' in DISPLAY: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2581 +# File: ../common/channels.c, line: 2703 #, c-format msgid "%.100s: unknown host. (%s)" msgstr "" # -# File: ../common/channels.c, line: 2603 +# File: ../common/channels.c, line: 2725 #, c-format msgid "connect %.100s port %d: %.100s" msgstr "" # -# File: ../common/channels.c, line: 2667 -# File: clientloop.c, line: 1256 +# File: ../common/channels.c, line: 2789 +# File: clientloop.c, line: 1403 msgid "Warning: ssh server tried agent forwarding." msgstr "" # -# File: ../common/channels.c, line: 2670 -# File: clientloop.c, line: 1222 +# File: ../common/channels.c, line: 2792 +# File: clientloop.c, line: 1369 msgid "Warning: ssh server tried X11 forwarding." msgstr "" # -# File: ../common/channels.c, line: 2673 +# File: ../common/channels.c, line: 2795 #, c-format msgid "deny_input_open: type %d" msgstr "" # -# File: ../common/channels.c, line: 2676 -# File: clientloop.c, line: 1223 -# File: clientloop.c, line: 1257 +# File: ../common/channels.c, line: 2798 +# File: clientloop.c, line: 1370 +# File: clientloop.c, line: 1404 msgid "" "Warning: this is probably a break in attempt by a malicious server." msgstr "" # -# File: ../common/channels.c, line: 2721 +# File: ../common/channels.c, line: 2843 #, c-format msgid "x11_request_forwarding: bad authentication data: %.100s" msgstr "" @@ -1338,6 +1365,29 @@ msgstr "" msgid "setsockopt TCP_NODELAY: %.100s" msgstr "" # +# File: ../common/misc.c, line: 365 +msgid "replacearg: argument too long" +msgstr "" +# +# File: ../common/misc.c, line: 368 +#, c-format +msgid "replacearg: tried to replace invalid arg %d >= %d" +msgstr "" +# +# File: ../common/misc.c, line: 549 +# File: ../common/readconf.c, line: 466 +# File: ../common/readconf.c, line: 487 +# File: ../common/readconf.c, line: 547 +# File: ../common/readconf.c, line: 567 +# File: ../common/readconf.c, line: 579 +# File: ../common/readconf.c, line: 590 +# File: ../common/readconf.c, line: 601 +# File: ../common/readconf.c, line: 613 +# File: ../common/readconf.c, line: 695 +#, c-format +msgid "%.200s line %d: Missing argument." +msgstr "" +# # File: ../common/nchan.c, line: 90 #, c-format msgid "chan_set_istate: bad state %d -> %d" @@ -1866,10 +1916,10 @@ msgid "%s: struct passwd size mismatch" msgstr "" # # File: ../common/monitor_wrap.c, line: 310 -# File: sshconnect2.c, line: 966 -# File: sshconnect2.c, line: 1342 -# File: sshconnect2.c, line: 1344 # File: auth.c, line: 542 +# File: sshconnect2.c, line: 976 +# File: sshconnect2.c, line: 1352 +# File: sshconnect2.c, line: 1354 #, c-format msgid "%s" msgstr "" @@ -1952,165 +2002,197 @@ msgstr "" msgid "%s: no fd" msgstr "" # -# File: ../common/readconf.c, line: 208 +# File: ../common/readconf.c, line: 214 msgid "Privileged ports can only be forwarded by root." msgstr "" # -# File: ../common/readconf.c, line: 211 +# File: ../common/readconf.c, line: 217 #, c-format msgid "Too many local forwards (max %d)." msgstr "" # -# File: ../common/readconf.c, line: 230 +# File: ../common/readconf.c, line: 236 #, c-format msgid "Too many remote forwards (max %d)." msgstr "" # -# File: ../common/readconf.c, line: 265 +# File: ../common/readconf.c, line: 271 # File: servconf.c, line: 482 #, c-format msgid "%s: line %d: Bad configuration option: %s" msgstr "" # -# File: ../common/readconf.c, line: 307 +# File: ../common/readconf.c, line: 313 # File: servconf.c, line: 587 #, c-format msgid "%s line %d: missing time value." msgstr "" # -# File: ../common/readconf.c, line: 310 +# File: ../common/readconf.c, line: 316 # File: servconf.c, line: 590 #, c-format msgid "%s line %d: invalid time value." msgstr "" # -# File: ../common/readconf.c, line: 321 +# File: ../common/readconf.c, line: 327 #, c-format msgid "%.200s line %d: Missing yes/no argument." msgstr "" # -# File: ../common/readconf.c, line: 328 +# File: ../common/readconf.c, line: 334 #, c-format msgid "%.200s line %d: Bad yes/no argument." msgstr "" # -# File: ../common/readconf.c, line: 418 +# File: ../common/readconf.c, line: 428 #, c-format msgid "%.200s line %d: Missing yes/no/ask argument." msgstr "" # -# File: ../common/readconf.c, line: 428 +# File: ../common/readconf.c, line: 438 #, c-format msgid "%.200s line %d: Bad yes/no/ask argument." msgstr "" # -# File: ../common/readconf.c, line: 456 -# File: ../common/readconf.c, line: 477 -# File: ../common/readconf.c, line: 537 -# File: ../common/readconf.c, line: 557 -# File: ../common/readconf.c, line: 569 -# File: ../common/readconf.c, line: 580 -# File: ../common/readconf.c, line: 591 -# File: ../common/readconf.c, line: 603 -# File: ../common/readconf.c, line: 685 -#, c-format -msgid "%.200s line %d: Missing argument." -msgstr "" -# -# File: ../common/readconf.c, line: 460 +# File: ../common/readconf.c, line: 470 #, c-format msgid "%.200s line %d: Too many identity files specified (max %d)." msgstr "" # -# File: ../common/readconf.c, line: 539 -# File: ../common/readconf.c, line: 544 +# File: ../common/readconf.c, line: 549 +# File: ../common/readconf.c, line: 554 #, c-format msgid "%.200s line %d: Bad number." msgstr "" # -# File: ../common/readconf.c, line: 560 +# File: ../common/readconf.c, line: 570 #, c-format msgid "%.200s line %d: Bad cipher '%s'." msgstr "" # -# File: ../common/readconf.c, line: 571 +# File: ../common/readconf.c, line: 581 #, c-format msgid "%.200s line %d: Bad SSH2 cipher spec '%s'." msgstr "" # -# File: ../common/readconf.c, line: 582 +# File: ../common/readconf.c, line: 592 #, c-format msgid "%.200s line %d: Bad SSH2 Mac spec '%s'." msgstr "" # -# File: ../common/readconf.c, line: 593 +# File: ../common/readconf.c, line: 603 #, c-format msgid "%.200s line %d: Bad protocol 2 host key algorithms '%s'." msgstr "" # -# File: ../common/readconf.c, line: 606 +# File: ../common/readconf.c, line: 616 #, c-format msgid "%.200s line %d: Bad protocol spec '%s'." msgstr "" # -# File: ../common/readconf.c, line: 617 +# File: ../common/readconf.c, line: 627 # File: servconf.c, line: 826 #, c-format msgid "%.200s line %d: unsupported log level '%s'" msgstr "" # -# File: ../common/readconf.c, line: 627 -# File: ../common/readconf.c, line: 656 +# File: ../common/readconf.c, line: 637 +# File: ../common/readconf.c, line: 666 #, c-format msgid "%.200s line %d: Missing port argument." msgstr "" # -# File: ../common/readconf.c, line: 630 +# File: ../common/readconf.c, line: 640 #, c-format msgid "%.200s line %d: Bad listen port." msgstr "" # -# File: ../common/readconf.c, line: 634 +# File: ../common/readconf.c, line: 644 #, c-format msgid "%.200s line %d: Missing second argument." msgstr "" # -# File: ../common/readconf.c, line: 638 +# File: ../common/readconf.c, line: 648 #, c-format msgid "%.200s line %d: Bad forwarding specification." msgstr "" # -# File: ../common/readconf.c, line: 641 +# File: ../common/readconf.c, line: 651 #, c-format msgid "%.200s line %d: Bad forwarding port." msgstr "" # -# File: ../common/readconf.c, line: 660 +# File: ../common/readconf.c, line: 670 #, c-format msgid "%.200s line %d: Badly formatted port number." msgstr "" # -# File: ../common/readconf.c, line: 694 +# File: ../common/readconf.c, line: 704 #, c-format msgid "%.200s line %d: Bad escape character." msgstr "" # -# File: ../common/readconf.c, line: 709 +# File: ../common/readconf.c, line: 730 +#, c-format +msgid "%.200s line %d: Bad yes/no/in-exec-mode argument." +msgstr "" +# +# File: ../common/readconf.c, line: 740 #, c-format msgid "process_config_line: Unimplemented opcode %d" msgstr "" # -# File: ../common/readconf.c, line: 714 +# File: ../common/readconf.c, line: 745 #, c-format msgid "%.200s line %d: garbage at end of line; \"%.200s\"." msgstr "" # -# File: ../common/readconf.c, line: 758 +# File: ../common/readconf.c, line: 789 # File: servconf.c, line: 1035 #, c-format msgid "%s: terminating, %d bad configuration options" msgstr "" # +# File: ../common/sftp-common.c, line: 164 +msgid "No error" +msgstr "" +# +# File: ../common/sftp-common.c, line: 166 +msgid "End of file" +msgstr "" +# +# File: ../common/sftp-common.c, line: 168 +msgid "No such file or directory" +msgstr "" +# +# File: ../common/sftp-common.c, line: 170 +msgid "Permission denied" +msgstr "" +# +# File: ../common/sftp-common.c, line: 172 +msgid "Failure" +msgstr "" +# +# File: ../common/sftp-common.c, line: 174 +msgid "Bad message" +msgstr "" +# +# File: ../common/sftp-common.c, line: 176 +msgid "No connection" +msgstr "" +# +# File: ../common/sftp-common.c, line: 178 +msgid "Connection lost" +msgstr "" +# +# File: ../common/sftp-common.c, line: 180 +msgid "Operation unsupported" +msgstr "" +# +# File: ../common/sftp-common.c, line: 182 +msgid "Unknown status" +msgstr "" +# # File: ssh.c, line: 164 #, c-format msgid "" @@ -2123,8 +2205,8 @@ msgid "" " -a Disable authentication agent forwarding (default).\n" " -X Enable X11 connection forwarding.\n" " -x Disable X11 connection forwarding (default).\n" -" -i file Identity for public key authentication (default: ~/.ssh/" -"identity)\n" +" -i file Identity for public key authentication (default: " +"~/.ssh/identity)\n" " -t Tty; allocate a tty even if command is given.\n" " -T Do not allocate a tty.\n" " -v Verbose; display verbose debugging messages.\n" @@ -2141,8 +2223,8 @@ msgid "" " -R listen-port:host:port Forward remote port to local address\n" " These cause %s to listen for connections on a port, " "and\n" -" forward them to the other side by connecting to host:" -"port.\n" +" forward them to the other side by connecting to " +"host:port.\n" " -D port Enable dynamic application-level port forwarding.\n" " -C Enable compression.\n" " -N Do not execute a shell or command.\n" @@ -2167,7 +2249,6 @@ msgid "You don't exist, go away!" msgstr "" # # File: ssh.c, line: 329 -#, c-format msgid "Warning: Option -P has been deprecated\n" msgstr "" # @@ -2181,8 +2262,8 @@ msgstr "" msgid "Too many identity files specified (max %d)" msgstr "" # -# File: ssh.c, line: 372 # File: ssh-keyscan.c, line: 725 +# File: ssh.c, line: 372 msgid "Too high debugging level." msgstr "" # @@ -2206,8 +2287,8 @@ msgstr "" msgid "Unknown mac type '%s'\n" msgstr "" # -# File: ssh.c, line: 440 # File: ssh-keyscan.c, line: 704 +# File: ssh.c, line: 440 #, c-format msgid "Bad port '%s'\n" msgstr "" @@ -2228,7 +2309,6 @@ msgid "Bad dynamic port '%s'\n" msgstr "" # # File: ssh.c, line: 562 -#, c-format msgid "You must specify a subsystem to invoke.\n" msgstr "" # @@ -2256,95 +2336,89 @@ msgstr "" msgid "Could not create directory '%.200s'." msgstr "" # -# File: ssh.c, line: 838 -msgid "" -"Warning: No xauth data; using fake authentication data for X11 " -"forwarding." -msgstr "" -# -# File: ssh.c, line: 868 +# File: ssh.c, line: 801 msgid "Could not request local forwarding." msgstr "" # -# File: ssh.c, line: 907 +# File: ssh.c, line: 841 msgid "Compression level must be from 1 (fast) to 9 (slow, best)." msgstr "" # -# File: ssh.c, line: 918 +# File: ssh.c, line: 852 msgid "Warning: Remote host refused compression." msgstr "" # -# File: ssh.c, line: 920 +# File: ssh.c, line: 854 msgid "Protocol error waiting for compression response." msgstr "" # -# File: ssh.c, line: 958 +# File: ssh.c, line: 892 msgid "Warning: Remote host failed or refused to allocate a pseudo tty." msgstr "" # -# File: ssh.c, line: 960 +# File: ssh.c, line: 894 msgid "Protocol error waiting for pty request response." msgstr "" # -# File: ssh.c, line: 976 +# File: ssh.c, line: 912 msgid "Warning: Remote host denied X11 forwarding." msgstr "" # -# File: ssh.c, line: 978 +# File: ssh.c, line: 914 msgid "Protocol error waiting for X11 forwarding" msgstr "" # -# File: ssh.c, line: 993 -# File: ssh.c, line: 1041 +# File: clientloop.c, line: 1294 +# File: clientloop.c, line: 1304 +# File: clientloop.c, line: 1313 +# File: clientloop.c, line: 1340 +# File: clientloop.c, line: 1380 +# File: clientloop.c, line: 1495 +# File: ssh.c, line: 929 +# File: ssh.c, line: 977 # File: sshconnect1.c, line: 122 # File: sshconnect1.c, line: 260 # File: sshconnect1.c, line: 377 # File: sshconnect1.c, line: 437 # File: sshconnect1.c, line: 560 -# File: sshconnect2.c, line: 326 -# File: sshconnect2.c, line: 439 -# File: sshconnect2.c, line: 473 -# File: sshconnect2.c, line: 646 -# File: sshconnect2.c, line: 698 -# File: sshconnect2.c, line: 781 -# File: sshconnect2.c, line: 806 -# File: sshconnect2.c, line: 1372 -# File: clientloop.c, line: 1147 -# File: clientloop.c, line: 1157 -# File: clientloop.c, line: 1166 -# File: clientloop.c, line: 1193 -# File: clientloop.c, line: 1233 -# File: clientloop.c, line: 1348 +# File: sshconnect2.c, line: 327 +# File: sshconnect2.c, line: 449 +# File: sshconnect2.c, line: 483 +# File: sshconnect2.c, line: 656 +# File: sshconnect2.c, line: 708 +# File: sshconnect2.c, line: 791 +# File: sshconnect2.c, line: 816 +# File: sshconnect2.c, line: 1382 #, c-format msgid "Packet integrity error (%d bytes remaining) at %s:%d" msgstr "" # -# File: ssh.c, line: 995 +# File: ssh.c, line: 931 msgid "Warning: Remote host denied authentication agent forwarding." msgstr "" # -# File: ssh.c, line: 1004 -# File: ssh.c, line: 1226 +# File: ssh.c, line: 940 +# File: ssh.c, line: 1162 # File: sshd.c, line: 1284 #, c-format msgid "daemon() failed: %.200s" msgstr "" # -# File: ssh.c, line: 1043 +# File: ssh.c, line: 979 #, c-format msgid "Request for subsystem '%.*s' failed on channel %d" msgstr "" # -# File: ssh.c, line: 1064 +# File: ssh.c, line: 997 #, c-format msgid "Warning: remote port forwarding failed for listen port %d" msgstr "" # -# File: ssh.c, line: 1182 +# File: ssh.c, line: 1118 msgid "dup() in/out/err failed" msgstr "" # -# File: ssh.c, line: 1262 +# File: ssh.c, line: 1198 msgid "Using rsh. WARNING: Connection will not be encrypted." msgstr "" # @@ -2353,9 +2427,9 @@ msgstr "" msgid "Could not create pipes to communicate with the proxy: %.100s" msgstr "" # -# File: sshconnect.c, line: 160 # File: session.c, line: 458 # File: session.c, line: 577 +# File: sshconnect.c, line: 160 #, c-format msgid "fork failed: %.100s" msgstr "" @@ -2647,7 +2721,7 @@ msgstr "" # # File: sshconnect1.c, line: 442 # File: sshconnect1.c, line: 483 -# File: sshconnect2.c, line: 925 +# File: sshconnect2.c, line: 935 msgid "Permission denied, please try again." msgstr "" # @@ -2676,8 +2750,8 @@ msgstr "" # File: sshconnect1.c, line: 537 #, c-format msgid "" -"Warning: Server lies about size of server public key: actual size is %" -"d bits vs. announced %d." +"Warning: Server lies about size of server public key: actual size is " +"%d bits vs. announced %d." msgstr "" # # File: sshconnect1.c, line: 539 @@ -2693,7 +2767,7 @@ msgid "" msgstr "" # # File: sshconnect1.c, line: 566 -# File: sshconnect2.c, line: 85 +# File: sshconnect2.c, line: 86 msgid "Host key verification failed." msgstr "" # @@ -2740,7 +2814,7 @@ msgid "Protocol error: got %d in response to rhosts auth" msgstr "" # # File: sshconnect1.c, line: 798 -# File: sshconnect2.c, line: 927 +# File: sshconnect2.c, line: 937 #, c-format msgid "%.30s@%.128s's password: " msgstr "" @@ -2749,210 +2823,226 @@ msgstr "" msgid "Permission denied." msgstr "" # -# File: sshconnect2.c, line: 93 +# File: sshconnect2.c, line: 94 msgid "" "GSS-API authenticated host key addition to known_hosts file failed" msgstr "" # -# File: sshconnect2.c, line: 115 +# File: sshconnect2.c, line: 116 msgid "No valid ciphers for protocol version 2 given, using defaults." msgstr "" # -# File: sshconnect2.c, line: 318 +# File: sshconnect2.c, line: 319 #, c-format msgid "Server denied authentication request: %d" msgstr "" # -# File: sshconnect2.c, line: 346 +# File: sshconnect2.c, line: 347 msgid "ssh_userauth2: internal error: cannot send userauth none request" msgstr "" # -# File: sshconnect2.c, line: 379 +# File: sshconnect2.c, line: 380 #, c-format msgid "Permission denied (%s)." msgstr "" # -# File: sshconnect2.c, line: 394 +# File: sshconnect2.c, line: 395 #, c-format msgid "input_userauth_error: bad message during authentication: type %d" msgstr "" # -# File: sshconnect2.c, line: 417 +# File: sshconnect2.c, line: 427 msgid "input_userauth_success: no authentication context" msgstr "" # -# File: sshconnect2.c, line: 435 +# File: sshconnect2.c, line: 445 msgid "input_userauth_failure: no authentication context" msgstr "" # -# File: sshconnect2.c, line: 442 +# File: sshconnect2.c, line: 452 msgid "Authenticated with partial success." msgstr "" # -# File: sshconnect2.c, line: 460 +# File: sshconnect2.c, line: 470 msgid "input_userauth_pk_ok: no authentication context" msgstr "" # -# File: sshconnect2.c, line: 493 +# File: sshconnect2.c, line: 503 #, c-format msgid "" "input_userauth_pk_ok: type mismatch for decoded key (received %d, " "expected %d)" msgstr "" # -# File: sshconnect2.c, line: 607 -# File: sshconnect2.c, line: 688 -# File: sshconnect2.c, line: 765 -# File: sshconnect2.c, line: 822 +# File: sshconnect2.c, line: 617 +# File: sshconnect2.c, line: 698 +# File: sshconnect2.c, line: 775 +# File: sshconnect2.c, line: 832 msgid "input_gssapi_response: no authentication context" msgstr "" # -# File: sshconnect2.c, line: 960 +# File: sshconnect2.c, line: 970 msgid "input_userauth_passwd_changereq: no authentication context" msgstr "" # -# File: sshconnect2.c, line: 975 +# File: sshconnect2.c, line: 985 #, c-format msgid "Enter %.30s@%.128s's old password: " msgstr "" # -# File: sshconnect2.c, line: 984 +# File: sshconnect2.c, line: 994 #, c-format msgid "Enter %.30s@%.128s's new password: " msgstr "" # -# File: sshconnect2.c, line: 992 +# File: sshconnect2.c, line: 1002 #, c-format msgid "Retype %.30s@%.128s's new password: " msgstr "" # -# File: sshconnect2.c, line: 998 +# File: sshconnect2.c, line: 1008 msgid "Mismatch; try again, EOF to quit." msgstr "" # -# File: sshconnect2.c, line: 1105 +# File: sshconnect2.c, line: 1115 msgid "userauth_pubkey: internal error" msgstr "" # -# File: sshconnect2.c, line: 1167 +# File: sshconnect2.c, line: 1177 #, c-format msgid "Enter passphrase for key '%.100s': " msgstr "" # -# File: sshconnect2.c, line: 1334 +# File: sshconnect2.c, line: 1344 msgid "input_userauth_info_req: no authentication context" msgstr "" # -# File: sshconnect2.c, line: 1390 +# File: sshconnect2.c, line: 1400 #, c-format msgid "ssh_keysign: no installed: %s" msgstr "" # -# File: sshconnect2.c, line: 1394 +# File: sshconnect2.c, line: 1404 #, c-format msgid "ssh_keysign: fflush: %s" msgstr "" # -# File: sshconnect2.c, line: 1396 -# File: sshconnect2.c, line: 1400 +# File: sshconnect2.c, line: 1406 +# File: sshconnect2.c, line: 1410 #, c-format msgid "ssh_keysign: pipe: %s" msgstr "" # -# File: sshconnect2.c, line: 1404 +# File: sshconnect2.c, line: 1414 #, c-format msgid "ssh_keysign: fork: %s" msgstr "" # -# File: sshconnect2.c, line: 1412 -# File: sshconnect2.c, line: 1415 +# File: sshconnect2.c, line: 1422 +# File: sshconnect2.c, line: 1425 #, c-format msgid "ssh_keysign: dup2: %s" msgstr "" # -# File: sshconnect2.c, line: 1419 +# File: sshconnect2.c, line: 1429 #, c-format msgid "ssh_keysign: exec(%s): %s" msgstr "" # -# File: sshconnect2.c, line: 1431 +# File: sshconnect2.c, line: 1441 msgid "ssh_keysign: no reply" msgstr "" # -# File: sshconnect2.c, line: 1443 +# File: sshconnect2.c, line: 1453 msgid "ssh_keysign: bad version" msgstr "" # -# File: sshconnect2.c, line: 1488 +# File: sshconnect2.c, line: 1498 msgid "userauth_hostbased: cannot get local ipaddr/name" msgstr "" # -# File: sshconnect2.c, line: 1525 # File: ssh-keysign.c, line: 249 +# File: sshconnect2.c, line: 1535 msgid "key_sign failed" msgstr "" # -# File: clientloop.c, line: 472 +# File: clientloop.c, line: 284 +msgid "" +"Warning: untrusted X11 forwarding setup failed: xauth key data not " +"generated" +msgstr "" +# +# File: clientloop.c, line: 309 +msgid "" +"Warning: No xauth data; using fake authentication data for X11 " +"forwarding." +msgstr "" +# +# File: clientloop.c, line: 460 +msgid "Timeout, server not responding." +msgstr "" +# +# File: clientloop.c, line: 619 #, c-format msgid "Connection to %.300s closed by remote host.\r\n" msgstr "" # -# File: clientloop.c, line: 490 +# File: clientloop.c, line: 637 #, c-format msgid "Read from remote host %.300s: %.100s\r\n" msgstr "" # -# File: clientloop.c, line: 520 -# File: sftp-int.c, line: 695 +# File: clientloop.c, line: 667 +# File: sftp.c, line: 894 msgid "Invalid command." msgstr "" # -# File: clientloop.c, line: 526 +# File: clientloop.c, line: 673 msgid "Not supported for SSH protocol version 1." msgstr "" # -# File: clientloop.c, line: 537 +# File: clientloop.c, line: 684 msgid "Bad forwarding specification." msgstr "" # -# File: clientloop.c, line: 542 +# File: clientloop.c, line: 689 msgid "Bad forwarding port(s)." msgstr "" # -# File: clientloop.c, line: 548 +# File: clientloop.c, line: 695 msgid "Port forwarding failed." msgstr "" # -# File: clientloop.c, line: 554 +# File: clientloop.c, line: 701 msgid "Forwarding port." msgstr "" # -# File: clientloop.c, line: 596 +# File: clientloop.c, line: 743 #, c-format msgid "%c^Z [suspend ssh]\r\n" msgstr "" # -# File: clientloop.c, line: 609 +# File: clientloop.c, line: 756 #, c-format msgid "%cB [sent break]\r\n" msgstr "" # -# File: clientloop.c, line: 623 +# File: clientloop.c, line: 770 msgid "Server does not support re-keying" msgstr "" # -# File: clientloop.c, line: 642 +# File: clientloop.c, line: 789 #, c-format msgid "%c& [backgrounded]\n" msgstr "" # -# File: clientloop.c, line: 649 +# File: clientloop.c, line: 796 # File: sshd.c, line: 1580 #, c-format msgid "fork: %.100s" msgstr "" # -# File: clientloop.c, line: 682 +# File: clientloop.c, line: 829 #, c-format msgid "" "%c?\r\n" @@ -2969,40 +3059,40 @@ msgid "" "(Note that escapes are only recognized immediately after newline.)\r\n" msgstr "" # -# File: clientloop.c, line: 874 +# File: clientloop.c, line: 1021 #, c-format msgid "client_channel_closed: id %d != session_ident %d" msgstr "" # -# File: clientloop.c, line: 1081 +# File: clientloop.c, line: 1228 #, c-format msgid "Killed by signal %d." msgstr "" # -# File: clientloop.c, line: 1091 +# File: clientloop.c, line: 1238 #, c-format msgid "Connection to %.64s closed.\r\n" msgstr "" # -# File: clientloop.c, line: 1101 +# File: clientloop.c, line: 1248 msgid "Write failed flushing stdout buffer." msgstr "" # -# File: clientloop.c, line: 1113 +# File: clientloop.c, line: 1260 msgid "Write failed flushing stderr buffer." msgstr "" # -# File: clientloop.c, line: 1337 +# File: clientloop.c, line: 1484 #, c-format msgid "client_input_channel_req: no channel %d" msgstr "" # -# File: clientloop.c, line: 1339 +# File: clientloop.c, line: 1486 #, c-format msgid "client_input_channel_req: channel %d: wrong channel: %d" msgstr "" # -# File: clientloop.c, line: 1344 +# File: clientloop.c, line: 1491 #, c-format msgid "client_input_channel_req: channel %d: unknown channel" msgstr "" @@ -3082,32 +3172,26 @@ msgid "" msgstr "" # # File: sshd.c, line: 1039 -#, c-format msgid "Debug level too high.\n" msgstr "" # # File: sshd.c, line: 1064 -#, c-format msgid "too many ports.\n" msgstr "" # # File: sshd.c, line: 1069 -#, c-format msgid "Bad port number.\n" msgstr "" # # File: sshd.c, line: 1076 -#, c-format msgid "Invalid login grace time.\n" msgstr "" # # File: sshd.c, line: 1083 -#, c-format msgid "Invalid key regeneration interval.\n" msgstr "" # # File: sshd.c, line: 1091 -#, c-format msgid "too many host keys.\n" msgstr "" # @@ -3122,7 +3206,6 @@ msgid "Could not load host key: %s" msgstr "" # # File: sshd.c, line: 1209 -#, c-format msgid "Bad server key size.\n" msgstr "" # @@ -3158,9 +3241,9 @@ msgstr "" msgid "Cannot bind any address." msgstr "" # -# File: sshd.c, line: 1451 # File: serverloop.c, line: 359 # File: serverloop.c, line: 812 +# File: sshd.c, line: 1451 #, c-format msgid "select: %.100s" msgstr "" @@ -3271,8 +3354,8 @@ msgstr "" # File: altprivsep.c, line: 888 #, c-format msgid "" -"Protocol error in privilege separation; expected packet type %d, got %" -"d" +"Protocol error in privilege separation; expected packet type %d, got " +"%d" msgstr "" # # File: auth.c, line: 198 @@ -3333,11 +3416,11 @@ msgstr "" msgid "input_userauth_request: no authctxt" msgstr "" # -# File: auth2.c, line: 286 # File: auth2-hostbased.c, line: 70 # File: auth2-none.c, line: 105 # File: auth2-passwd.c, line: 52 # File: auth2-pubkey.c, line: 69 +# File: auth2.c, line: 286 #, c-format msgid "%s: missing context" msgstr "" @@ -3444,8 +3527,8 @@ msgid "" "%d)" msgstr "" # -# File: auth2-pubkey.c, line: 295 # File: auth-rsa.c, line: 332 +# File: auth2-pubkey.c, line: 295 #, c-format msgid "Found matching %s key: %s" msgstr "" @@ -4115,7 +4198,6 @@ msgid "Could not set ULIMIT to %ld from %s\n" msgstr "" # # File: session.c, line: 1063 -#, c-format msgid "Environment:\n" msgstr "" # @@ -4337,7 +4419,6 @@ msgid "do_local_cmd: no arguments" msgstr "" # # File: scp.c, line: 168 -#, c-format msgid "Executing:" msgstr "" # @@ -4367,7 +4448,7 @@ msgid "pipe: %s" msgstr "" # # File: scp.c, line: 256 -# File: sftp.c, line: 71 +# File: sftp.c, line: 1346 #, c-format msgid "fork: %s" msgstr "" @@ -4388,7 +4469,6 @@ msgid "Entering directory: %s" msgstr "" # # File: scp.c, line: 1064 -#, c-format msgid "" "Usage: scp [-pqrvBC46] [-F config] [-S program] [-P port]\n" " [-c cipher] [-i identity] [-o option]\n" @@ -4416,12 +4496,10 @@ msgid "Could not remove identity: %s\n" msgstr "" # # File: ssh-add.c, line: 127 -#, c-format msgid "All identities removed.\n" msgstr "" # # File: ssh-add.c, line: 129 -#, c-format msgid "Failed to remove all identities.\n" msgstr "" # @@ -4452,37 +4530,30 @@ msgstr "" # # File: ssh-add.c, line: 221 # File: ssh-keygen.c, line: 393 -#, c-format msgid "key_write failed" msgstr "" # # File: ssh-add.c, line: 229 -#, c-format msgid "The agent has no identities.\n" msgstr "" # # File: ssh-add.c, line: 247 -#, c-format msgid "Passwords do not match.\n" msgstr "" # # File: ssh-add.c, line: 255 -#, c-format msgid "Agent locked.\n" msgstr "" # # File: ssh-add.c, line: 257 -#, c-format msgid "Agent unlocked.\n" msgstr "" # # File: ssh-add.c, line: 261 -#, c-format msgid "Failed to lock agent.\n" msgstr "" # # File: ssh-add.c, line: 263 -#, c-format msgid "Failed to unlock agent.\n" msgstr "" # @@ -4501,12 +4572,10 @@ msgid "" msgstr "" # # File: ssh-add.c, line: 321 -#, c-format msgid "Could not open a connection to your authentication agent.\n" msgstr "" # # File: ssh-add.c, line: 350 -#, c-format msgid "Invalid lifetime\n" msgstr "" # @@ -4529,8 +4598,8 @@ msgstr "" msgid "process_remove_identity: internal error: tab->nentries %d" msgstr "" # +# File: sftp-server.c, line: 1172 # File: ssh-agent.c, line: 630 -# File: sftp-server.c, line: 994 #, c-format msgid "Unknown message %d" msgstr "" @@ -4613,13 +4682,13 @@ msgstr "" msgid "setrlimit RLIMIT_CORE: %s" msgstr "" # +# File: sftp-server.c, line: 1313 # File: ssh-agent.c, line: 1099 #, c-format msgid "select: %s" msgstr "" # # File: ssh-keygen.c, line: 111 -#, c-format msgid "bad key type" msgstr "" # @@ -4639,12 +4708,10 @@ msgstr "" # # File: ssh-keygen.c, line: 166 # File: ssh-keygen.c, line: 389 -#, c-format msgid "load failed\n" msgstr "" # # File: ssh-keygen.c, line: 171 -#, c-format msgid "key_to_blob failed\n" msgstr "" # @@ -4675,22 +4742,18 @@ msgid "" msgstr "" # # File: ssh-keygen.c, line: 318 -#, c-format msgid "input line too long.\n" msgstr "" # # File: ssh-keygen.c, line: 349 -#, c-format msgid "uudecode failed.\n" msgstr "" # # File: ssh-keygen.c, line: 356 -#, c-format msgid "decode blob failed.\n" msgstr "" # # File: ssh-keygen.c, line: 365 -#, c-format msgid "key write failed" msgstr "" # @@ -4714,7 +4777,6 @@ msgstr "" # # File: ssh-keygen.c, line: 531 # File: ssh-keygen.c, line: 618 -#, c-format msgid "Bad passphrase.\n" msgstr "" # @@ -4733,7 +4795,6 @@ msgid "Enter same passphrase again: " msgstr "" # # File: ssh-keygen.c, line: 554 -#, c-format msgid "Pass phrases do not match. Try again.\n" msgstr "" # @@ -4745,12 +4806,10 @@ msgid "Saving the key failed: %s.\n" msgstr "" # # File: ssh-keygen.c, line: 578 -#, c-format msgid "Your identification has been saved with the new passphrase.\n" msgstr "" # # File: ssh-keygen.c, line: 625 -#, c-format msgid "Comments are only supported for RSA1 keys.\n" msgstr "" # @@ -4760,7 +4819,6 @@ msgid "Key now has comment '%s'\n" msgstr "" # # File: ssh-keygen.c, line: 635 -#, c-format msgid "Enter new comment: " msgstr "" # @@ -4778,12 +4836,10 @@ msgstr "" # # File: ssh-keygen.c, line: 673 # File: ssh-keygen.c, line: 957 -#, c-format msgid "write key failed" msgstr "" # # File: ssh-keygen.c, line: 680 -#, c-format msgid "The comment in your key file has been changed.\n" msgstr "" # @@ -4809,22 +4865,18 @@ msgid "" msgstr "" # # File: ssh-keygen.c, line: 740 -#, c-format msgid "You don't exist, go away!\n" msgstr "" # # File: ssh-keygen.c, line: 754 -#, c-format msgid "Bits has bad value.\n" msgstr "" # # File: ssh-keygen.c, line: 816 -#, c-format msgid "Too many arguments.\n" msgstr "" # # File: ssh-keygen.c, line: 820 -#, c-format msgid "Can only have one of -p and -c.\n" msgstr "" # @@ -4833,7 +4885,6 @@ msgid "no support for smartcards." msgstr "" # # File: ssh-keygen.c, line: 844 -#, c-format msgid "You must specify a key type (-t).\n" msgstr "" # @@ -4848,7 +4899,6 @@ msgid "Generating public/private %s key pair.\n" msgstr "" # # File: ssh-keygen.c, line: 858 -#, c-format msgid "key_generate failed" msgstr "" # @@ -4881,7 +4931,6 @@ msgid "Enter passphrase (empty for no passphrase): " msgstr "" # # File: ssh-keygen.c, line: 909 -#, c-format msgid "Passphrases do not match. Try again.\n" msgstr "" # @@ -4896,7 +4945,6 @@ msgid "Your public key has been saved in %s.\n" msgstr "" # # File: ssh-keygen.c, line: 965 -#, c-format msgid "The key fingerprint is:\n" msgstr "" # @@ -5043,527 +5091,601 @@ msgstr "" msgid "%s: not enough file descriptors" msgstr "" # -# File: sftp-server.c, line: 450 +# File: sftp-server.c, line: 483 +#, c-format +msgid "received client version %d" +msgstr "" +# +# File: sftp-server.c, line: 562 msgid "process_read: seek failed" msgstr "" # -# File: sftp-server.c, line: 488 +# File: sftp-server.c, line: 601 msgid "process_write: seek failed" msgstr "" # -# File: sftp-server.c, line: 493 +# File: sftp-server.c, line: 606 msgid "process_write: write failed" msgstr "" # -# File: sftp-server.c, line: 924 -msgid "bad message " +# File: sftp-server.c, line: 632 +#, c-format +msgid "%sstat name \"%s\"" msgstr "" # -# File: sftp-server.c, line: 999 -msgid "iqueue grows" +# File: sftp-server.c, line: 959 +#, c-format +msgid "realpath \"%s\"" msgstr "" # -# File: sftp-server.c, line: 1002 +# File: sftp-server.c, line: 1038 #, c-format -msgid "msg_len %d < consumed %d" +msgid "readlink \"%s\"" +msgstr "" +# +# File: sftp-server.c, line: 1101 +#, c-format +msgid "bad message from %s local user %s" msgstr "" # -# File: sftp-server.c, line: 1065 -msgid "read error" +# File: sftp-server.c, line: 1177 +msgid "iqueue grew unexpectedly" msgstr "" # -# File: sftp-server.c, line: 1075 -msgid "write error" +# File: sftp-server.c, line: 1180 +#, c-format +msgid "msg_len %d < consumed %d" msgstr "" # -# File: sftp.c, line: 65 +# File: sftp-server.c, line: 1241 #, c-format -msgid "socketpair: %s" +msgid "Invalid log level \"%s\"" msgstr "" # -# File: sftp.c, line: 97 +# File: sftp-server.c, line: 1246 #, c-format -msgid "" -"Usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path]\n" -" [-F config] [-P direct server path] [-S program] [-B " -"buffer_size]\n" -" [-R num_requests] [user@]host[:file [file]]\n" +msgid "Invalid log facility \"%s\"" msgstr "" # -# File: sftp.c, line: 162 +# File: sftp-server.c, line: 1259 #, c-format -msgid "%s (%s)." +msgid "Malformed SSH_CONNECTION variable: \"%s\"" msgstr "" # -# File: sftp.c, line: 164 -msgid "Filename already specified." +# File: sftp-server.c, line: 1266 +#, c-format +msgid "No user found for uid %lu" msgstr "" # -# File: sftp.c, line: 172 +# File: sftp-server.c, line: 1324 #, c-format -msgid "Invalid buffer size \"%s\"" +msgid "read: %s" msgstr "" # -# File: sftp.c, line: 177 +# File: sftp-server.c, line: 1334 #, c-format -msgid "Invalid number of requests \"%s\"" +msgid "write: %s" +msgstr "" +# +# File: sftp.c, line: 172 +msgid "" +"Available commands:\n" +"cd path Change remote directory to 'path'\n" +"lcd path Change local directory to 'path'\n" +"chgrp grp path Change group of file 'path' to 'grp'\n" +"chmod mode path Change permissions of file 'path' to " +"'mode'\n" +"chown own path Change owner of file 'path' to 'own'\n" +"help Display this help text\n" +"get remote-path [local-path] Download file\n" +"lls [ls-options [path]] Display local directory listing\n" +"ln oldpath newpath Symlink remote file\n" +"lmkdir path Create local directory\n" +"lpwd Print local working directory\n" +"ls [path] Display remote directory listing\n" +"lumask umask Set local umask to 'umask'\n" +"mkdir path Create remote directory\n" +"progress Toggle display of progress meter\n" +"put local-path [remote-path] Upload file\n" +"pwd Display remote working directory\n" +"exit Quit sftp\n" +"quit Quit sftp\n" +"rename oldpath newpath Rename remote file\n" +"rmdir path Remove remote directory\n" +"rm path Delete remote file\n" +"symlink oldpath newpath Symlink remote file\n" +"version Show SFTP version\n" +"!command Execute 'command' in local shell\n" +"! Escape to local shell\n" +"? Synonym for help\n" msgstr "" # -# File: sftp.c, line: 205 +# File: sftp.c, line: 216 #, c-format -msgid "Missing username\n" +msgid "Couldn't fork: %s" msgstr "" # -# File: sftp.c, line: 213 +# File: sftp.c, line: 227 #, c-format -msgid "Missing hostname\n" +msgid "Couldn't execute \"%s\": %s\n" msgstr "" # -# File: sftp.c, line: 228 +# File: sftp.c, line: 233 #, c-format -msgid "Connecting to %s...\n" +msgid "Couldn't wait for child: %s" msgstr "" # # File: sftp.c, line: 235 -#, c-format -msgid "Attaching to %s...\n" +msgid "Shell exited abnormally" msgstr "" # -# File: sftp.c, line: 254 +# File: sftp.c, line: 237 #, c-format -msgid "Couldn't wait for ssh process: %s" +msgid "Shell exited with status %d" msgstr "" # -# File: sftp-client.c, line: 78 +# File: sftp.c, line: 316 +msgid "Invalid path" +msgstr "" +# +# File: sftp.c, line: 337 +# File: sftp.c, line: 389 #, c-format -msgid "Couldn't send packet: %s" +msgid "Invalid flag -%c" msgstr "" # -# File: sftp-client.c, line: 91 -# File: sftp-client.c, line: 102 -msgid "Connection closed" +# File: sftp.c, line: 427 +msgid "Unterminated quote" msgstr "" # -# File: sftp-client.c, line: 93 -# File: sftp-client.c, line: 104 +# File: sftp.c, line: 434 #, c-format -msgid "Couldn't read packet: %s" +msgid "Bad escaped character '\\%c'" msgstr "" # -# File: sftp-client.c, line: 97 +# File: sftp.c, line: 443 +msgid "Empty quotes" +msgstr "" +# +# File: sftp.c, line: 483 #, c-format -msgid "Received message too long %u" +msgid "stat %s: %s" msgstr "" # -# File: sftp-client.c, line: 154 -# File: sftp-client.c, line: 180 -# File: sftp-client.c, line: 211 -# File: sftp-client.c, line: 367 -# File: sftp-client.c, line: 577 +# File: sftp.c, line: 517 +# File: sftp.c, line: 585 #, c-format -msgid "ID mismatch (%u != %u)" +msgid "File \"%s\" not found." msgstr "" # -# File: sftp-client.c, line: 156 +# File: sftp.c, line: 524 +# File: sftp.c, line: 592 #, c-format -msgid "Expected SSH2_FXP_STATUS(%u) packet, got %u" +msgid "Multiple files match, but \"%s\" is not a directory" msgstr "" # -# File: sftp-client.c, line: 184 +# File: sftp.c, line: 554 #, c-format -msgid "Couldn't get handle: %s" +msgid "Fetching %s to %s\n" msgstr "" # -# File: sftp-client.c, line: 187 +# File: sftp.c, line: 600 #, c-format -msgid "Expected SSH2_FXP_HANDLE(%u) packet, got %u" +msgid "skipping non-regular file %s" msgstr "" # -# File: sftp-client.c, line: 218 +# File: sftp.c, line: 627 #, c-format -msgid "Couldn't stat remote file: %s" +msgid "Uploading %s to %s\n" msgstr "" # -# File: sftp-client.c, line: 221 +# File: sftp.c, line: 656 +msgid "Unknown ls sort type" +msgstr "" +# +# File: sftp.c, line: 761 #, c-format -msgid "Expected SSH2_FXP_ATTRS(%u) packet, got %u" +msgid "Can't ls: \"%s\" not found" msgstr "" # -# File: sftp-client.c, line: 249 +# File: sftp.c, line: 910 #, c-format -msgid "Invalid packet back from SSH2_FXP_INIT (type %u)" +msgid "You must specify at least one path after a %s command." msgstr "" # -# File: sftp-client.c, line: 308 +# File: sftp.c, line: 925 #, c-format -msgid "Couldn't close file: %s" +msgid "You must specify two paths after a %s command." msgstr "" # -# File: sftp-client.c, line: 377 +# File: sftp.c, line: 940 +# File: sftp.c, line: 988 #, c-format -msgid "Couldn't read directory: %s" +msgid "You must specify a path after a %s command." msgstr "" # -# File: sftp-client.c, line: 383 -# File: sftp-client.c, line: 585 +# File: sftp.c, line: 969 +# File: sftp.c, line: 978 #, c-format -msgid "Expected SSH2_FXP_NAME(%u) packet, got %u" +msgid "You must supply a numeric argument to the %s command." +msgstr "" +# +# File: sftp.c, line: 1001 +msgid "Command not implemented" msgstr "" # -# File: sftp-client.c, line: 453 +# File: sftp.c, line: 1057 #, c-format -msgid "Couldn't delete file: %s" +msgid "Removing %s\n" msgstr "" # -# File: sftp-client.c, line: 468 +# File: sftp.c, line: 1086 +msgid "Can't change directory: Can't check target" +msgstr "" +# +# File: sftp.c, line: 1092 #, c-format -msgid "Couldn't create directory: %s" +msgid "Can't change directory: \"%s\" is not a directory" msgstr "" # -# File: sftp-client.c, line: 484 +# File: sftp.c, line: 1117 #, c-format -msgid "Couldn't remove directory: %s" +msgid "Couldn't change local directory to \"%s\": %s" msgstr "" # -# File: sftp-client.c, line: 536 +# File: sftp.c, line: 1124 #, c-format -msgid "Couldn't setstat on \"%s\": %s" +msgid "Couldn't create local directory \"%s\": %s" msgstr "" # -# File: sftp-client.c, line: 554 +# File: sftp.c, line: 1137 #, c-format -msgid "Couldn't fsetstat: %s" +msgid "Local umask: %03lo\n" msgstr "" # -# File: sftp-client.c, line: 582 +# File: sftp.c, line: 1146 #, c-format -msgid "Couldn't canonicalise: %s" +msgid "Changing mode on %s\n" msgstr "" # -# File: sftp-client.c, line: 590 +# File: sftp.c, line: 1164 #, c-format -msgid "Got multiple names (%d) from SSH_FXP_REALPATH" +msgid "Can't get current ownership of remote file \"%s\"" msgstr "" # -# File: sftp-client.c, line: 626 -# File: sftp-client.c, line: 658 +# File: sftp.c, line: 1173 #, c-format -msgid "Couldn't rename file \"%s\" to \"%s\": %s" +msgid "Changing owner on %s\n" msgstr "" # -# File: sftp-client.c, line: 639 -msgid "This server does not support the symlink operation" +# File: sftp.c, line: 1176 +#, c-format +msgid "Changing group on %s\n" msgstr "" # -# File: sftp-client.c, line: 717 +# File: sftp.c, line: 1185 #, c-format -msgid "Cannot download a directory: %s" +msgid "Remote working directory: %s\n" msgstr "" # -# File: sftp-client.c, line: 748 +# File: sftp.c, line: 1189 #, c-format -msgid "Couldn't open local file \"%s\" for writing: %s" +msgid "Couldn't get local cwd: %s" msgstr "" # -# File: sftp-client.c, line: 791 +# File: sftp.c, line: 1193 #, c-format -msgid "Unexpected reply %u" +msgid "Local working directory: %s\n" msgstr "" # -# File: sftp-client.c, line: 809 +# File: sftp.c, line: 1202 #, c-format -msgid "Received more data than asked for %u > %u" +msgid "SFTP protocol version %u\n" msgstr "" # -# File: sftp-client.c, line: 856 +# File: sftp.c, line: 1212 #, c-format -msgid "Expected SSH2_FXP_DATA(%u) packet, got %u" +msgid "%d is not implemented" msgstr "" # -# File: sftp-client.c, line: 863 -msgid "Transfer complete, but requests still in queue" +# File: sftp.c, line: 1246 +msgid "Couldn't initialise connection to server" +msgstr "" +# +# File: sftp.c, line: 1250 +msgid "Need cwd" msgstr "" # -# File: sftp-client.c, line: 866 +# File: sftp.c, line: 1257 #, c-format -msgid "Couldn't read from remote file \"%s\" : %s" +msgid "Changing to: %s\n" msgstr "" # -# File: sftp-client.c, line: 870 +# File: sftp.c, line: 1340 #, c-format -msgid "Couldn't write to \"%s\": %s" +msgid "socketpair: %s" msgstr "" # -# File: sftp-client.c, line: 881 +# File: sftp.c, line: 1382 #, c-format -msgid "Couldn't set mode on \"%s\": %s" +msgid "" +"Usage: %s [-1Cv] [-b batchfile] [-B buffer_size]\n" +" [-F ssh_config] [-o ssh_option] [-P sftp_server_path]\n" +" [-R num_requests] [-s subsystem | sftp_server]\n" +" [-S program] [user@]host[:dir[/] | :file [file]]\n" msgstr "" # -# File: sftp-client.c, line: 889 +# File: sftp.c, line: 1450 +msgid "Batch file already specified." +msgstr "" +# +# File: sftp.c, line: 1455 #, c-format -msgid "Can't set times on \"%s\": %s" +msgid "%s (%s)." msgstr "" # -# File: sftp-client.c, line: 925 +# File: sftp.c, line: 1466 #, c-format -msgid "Couldn't open local file \"%s\" for reading: %s" +msgid "Invalid buffer size \"%s\"" msgstr "" # -# File: sftp-client.c, line: 930 +# File: sftp.c, line: 1471 #, c-format -msgid "Couldn't fstat local file \"%s\": %s" +msgid "Invalid number of requests \"%s\"" +msgstr "" +# +# File: sftp.c, line: 1497 +msgid "Missing username\n" msgstr "" # -# File: sftp-client.c, line: 982 +# File: sftp.c, line: 1510 +msgid "Missing hostname\n" +msgstr "" +# +# File: sftp.c, line: 1525 #, c-format -msgid "Couldn't read from \"%s\": %s" +msgid "Connecting to %s...\n" msgstr "" # -# File: sftp-client.c, line: 1005 +# File: sftp.c, line: 1532 #, c-format -msgid "Unexpected ACK %u" +msgid "Attaching to %s...\n" msgstr "" # -# File: sftp-client.c, line: 1017 +# File: sftp.c, line: 1551 #, c-format -msgid "Expected SSH2_FXP_STATUS(%d) packet, got %d" +msgid "Couldn't wait for ssh process: %s" msgstr "" # -# File: sftp-client.c, line: 1029 +# File: sftp-client.c, line: 81 #, c-format -msgid "Can't find request for ID %u" +msgid "Outbound message too long %u" msgstr "" # -# File: sftp-client.c, line: 1033 +# File: sftp-client.c, line: 91 #, c-format -msgid "Couldn't write to remote file \"%s\": %s" +msgid "Couldn't send packet: %s" msgstr "" # -# File: sftp-client.c, line: 1049 +# File: sftp-client.c, line: 104 +# File: sftp-client.c, line: 116 +msgid "Connection closed" +msgstr "" +# +# File: sftp-client.c, line: 106 #, c-format -msgid "Couldn't close local file \"%s\": %s" +msgid "Couldn't read packet: %s" msgstr "" # -# File: sftp-int.c, line: 105 +# File: sftp-client.c, line: 111 #, c-format -msgid "" -"Available commands:\n" -"cd path Change remote directory to 'path'\n" -"lcd path Change local directory to 'path'\n" -"chgrp grp path Change group of file 'path' to 'grp'\n" -"chmod mode path Change permissions of file 'path' to " -"'mode'\n" -"chown own path Change owner of file 'path' to 'own'\n" -"help Display this help text\n" -"get remote-path [local-path] Download file\n" -"lls [ls-options [path]] Display local directory listing\n" -"ln oldpath newpath Symlink remote file\n" -"lmkdir path Create local directory\n" -"lpwd Print local working directory\n" -"ls [path] Display remote directory listing\n" -"lumask umask Set local umask to 'umask'\n" -"mkdir path Create remote directory\n" -"put local-path [remote-path] Upload file\n" -"pwd Display remote working directory\n" -"exit Quit sftp\n" -"quit Quit sftp\n" -"rename oldpath newpath Rename remote file\n" -"rmdir path Remove remote directory\n" -"rm path Delete remote file\n" -"symlink oldpath newpath Symlink remote file\n" -"version Show SFTP version\n" -"!command Execute 'command' in local shell\n" -"! Escape to local shell\n" -"? Synonym for help\n" +msgid "Received message too long %u" msgstr "" # -# File: sftp-int.c, line: 151 +# File: sftp-client.c, line: 118 #, c-format -msgid "Couldn't fork: %s" +msgid "Read packet: %s" msgstr "" # -# File: sftp-int.c, line: 162 +# File: sftp-client.c, line: 165 +# File: sftp-client.c, line: 191 +# File: sftp-client.c, line: 223 +# File: sftp-client.c, line: 378 +# File: sftp-client.c, line: 598 #, c-format -msgid "Couldn't execute \"%s\": %s\n" +msgid "ID mismatch (%u != %u)" msgstr "" # -# File: sftp-int.c, line: 168 +# File: sftp-client.c, line: 167 #, c-format -msgid "Couldn't wait for child: %s" +msgid "Expected SSH2_FXP_STATUS(%u) packet, got %u" msgstr "" # -# File: sftp-int.c, line: 170 -msgid "Shell exited abnormally" +# File: sftp-client.c, line: 195 +#, c-format +msgid "Couldn't get handle: %s" msgstr "" # -# File: sftp-int.c, line: 172 +# File: sftp-client.c, line: 199 #, c-format -msgid "Shell exited with status %d" +msgid "Expected SSH2_FXP_HANDLE(%u) packet, got %u" msgstr "" # -# File: sftp-int.c, line: 251 -msgid "Invalid path" +# File: sftp-client.c, line: 230 +#, c-format +msgid "Couldn't stat remote file: %s" msgstr "" # -# File: sftp-int.c, line: 272 -# File: sftp-int.c, line: 295 +# File: sftp-client.c, line: 234 #, c-format -msgid "Invalid flag -%c" +msgid "Expected SSH2_FXP_ATTRS(%u) packet, got %u" msgstr "" # -# File: sftp-int.c, line: 325 -msgid "Unterminated quote" +# File: sftp-client.c, line: 262 +#, c-format +msgid "Invalid packet back from SSH2_FXP_INIT (type %u)" msgstr "" # -# File: sftp-int.c, line: 329 -msgid "Empty quotes" +# File: sftp-client.c, line: 321 +#, c-format +msgid "Couldn't close file: %s" msgstr "" # -# File: sftp-int.c, line: 394 -# File: sftp-int.c, line: 473 +# File: sftp-client.c, line: 388 #, c-format -msgid "File \"%s\" not found." +msgid "Couldn't read directory: %s" msgstr "" # -# File: sftp-int.c, line: 416 -# File: sftp-int.c, line: 440 +# File: sftp-client.c, line: 395 +# File: sftp-client.c, line: 606 #, c-format -msgid "Fetching %s to %s\n" +msgid "Expected SSH2_FXP_NAME(%u) packet, got %u" msgstr "" # -# File: sftp-int.c, line: 423 -# File: sftp-int.c, line: 505 +# File: sftp-client.c, line: 471 #, c-format -msgid "Multiple files match, but \"%s\" is not a directory" +msgid "Couldn't delete file: %s" msgstr "" # -# File: sftp-int.c, line: 498 -# File: sftp-int.c, line: 522 +# File: sftp-client.c, line: 486 #, c-format -msgid "Uploading %s to %s\n" +msgid "Couldn't create directory: %s" msgstr "" # -# File: sftp-int.c, line: 602 +# File: sftp-client.c, line: 502 #, c-format -msgid "Can't ls: \"%s\" not found" +msgid "Couldn't remove directory: %s" msgstr "" # -# File: sftp-int.c, line: 711 +# File: sftp-client.c, line: 555 #, c-format -msgid "You must specify at least one path after a %s command." +msgid "Couldn't setstat on \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 726 +# File: sftp-client.c, line: 573 #, c-format -msgid "You must specify two paths after a %s command." +msgid "Couldn't fsetstat: %s" msgstr "" # -# File: sftp-int.c, line: 741 -# File: sftp-int.c, line: 788 +# File: sftp-client.c, line: 603 #, c-format -msgid "You must specify a path after a %s command." +msgid "Couldn't canonicalise: %s" msgstr "" # -# File: sftp-int.c, line: 769 -# File: sftp-int.c, line: 778 +# File: sftp-client.c, line: 611 #, c-format -msgid "You must supply a numeric argument to the %s command." +msgid "Got multiple names (%d) from SSH_FXP_REALPATH" msgstr "" # -# File: sftp-int.c, line: 800 -msgid "Command not implemented" +# File: sftp-client.c, line: 647 +#, c-format +msgid "Couldn't rename file \"%s\" to \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 847 +# File: sftp-client.c, line: 660 +msgid "This server does not support the symlink operation" +msgstr "" +# +# File: sftp-client.c, line: 679 #, c-format -msgid "Removing %s\n" +msgid "Couldn't symlink file \"%s\" to \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 875 -msgid "Can't change directory: Can't check target" +# File: sftp-client.c, line: 740 +#, c-format +msgid "Cannot download non-regular file: %s" msgstr "" # -# File: sftp-int.c, line: 881 +# File: sftp-client.c, line: 772 #, c-format -msgid "Can't change directory: \"%s\" is not a directory" +msgid "Couldn't open local file \"%s\" for writing: %s" msgstr "" # -# File: sftp-int.c, line: 907 +# File: sftp-client.c, line: 831 #, c-format -msgid "Couldn't change local directory to \"%s\": %s" +msgid "Unexpected reply %u" msgstr "" # -# File: sftp-int.c, line: 914 +# File: sftp-client.c, line: 849 #, c-format -msgid "Couldn't create local directory \"%s\": %s" +msgid "Received more data than asked for %u > %u" msgstr "" # -# File: sftp-int.c, line: 927 +# File: sftp-client.c, line: 896 #, c-format -msgid "Local umask: %03lo\n" +msgid "Expected SSH2_FXP_DATA(%u) packet, got %u" msgstr "" # -# File: sftp-int.c, line: 936 +# File: sftp-client.c, line: 906 +msgid "Transfer complete, but requests still in queue" +msgstr "" +# +# File: sftp-client.c, line: 909 #, c-format -msgid "Changing mode on %s\n" +msgid "Couldn't read from remote file \"%s\" : %s" msgstr "" # -# File: sftp-int.c, line: 947 -# File: sftp-int.c, line: 965 +# File: sftp-client.c, line: 913 #, c-format -msgid "Can't get current ownership of remote file \"%s\"" +msgid "Couldn't write to \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 951 +# File: sftp-client.c, line: 924 #, c-format -msgid "Changing owner on %s\n" +msgid "Couldn't set mode on \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 969 +# File: sftp-client.c, line: 932 #, c-format -msgid "Changing group on %s\n" +msgid "Can't set times on \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 977 +# File: sftp-client.c, line: 968 #, c-format -msgid "Remote working directory: %s\n" +msgid "Couldn't open local file \"%s\" for reading: %s" msgstr "" # -# File: sftp-int.c, line: 981 +# File: sftp-client.c, line: 973 #, c-format -msgid "Couldn't get local cwd: %s" +msgid "Couldn't fstat local file \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 984 +# File: sftp-client.c, line: 979 #, c-format -msgid "Local working directory: %s\n" +msgid "%s is not a regular file" msgstr "" # -# File: sftp-int.c, line: 993 +# File: sftp-client.c, line: 1037 #, c-format -msgid "SFTP protocol version %u\n" +msgid "Couldn't read from \"%s\": %s" msgstr "" # -# File: sftp-int.c, line: 997 +# File: sftp-client.c, line: 1060 #, c-format -msgid "%d is not implemented" +msgid "Unexpected ACK %u" msgstr "" # -# File: sftp-int.c, line: 1024 -msgid "Couldn't initialise connection to server" +# File: sftp-client.c, line: 1072 +#, c-format +msgid "Expected SSH2_FXP_STATUS(%d) packet, got %d" msgstr "" # -# File: sftp-int.c, line: 1028 -msgid "Need cwd" +# File: sftp-client.c, line: 1084 +#, c-format +msgid "Can't find request for ID %u" msgstr "" # -# File: sftp-int.c, line: 1035 +# File: sftp-client.c, line: 1088 #, c-format -msgid "Changing to: %s\n" +msgid "Couldn't write to remote file \"%s\": %s" msgstr "" # -# File: ssh-http-proxy-connect.c, line: 63 +# File: sftp-client.c, line: 1111 #, c-format +msgid "Couldn't close local file \"%s\": %s" +msgstr "" +# +# File: ssh-http-proxy-connect.c, line: 63 msgid "" "Usage: ssh-http-proxy-connect [-h http_proxy_host] [-p " "http_proxy_port]\n" @@ -5571,14 +5693,12 @@ msgid "" msgstr "" # # File: ssh-http-proxy-connect.c, line: 158 -#, c-format msgid "" "ssh-http-proxy: Incorrect url specified for http_proxy environment " "variable\n" msgstr "" # # File: ssh-http-proxy-connect.c, line: 167 -#, c-format msgid "ssh-http-proxy: http proxy not specified\n" msgstr "" # @@ -5588,12 +5708,10 @@ msgid "ssh-http-proxy: Unable to connect to %s: %s\n" msgstr "" # # File: ssh-http-proxy-connect.c, line: 230 -#, c-format msgid "ssh-http-proxy: HTTP reply not understood\n" msgstr "" # # File: ssh-socks5-proxy-connect.c, line: 63 -#, c-format msgid "" "Usage: ssh-socks5-proxy-connect [-h socks5_proxy_host] [-p " "socks5_proxy_port] \n" @@ -5606,7 +5724,6 @@ msgid "Unsupported SOCKS version: %x\n" msgstr "" # # File: ssh-socks5-proxy-connect.c, line: 209 -#, c-format msgid "ssh-socks5-proxy: SOCKS Server reply not understood\n" msgstr "" # @@ -5616,11 +5733,9 @@ msgid "ssh-socks5-proxy: Address type not supported: %u\n" msgstr "" # # File: ssh-socks5-proxy-connect.c, line: 289 -#, c-format msgid "ssh-socks5-proxy: SOCKS5 SERVER not specified\n" msgstr "" # # File: ssh-socks5-proxy-connect.c, line: 327 -#, c-format msgid "ssh-socks5-proxy: Client and Server versions differ.\n" msgstr "" |