summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2019-02-08 15:41:19 +0000
committerColin Watson <cjwatson@debian.org>2019-02-08 16:24:58 +0000
commitbbf87fe18360e9dabdeb9af0cadff0f8087a5492 (patch)
tree6aba9afdccceb18a863f0fc6c89d3ec06a2961ac
parentd6448492718c5e1174323eebcc696364e96d5047 (diff)
parent2a8f710447442e9a03e71c022859112ec2d77d17 (diff)
Sanitize scp filenames via snmprintf
CVE-2019-6109 Closes: #793412
-rw-r--r--atomicio.c20
-rw-r--r--debian/.git-dpm4
-rw-r--r--debian/changelog7
-rw-r--r--debian/patches/have-progressmeter-force-update-at-beginning-and-end-transfer.patch120
-rw-r--r--debian/patches/sanitize-scp-filenames-via-snmprintf.patch276
-rw-r--r--debian/patches/series2
-rw-r--r--progressmeter.c60
-rw-r--r--progressmeter.h3
-rw-r--r--scp.c1
-rw-r--r--sftp-client.c16
10 files changed, 460 insertions, 49 deletions
diff --git a/atomicio.c b/atomicio.c
index f854a06f5..d91bd7621 100644
--- a/atomicio.c
+++ b/atomicio.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */ 1/* $OpenBSD: atomicio.c,v 1.29 2019/01/23 08:01:46 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2006 Damien Miller. All rights reserved. 3 * Copyright (c) 2006 Damien Miller. All rights reserved.
4 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 4 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
@@ -65,9 +65,14 @@ atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
65 res = (f) (fd, s + pos, n - pos); 65 res = (f) (fd, s + pos, n - pos);
66 switch (res) { 66 switch (res) {
67 case -1: 67 case -1:
68 if (errno == EINTR) 68 if (errno == EINTR) {
69 /* possible SIGALARM, update callback */
70 if (cb != NULL && cb(cb_arg, 0) == -1) {
71 errno = EINTR;
72 return pos;
73 }
69 continue; 74 continue;
70 if (errno == EAGAIN || errno == EWOULDBLOCK) { 75 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
71#ifndef BROKEN_READ_COMPARISON 76#ifndef BROKEN_READ_COMPARISON
72 (void)poll(&pfd, 1, -1); 77 (void)poll(&pfd, 1, -1);
73#endif 78#endif
@@ -122,9 +127,14 @@ atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
122 res = (f) (fd, iov, iovcnt); 127 res = (f) (fd, iov, iovcnt);
123 switch (res) { 128 switch (res) {
124 case -1: 129 case -1:
125 if (errno == EINTR) 130 if (errno == EINTR) {
131 /* possible SIGALARM, update callback */
132 if (cb != NULL && cb(cb_arg, 0) == -1) {
133 errno = EINTR;
134 return pos;
135 }
126 continue; 136 continue;
127 if (errno == EAGAIN || errno == EWOULDBLOCK) { 137 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
128#ifndef BROKEN_READV_COMPARISON 138#ifndef BROKEN_READV_COMPARISON
129 (void)poll(&pfd, 1, -1); 139 (void)poll(&pfd, 1, -1);
130#endif 140#endif
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 10491782a..992d37c60 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,6 +1,6 @@
1# see git-dpm(1) from git-dpm package 1# see git-dpm(1) from git-dpm package
2dee21e97428e69d30e2d15c71f3e7cc08bf8e4f8 22a8f710447442e9a03e71c022859112ec2d77d17
3dee21e97428e69d30e2d15c71f3e7cc08bf8e4f8 32a8f710447442e9a03e71c022859112ec2d77d17
43d246f10429fc9a37b98eabef94fe8dc7c61002b 43d246f10429fc9a37b98eabef94fe8dc7c61002b
53d246f10429fc9a37b98eabef94fe8dc7c61002b 53d246f10429fc9a37b98eabef94fe8dc7c61002b
6openssh_7.9p1.orig.tar.gz 6openssh_7.9p1.orig.tar.gz
diff --git a/debian/changelog b/debian/changelog
index 2c567e1d7..cc1cfd5f1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
1openssh (1:7.9p1-6) UNRELEASED; urgency=medium
2
3 * CVE-2019-6109: Apply upstream patches to sanitize scp filenames via
4 snmprintf (closes: #793412).
5
6 -- Colin Watson <cjwatson@debian.org> Fri, 08 Feb 2019 15:41:25 +0000
7
1openssh (1:7.9p1-5) unstable; urgency=high 8openssh (1:7.9p1-5) unstable; urgency=high
2 9
3 * Move /etc/ssh/moduli to openssh-server, since it's reasonably large and 10 * Move /etc/ssh/moduli to openssh-server, since it's reasonably large and
diff --git a/debian/patches/have-progressmeter-force-update-at-beginning-and-end-transfer.patch b/debian/patches/have-progressmeter-force-update-at-beginning-and-end-transfer.patch
new file mode 100644
index 000000000..767dbf2b5
--- /dev/null
+++ b/debian/patches/have-progressmeter-force-update-at-beginning-and-end-transfer.patch
@@ -0,0 +1,120 @@
1From 2a8f710447442e9a03e71c022859112ec2d77d17 Mon Sep 17 00:00:00 2001
2From: "dtucker@openbsd.org" <dtucker@openbsd.org>
3Date: Thu, 24 Jan 2019 16:52:17 +0000
4Subject: upstream: Have progressmeter force an update at the beginning and
5
6end of each transfer. Fixes the problem recently introduces where very quick
7transfers do not display the progressmeter at all. Spotted by naddy@
8
9OpenBSD-Commit-ID: 68dc46c259e8fdd4f5db3ec2a130f8e4590a7a9a
10
11Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=bdc6c63c80b55bcbaa66b5fde31c1cb1d09a41eb
12Last-Update: 2019-02-08
13
14Patch-Name: have-progressmeter-force-update-at-beginning-and-end-transfer.patch
15---
16 progressmeter.c | 13 +++++--------
17 progressmeter.h | 4 ++--
18 scp.c | 2 +-
19 sftp-client.c | 2 +-
20 4 files changed, 9 insertions(+), 12 deletions(-)
21
22diff --git a/progressmeter.c b/progressmeter.c
23index add462dde..e385c1254 100644
24--- a/progressmeter.c
25+++ b/progressmeter.c
26@@ -1,4 +1,4 @@
27-/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */
28+/* $OpenBSD: progressmeter.c,v 1.47 2019/01/24 16:52:17 dtucker Exp $ */
29 /*
30 * Copyright (c) 2003 Nils Nordman. All rights reserved.
31 *
32@@ -59,9 +59,6 @@ static void format_rate(char *, int, off_t);
33 static void sig_winch(int);
34 static void setscreensize(void);
35
36-/* updates the progressmeter to reflect the current state of the transfer */
37-void refresh_progress_meter(void);
38-
39 /* signal handler for updating the progress meter */
40 static void sig_alarm(int);
41
42@@ -120,7 +117,7 @@ format_size(char *buf, int size, off_t bytes)
43 }
44
45 void
46-refresh_progress_meter(void)
47+refresh_progress_meter(int force_update)
48 {
49 char buf[MAX_WINSIZE + 1];
50 off_t transferred;
51@@ -131,7 +128,7 @@ refresh_progress_meter(void)
52 int hours, minutes, seconds;
53 int file_len;
54
55- if ((!alarm_fired && !win_resized) || !can_output())
56+ if ((!force_update && !alarm_fired && !win_resized) || !can_output())
57 return;
58 alarm_fired = 0;
59
60@@ -254,7 +251,7 @@ start_progress_meter(const char *f, off_t filesize, off_t *ctr)
61 bytes_per_second = 0;
62
63 setscreensize();
64- refresh_progress_meter();
65+ refresh_progress_meter(1);
66
67 signal(SIGALRM, sig_alarm);
68 signal(SIGWINCH, sig_winch);
69@@ -271,7 +268,7 @@ stop_progress_meter(void)
70
71 /* Ensure we complete the progress */
72 if (cur_pos != end_pos)
73- refresh_progress_meter();
74+ refresh_progress_meter(1);
75
76 atomicio(vwrite, STDOUT_FILENO, "\n", 1);
77 }
78diff --git a/progressmeter.h b/progressmeter.h
79index 8f6678060..1703ea75b 100644
80--- a/progressmeter.h
81+++ b/progressmeter.h
82@@ -1,4 +1,4 @@
83-/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */
84+/* $OpenBSD: progressmeter.h,v 1.5 2019/01/24 16:52:17 dtucker Exp $ */
85 /*
86 * Copyright (c) 2002 Nils Nordman. All rights reserved.
87 *
88@@ -24,5 +24,5 @@
89 */
90
91 void start_progress_meter(const char *, off_t, off_t *);
92-void refresh_progress_meter(void);
93+void refresh_progress_meter(int);
94 void stop_progress_meter(void);
95diff --git a/scp.c b/scp.c
96index 80308573c..1971c80cd 100644
97--- a/scp.c
98+++ b/scp.c
99@@ -593,7 +593,7 @@ scpio(void *_cnt, size_t s)
100 off_t *cnt = (off_t *)_cnt;
101
102 *cnt += s;
103- refresh_progress_meter();
104+ refresh_progress_meter(0);
105 if (limit_kbps > 0)
106 bandwidth_limit(&bwlimit, s);
107 return 0;
108diff --git a/sftp-client.c b/sftp-client.c
109index 2bc698f86..cf2887a40 100644
110--- a/sftp-client.c
111+++ b/sftp-client.c
112@@ -101,7 +101,7 @@ sftpio(void *_bwlimit, size_t amount)
113 {
114 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
115
116- refresh_progress_meter();
117+ refresh_progress_meter(0);
118 if (bwlimit != NULL)
119 bandwidth_limit(bwlimit, amount);
120 return 0;
diff --git a/debian/patches/sanitize-scp-filenames-via-snmprintf.patch b/debian/patches/sanitize-scp-filenames-via-snmprintf.patch
new file mode 100644
index 000000000..e58b8b1bd
--- /dev/null
+++ b/debian/patches/sanitize-scp-filenames-via-snmprintf.patch
@@ -0,0 +1,276 @@
1From 11b88754cadcad0ba79b4ffcc127223248dccb54 Mon Sep 17 00:00:00 2001
2From: "dtucker@openbsd.org" <dtucker@openbsd.org>
3Date: Wed, 23 Jan 2019 08:01:46 +0000
4Subject: upstream: Sanitize scp filenames via snmprintf. To do this we move
5
6the progressmeter formatting outside of signal handler context and have the
7atomicio callback called for EINTR too. bz#2434 with contributions from djm
8and jjelen at redhat.com, ok djm@
9
10OpenBSD-Commit-ID: 1af61c1f70e4f3bd8ab140b9f1fa699481db57d8
11
12CVE-2019-6109
13
14Origin: backport, https://anongit.mindrot.org/openssh.git/commit/?id=8976f1c4b2721c26e878151f52bdf346dfe2d54c
15Bug-Debian: https://bugs.debian.org/793412
16Last-Update: 2019-02-08
17
18Patch-Name: sanitize-scp-filenames-via-snmprintf.patch
19---
20 atomicio.c | 20 ++++++++++++++-----
21 progressmeter.c | 53 ++++++++++++++++++++++---------------------------
22 progressmeter.h | 3 ++-
23 scp.c | 1 +
24 sftp-client.c | 16 ++++++++-------
25 5 files changed, 51 insertions(+), 42 deletions(-)
26
27diff --git a/atomicio.c b/atomicio.c
28index f854a06f5..d91bd7621 100644
29--- a/atomicio.c
30+++ b/atomicio.c
31@@ -1,4 +1,4 @@
32-/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */
33+/* $OpenBSD: atomicio.c,v 1.29 2019/01/23 08:01:46 dtucker Exp $ */
34 /*
35 * Copyright (c) 2006 Damien Miller. All rights reserved.
36 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
37@@ -65,9 +65,14 @@ atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
38 res = (f) (fd, s + pos, n - pos);
39 switch (res) {
40 case -1:
41- if (errno == EINTR)
42+ if (errno == EINTR) {
43+ /* possible SIGALARM, update callback */
44+ if (cb != NULL && cb(cb_arg, 0) == -1) {
45+ errno = EINTR;
46+ return pos;
47+ }
48 continue;
49- if (errno == EAGAIN || errno == EWOULDBLOCK) {
50+ } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
51 #ifndef BROKEN_READ_COMPARISON
52 (void)poll(&pfd, 1, -1);
53 #endif
54@@ -122,9 +127,14 @@ atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
55 res = (f) (fd, iov, iovcnt);
56 switch (res) {
57 case -1:
58- if (errno == EINTR)
59+ if (errno == EINTR) {
60+ /* possible SIGALARM, update callback */
61+ if (cb != NULL && cb(cb_arg, 0) == -1) {
62+ errno = EINTR;
63+ return pos;
64+ }
65 continue;
66- if (errno == EAGAIN || errno == EWOULDBLOCK) {
67+ } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
68 #ifndef BROKEN_READV_COMPARISON
69 (void)poll(&pfd, 1, -1);
70 #endif
71diff --git a/progressmeter.c b/progressmeter.c
72index fe9bf52e4..add462dde 100644
73--- a/progressmeter.c
74+++ b/progressmeter.c
75@@ -1,4 +1,4 @@
76-/* $OpenBSD: progressmeter.c,v 1.45 2016/06/30 05:17:05 dtucker Exp $ */
77+/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */
78 /*
79 * Copyright (c) 2003 Nils Nordman. All rights reserved.
80 *
81@@ -31,6 +31,7 @@
82
83 #include <errno.h>
84 #include <signal.h>
85+#include <stdarg.h>
86 #include <stdio.h>
87 #include <string.h>
88 #include <time.h>
89@@ -39,6 +40,7 @@
90 #include "progressmeter.h"
91 #include "atomicio.h"
92 #include "misc.h"
93+#include "utf8.h"
94
95 #define DEFAULT_WINSIZE 80
96 #define MAX_WINSIZE 512
97@@ -61,7 +63,7 @@ static void setscreensize(void);
98 void refresh_progress_meter(void);
99
100 /* signal handler for updating the progress meter */
101-static void update_progress_meter(int);
102+static void sig_alarm(int);
103
104 static double start; /* start progress */
105 static double last_update; /* last progress update */
106@@ -74,6 +76,7 @@ static long stalled; /* how long we have been stalled */
107 static int bytes_per_second; /* current speed in bytes per second */
108 static int win_size; /* terminal window size */
109 static volatile sig_atomic_t win_resized; /* for window resizing */
110+static volatile sig_atomic_t alarm_fired;
111
112 /* units for format_size */
113 static const char unit[] = " KMGT";
114@@ -126,9 +129,17 @@ refresh_progress_meter(void)
115 off_t bytes_left;
116 int cur_speed;
117 int hours, minutes, seconds;
118- int i, len;
119 int file_len;
120
121+ if ((!alarm_fired && !win_resized) || !can_output())
122+ return;
123+ alarm_fired = 0;
124+
125+ if (win_resized) {
126+ setscreensize();
127+ win_resized = 0;
128+ }
129+
130 transferred = *counter - (cur_pos ? cur_pos : start_pos);
131 cur_pos = *counter;
132 now = monotime_double();
133@@ -158,16 +169,11 @@ refresh_progress_meter(void)
134
135 /* filename */
136 buf[0] = '\0';
137- file_len = win_size - 35;
138+ file_len = win_size - 36;
139 if (file_len > 0) {
140- len = snprintf(buf, file_len + 1, "\r%s", file);
141- if (len < 0)
142- len = 0;
143- if (len >= file_len + 1)
144- len = file_len;
145- for (i = len; i < file_len; i++)
146- buf[i] = ' ';
147- buf[file_len] = '\0';
148+ buf[0] = '\r';
149+ snmprintf(buf+1, sizeof(buf)-1 , &file_len, "%*s",
150+ file_len * -1, file);
151 }
152
153 /* percent of transfer done */
154@@ -228,22 +234,11 @@ refresh_progress_meter(void)
155
156 /*ARGSUSED*/
157 static void
158-update_progress_meter(int ignore)
159+sig_alarm(int ignore)
160 {
161- int save_errno;
162-
163- save_errno = errno;
164-
165- if (win_resized) {
166- setscreensize();
167- win_resized = 0;
168- }
169- if (can_output())
170- refresh_progress_meter();
171-
172- signal(SIGALRM, update_progress_meter);
173+ signal(SIGALRM, sig_alarm);
174+ alarm_fired = 1;
175 alarm(UPDATE_INTERVAL);
176- errno = save_errno;
177 }
178
179 void
180@@ -259,10 +254,9 @@ start_progress_meter(const char *f, off_t filesize, off_t *ctr)
181 bytes_per_second = 0;
182
183 setscreensize();
184- if (can_output())
185- refresh_progress_meter();
186+ refresh_progress_meter();
187
188- signal(SIGALRM, update_progress_meter);
189+ signal(SIGALRM, sig_alarm);
190 signal(SIGWINCH, sig_winch);
191 alarm(UPDATE_INTERVAL);
192 }
193@@ -286,6 +280,7 @@ stop_progress_meter(void)
194 static void
195 sig_winch(int sig)
196 {
197+ signal(SIGWINCH, sig_winch);
198 win_resized = 1;
199 }
200
201diff --git a/progressmeter.h b/progressmeter.h
202index bf179dca6..8f6678060 100644
203--- a/progressmeter.h
204+++ b/progressmeter.h
205@@ -1,4 +1,4 @@
206-/* $OpenBSD: progressmeter.h,v 1.3 2015/01/14 13:54:13 djm Exp $ */
207+/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */
208 /*
209 * Copyright (c) 2002 Nils Nordman. All rights reserved.
210 *
211@@ -24,4 +24,5 @@
212 */
213
214 void start_progress_meter(const char *, off_t, off_t *);
215+void refresh_progress_meter(void);
216 void stop_progress_meter(void);
217diff --git a/scp.c b/scp.c
218index 7163d33dc..80308573c 100644
219--- a/scp.c
220+++ b/scp.c
221@@ -593,6 +593,7 @@ scpio(void *_cnt, size_t s)
222 off_t *cnt = (off_t *)_cnt;
223
224 *cnt += s;
225+ refresh_progress_meter();
226 if (limit_kbps > 0)
227 bandwidth_limit(&bwlimit, s);
228 return 0;
229diff --git a/sftp-client.c b/sftp-client.c
230index 4986d6d8d..2bc698f86 100644
231--- a/sftp-client.c
232+++ b/sftp-client.c
233@@ -101,7 +101,9 @@ sftpio(void *_bwlimit, size_t amount)
234 {
235 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
236
237- bandwidth_limit(bwlimit, amount);
238+ refresh_progress_meter();
239+ if (bwlimit != NULL)
240+ bandwidth_limit(bwlimit, amount);
241 return 0;
242 }
243
244@@ -121,8 +123,8 @@ send_msg(struct sftp_conn *conn, struct sshbuf *m)
245 iov[1].iov_base = (u_char *)sshbuf_ptr(m);
246 iov[1].iov_len = sshbuf_len(m);
247
248- if (atomiciov6(writev, conn->fd_out, iov, 2,
249- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
250+ if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
251+ conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
252 sshbuf_len(m) + sizeof(mlen))
253 fatal("Couldn't send packet: %s", strerror(errno));
254
255@@ -138,8 +140,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
256
257 if ((r = sshbuf_reserve(m, 4, &p)) != 0)
258 fatal("%s: buffer error: %s", __func__, ssh_err(r));
259- if (atomicio6(read, conn->fd_in, p, 4,
260- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
261+ if (atomicio6(read, conn->fd_in, p, 4, sftpio,
262+ conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
263 if (errno == EPIPE || errno == ECONNRESET)
264 fatal("Connection closed");
265 else
266@@ -157,8 +159,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
267
268 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
269 fatal("%s: buffer error: %s", __func__, ssh_err(r));
270- if (atomicio6(read, conn->fd_in, p, msg_len,
271- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
272+ if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
273+ conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
274 != msg_len) {
275 if (errno == EPIPE)
276 fatal("Connection closed");
diff --git a/debian/patches/series b/debian/patches/series
index a6fc19449..710e56b7b 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -25,3 +25,5 @@ seccomp-s390-flock-ipc.patch
25seccomp-s390-ioctl-ep11-crypto.patch 25seccomp-s390-ioctl-ep11-crypto.patch
26conch-old-privkey-format.patch 26conch-old-privkey-format.patch
27scp-disallow-dot-or-empty-filename.patch 27scp-disallow-dot-or-empty-filename.patch
28sanitize-scp-filenames-via-snmprintf.patch
29have-progressmeter-force-update-at-beginning-and-end-transfer.patch
diff --git a/progressmeter.c b/progressmeter.c
index fe9bf52e4..e385c1254 100644
--- a/progressmeter.c
+++ b/progressmeter.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: progressmeter.c,v 1.45 2016/06/30 05:17:05 dtucker Exp $ */ 1/* $OpenBSD: progressmeter.c,v 1.47 2019/01/24 16:52:17 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2003 Nils Nordman. All rights reserved. 3 * Copyright (c) 2003 Nils Nordman. All rights reserved.
4 * 4 *
@@ -31,6 +31,7 @@
31 31
32#include <errno.h> 32#include <errno.h>
33#include <signal.h> 33#include <signal.h>
34#include <stdarg.h>
34#include <stdio.h> 35#include <stdio.h>
35#include <string.h> 36#include <string.h>
36#include <time.h> 37#include <time.h>
@@ -39,6 +40,7 @@
39#include "progressmeter.h" 40#include "progressmeter.h"
40#include "atomicio.h" 41#include "atomicio.h"
41#include "misc.h" 42#include "misc.h"
43#include "utf8.h"
42 44
43#define DEFAULT_WINSIZE 80 45#define DEFAULT_WINSIZE 80
44#define MAX_WINSIZE 512 46#define MAX_WINSIZE 512
@@ -57,11 +59,8 @@ static void format_rate(char *, int, off_t);
57static void sig_winch(int); 59static void sig_winch(int);
58static void setscreensize(void); 60static void setscreensize(void);
59 61
60/* updates the progressmeter to reflect the current state of the transfer */
61void refresh_progress_meter(void);
62
63/* signal handler for updating the progress meter */ 62/* signal handler for updating the progress meter */
64static void update_progress_meter(int); 63static void sig_alarm(int);
65 64
66static double start; /* start progress */ 65static double start; /* start progress */
67static double last_update; /* last progress update */ 66static double last_update; /* last progress update */
@@ -74,6 +73,7 @@ static long stalled; /* how long we have been stalled */
74static int bytes_per_second; /* current speed in bytes per second */ 73static int bytes_per_second; /* current speed in bytes per second */
75static int win_size; /* terminal window size */ 74static int win_size; /* terminal window size */
76static volatile sig_atomic_t win_resized; /* for window resizing */ 75static volatile sig_atomic_t win_resized; /* for window resizing */
76static volatile sig_atomic_t alarm_fired;
77 77
78/* units for format_size */ 78/* units for format_size */
79static const char unit[] = " KMGT"; 79static const char unit[] = " KMGT";
@@ -117,7 +117,7 @@ format_size(char *buf, int size, off_t bytes)
117} 117}
118 118
119void 119void
120refresh_progress_meter(void) 120refresh_progress_meter(int force_update)
121{ 121{
122 char buf[MAX_WINSIZE + 1]; 122 char buf[MAX_WINSIZE + 1];
123 off_t transferred; 123 off_t transferred;
@@ -126,9 +126,17 @@ refresh_progress_meter(void)
126 off_t bytes_left; 126 off_t bytes_left;
127 int cur_speed; 127 int cur_speed;
128 int hours, minutes, seconds; 128 int hours, minutes, seconds;
129 int i, len;
130 int file_len; 129 int file_len;
131 130
131 if ((!force_update && !alarm_fired && !win_resized) || !can_output())
132 return;
133 alarm_fired = 0;
134
135 if (win_resized) {
136 setscreensize();
137 win_resized = 0;
138 }
139
132 transferred = *counter - (cur_pos ? cur_pos : start_pos); 140 transferred = *counter - (cur_pos ? cur_pos : start_pos);
133 cur_pos = *counter; 141 cur_pos = *counter;
134 now = monotime_double(); 142 now = monotime_double();
@@ -158,16 +166,11 @@ refresh_progress_meter(void)
158 166
159 /* filename */ 167 /* filename */
160 buf[0] = '\0'; 168 buf[0] = '\0';
161 file_len = win_size - 35; 169 file_len = win_size - 36;
162 if (file_len > 0) { 170 if (file_len > 0) {
163 len = snprintf(buf, file_len + 1, "\r%s", file); 171 buf[0] = '\r';
164 if (len < 0) 172 snmprintf(buf+1, sizeof(buf)-1 , &file_len, "%*s",
165 len = 0; 173 file_len * -1, file);
166 if (len >= file_len + 1)
167 len = file_len;
168 for (i = len; i < file_len; i++)
169 buf[i] = ' ';
170 buf[file_len] = '\0';
171 } 174 }
172 175
173 /* percent of transfer done */ 176 /* percent of transfer done */
@@ -228,22 +231,11 @@ refresh_progress_meter(void)
228 231
229/*ARGSUSED*/ 232/*ARGSUSED*/
230static void 233static void
231update_progress_meter(int ignore) 234sig_alarm(int ignore)
232{ 235{
233 int save_errno; 236 signal(SIGALRM, sig_alarm);
234 237 alarm_fired = 1;
235 save_errno = errno;
236
237 if (win_resized) {
238 setscreensize();
239 win_resized = 0;
240 }
241 if (can_output())
242 refresh_progress_meter();
243
244 signal(SIGALRM, update_progress_meter);
245 alarm(UPDATE_INTERVAL); 238 alarm(UPDATE_INTERVAL);
246 errno = save_errno;
247} 239}
248 240
249void 241void
@@ -259,10 +251,9 @@ start_progress_meter(const char *f, off_t filesize, off_t *ctr)
259 bytes_per_second = 0; 251 bytes_per_second = 0;
260 252
261 setscreensize(); 253 setscreensize();
262 if (can_output()) 254 refresh_progress_meter(1);
263 refresh_progress_meter();
264 255
265 signal(SIGALRM, update_progress_meter); 256 signal(SIGALRM, sig_alarm);
266 signal(SIGWINCH, sig_winch); 257 signal(SIGWINCH, sig_winch);
267 alarm(UPDATE_INTERVAL); 258 alarm(UPDATE_INTERVAL);
268} 259}
@@ -277,7 +268,7 @@ stop_progress_meter(void)
277 268
278 /* Ensure we complete the progress */ 269 /* Ensure we complete the progress */
279 if (cur_pos != end_pos) 270 if (cur_pos != end_pos)
280 refresh_progress_meter(); 271 refresh_progress_meter(1);
281 272
282 atomicio(vwrite, STDOUT_FILENO, "\n", 1); 273 atomicio(vwrite, STDOUT_FILENO, "\n", 1);
283} 274}
@@ -286,6 +277,7 @@ stop_progress_meter(void)
286static void 277static void
287sig_winch(int sig) 278sig_winch(int sig)
288{ 279{
280 signal(SIGWINCH, sig_winch);
289 win_resized = 1; 281 win_resized = 1;
290} 282}
291 283
diff --git a/progressmeter.h b/progressmeter.h
index bf179dca6..1703ea75b 100644
--- a/progressmeter.h
+++ b/progressmeter.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: progressmeter.h,v 1.3 2015/01/14 13:54:13 djm Exp $ */ 1/* $OpenBSD: progressmeter.h,v 1.5 2019/01/24 16:52:17 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Nils Nordman. All rights reserved. 3 * Copyright (c) 2002 Nils Nordman. All rights reserved.
4 * 4 *
@@ -24,4 +24,5 @@
24 */ 24 */
25 25
26void start_progress_meter(const char *, off_t, off_t *); 26void start_progress_meter(const char *, off_t, off_t *);
27void refresh_progress_meter(int);
27void stop_progress_meter(void); 28void stop_progress_meter(void);
diff --git a/scp.c b/scp.c
index 7163d33dc..1971c80cd 100644
--- a/scp.c
+++ b/scp.c
@@ -593,6 +593,7 @@ scpio(void *_cnt, size_t s)
593 off_t *cnt = (off_t *)_cnt; 593 off_t *cnt = (off_t *)_cnt;
594 594
595 *cnt += s; 595 *cnt += s;
596 refresh_progress_meter(0);
596 if (limit_kbps > 0) 597 if (limit_kbps > 0)
597 bandwidth_limit(&bwlimit, s); 598 bandwidth_limit(&bwlimit, s);
598 return 0; 599 return 0;
diff --git a/sftp-client.c b/sftp-client.c
index 4986d6d8d..cf2887a40 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -101,7 +101,9 @@ sftpio(void *_bwlimit, size_t amount)
101{ 101{
102 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 102 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
103 103
104 bandwidth_limit(bwlimit, amount); 104 refresh_progress_meter(0);
105 if (bwlimit != NULL)
106 bandwidth_limit(bwlimit, amount);
105 return 0; 107 return 0;
106} 108}
107 109
@@ -121,8 +123,8 @@ send_msg(struct sftp_conn *conn, struct sshbuf *m)
121 iov[1].iov_base = (u_char *)sshbuf_ptr(m); 123 iov[1].iov_base = (u_char *)sshbuf_ptr(m);
122 iov[1].iov_len = sshbuf_len(m); 124 iov[1].iov_len = sshbuf_len(m);
123 125
124 if (atomiciov6(writev, conn->fd_out, iov, 2, 126 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
125 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != 127 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
126 sshbuf_len(m) + sizeof(mlen)) 128 sshbuf_len(m) + sizeof(mlen))
127 fatal("Couldn't send packet: %s", strerror(errno)); 129 fatal("Couldn't send packet: %s", strerror(errno));
128 130
@@ -138,8 +140,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
138 140
139 if ((r = sshbuf_reserve(m, 4, &p)) != 0) 141 if ((r = sshbuf_reserve(m, 4, &p)) != 0)
140 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 142 fatal("%s: buffer error: %s", __func__, ssh_err(r));
141 if (atomicio6(read, conn->fd_in, p, 4, 143 if (atomicio6(read, conn->fd_in, p, 4, sftpio,
142 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { 144 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
143 if (errno == EPIPE || errno == ECONNRESET) 145 if (errno == EPIPE || errno == ECONNRESET)
144 fatal("Connection closed"); 146 fatal("Connection closed");
145 else 147 else
@@ -157,8 +159,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
157 159
158 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) 160 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
159 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 161 fatal("%s: buffer error: %s", __func__, ssh_err(r));
160 if (atomicio6(read, conn->fd_in, p, msg_len, 162 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
161 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) 163 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
162 != msg_len) { 164 != msg_len) {
163 if (errno == EPIPE) 165 if (errno == EPIPE)
164 fatal("Connection closed"); 166 fatal("Connection closed");