diff options
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | progressmeter.c | 51 | ||||
-rw-r--r-- | scp.c | 45 | ||||
-rw-r--r-- | sftp-client.c | 9 | ||||
-rw-r--r-- | sftp.c | 46 | ||||
-rw-r--r-- | utf8.c | 258 | ||||
-rw-r--r-- | utf8.h | 24 |
7 files changed, 369 insertions, 66 deletions
diff --git a/Makefile.in b/Makefile.in index af758d035..6267fefda 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -82,7 +82,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ | |||
82 | compat.o crc32.o deattack.o fatal.o hostfile.o \ | 82 | compat.o crc32.o deattack.o fatal.o hostfile.o \ |
83 | log.o match.o md-sha256.o moduli.o nchan.o packet.o opacket.o \ | 83 | log.o match.o md-sha256.o moduli.o nchan.o packet.o opacket.o \ |
84 | readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ | 84 | readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ |
85 | atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \ | 85 | atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf.o \ |
86 | monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ | 86 | monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ |
87 | msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ | 87 | msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ |
88 | ssh-pkcs11.o smult_curve25519_ref.o \ | 88 | ssh-pkcs11.o smult_curve25519_ref.o \ |
diff --git a/progressmeter.c b/progressmeter.c index 3a455408c..4fed2f4f0 100644 --- a/progressmeter.c +++ b/progressmeter.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: progressmeter.c,v 1.42 2016/03/02 22:42:40 dtucker Exp $ */ | 1 | /* $OpenBSD: progressmeter.c,v 1.43 2016/05/25 23:48:45 schwarze 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 |
@@ -119,14 +121,14 @@ format_size(char *buf, int size, off_t bytes) | |||
119 | void | 121 | void |
120 | refresh_progress_meter(void) | 122 | refresh_progress_meter(void) |
121 | { | 123 | { |
122 | char buf[MAX_WINSIZE + 1]; | 124 | char buf[MAX_WINSIZE * 4 + 1]; |
123 | off_t transferred; | 125 | off_t transferred; |
124 | double elapsed, now; | 126 | double elapsed, now; |
125 | int percent; | 127 | int percent; |
126 | off_t bytes_left; | 128 | off_t bytes_left; |
127 | int cur_speed; | 129 | int cur_speed; |
128 | int hours, minutes, seconds; | 130 | int hours, minutes, seconds; |
129 | int i, len; | 131 | size_t i; |
130 | int file_len; | 132 | int file_len; |
131 | 133 | ||
132 | transferred = *counter - (cur_pos ? cur_pos : start_pos); | 134 | transferred = *counter - (cur_pos ? cur_pos : start_pos); |
@@ -157,17 +159,16 @@ refresh_progress_meter(void) | |||
157 | bytes_per_second = cur_speed; | 159 | bytes_per_second = cur_speed; |
158 | 160 | ||
159 | /* filename */ | 161 | /* filename */ |
160 | buf[0] = '\0'; | 162 | buf[0] = '\r'; |
163 | buf[1] = '\0'; | ||
161 | file_len = win_size - 35; | 164 | file_len = win_size - 35; |
162 | if (file_len > 0) { | 165 | if (file_len > 0) { |
163 | len = snprintf(buf, file_len + 1, "\r%s", file); | 166 | (void) snmprintf(buf + 1, sizeof(buf) - 1 - 35, |
164 | if (len < 0) | 167 | &file_len, "%s", file); |
165 | len = 0; | 168 | i = strlen(buf); |
166 | if (len >= file_len + 1) | 169 | while (++file_len < win_size - 35 && i + 1 < sizeof(buf)) |
167 | len = file_len; | 170 | buf[i++] = ' '; |
168 | for (i = len; i < file_len; i++) | 171 | buf[i] = '\0'; |
169 | buf[i] = ' '; | ||
170 | buf[file_len] = '\0'; | ||
171 | } | 172 | } |
172 | 173 | ||
173 | /* percent of transfer done */ | 174 | /* percent of transfer done */ |
@@ -175,18 +176,18 @@ refresh_progress_meter(void) | |||
175 | percent = ((float)cur_pos / end_pos) * 100; | 176 | percent = ((float)cur_pos / end_pos) * 100; |
176 | else | 177 | else |
177 | percent = 100; | 178 | percent = 100; |
178 | snprintf(buf + strlen(buf), win_size - strlen(buf), | 179 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), |
179 | " %3d%% ", percent); | 180 | " %3d%% ", percent); |
180 | 181 | ||
181 | /* amount transferred */ | 182 | /* amount transferred */ |
182 | format_size(buf + strlen(buf), win_size - strlen(buf), | 183 | format_size(buf + strlen(buf), sizeof(buf) - strlen(buf), |
183 | cur_pos); | 184 | cur_pos); |
184 | strlcat(buf, " ", win_size); | 185 | strlcat(buf, " ", sizeof(buf)); |
185 | 186 | ||
186 | /* bandwidth usage */ | 187 | /* bandwidth usage */ |
187 | format_rate(buf + strlen(buf), win_size - strlen(buf), | 188 | format_rate(buf + strlen(buf), sizeof(buf) - strlen(buf), |
188 | (off_t)bytes_per_second); | 189 | (off_t)bytes_per_second); |
189 | strlcat(buf, "/s ", win_size); | 190 | strlcat(buf, "/s ", sizeof(buf)); |
190 | 191 | ||
191 | /* ETA */ | 192 | /* ETA */ |
192 | if (!transferred) | 193 | if (!transferred) |
@@ -195,9 +196,9 @@ refresh_progress_meter(void) | |||
195 | stalled = 0; | 196 | stalled = 0; |
196 | 197 | ||
197 | if (stalled >= STALL_TIME) | 198 | if (stalled >= STALL_TIME) |
198 | strlcat(buf, "- stalled -", win_size); | 199 | strlcat(buf, "- stalled -", sizeof(buf)); |
199 | else if (bytes_per_second == 0 && bytes_left) | 200 | else if (bytes_per_second == 0 && bytes_left) |
200 | strlcat(buf, " --:-- ETA", win_size); | 201 | strlcat(buf, " --:-- ETA", sizeof(buf)); |
201 | else { | 202 | else { |
202 | if (bytes_left > 0) | 203 | if (bytes_left > 0) |
203 | seconds = bytes_left / bytes_per_second; | 204 | seconds = bytes_left / bytes_per_second; |
@@ -210,19 +211,21 @@ refresh_progress_meter(void) | |||
210 | seconds -= minutes * 60; | 211 | seconds -= minutes * 60; |
211 | 212 | ||
212 | if (hours != 0) | 213 | if (hours != 0) |
213 | snprintf(buf + strlen(buf), win_size - strlen(buf), | 214 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), |
214 | "%d:%02d:%02d", hours, minutes, seconds); | 215 | "%d:%02d:%02d", hours, minutes, seconds); |
215 | else | 216 | else |
216 | snprintf(buf + strlen(buf), win_size - strlen(buf), | 217 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), |
217 | " %02d:%02d", minutes, seconds); | 218 | " %02d:%02d", minutes, seconds); |
218 | 219 | ||
219 | if (bytes_left > 0) | 220 | if (bytes_left > 0) |
220 | strlcat(buf, " ETA", win_size); | 221 | strlcat(buf, " ETA", sizeof(buf)); |
221 | else | 222 | else |
222 | strlcat(buf, " ", win_size); | 223 | strlcat(buf, " ", sizeof(buf)); |
223 | } | 224 | } |
225 | if (win_size < 35) | ||
226 | buf[win_size] = '\0'; | ||
224 | 227 | ||
225 | atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); | 228 | atomicio(vwrite, STDOUT_FILENO, buf, strlen(buf)); |
226 | last_update = now; | 229 | last_update = now; |
227 | } | 230 | } |
228 | 231 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: scp.c,v 1.185 2016/03/02 22:43:52 dtucker Exp $ */ | 1 | /* $OpenBSD: scp.c,v 1.186 2016/05/25 23:48:45 schwarze Exp $ */ |
2 | /* | 2 | /* |
3 | * scp - secure remote copy. This is basically patched BSD rcp which | 3 | * scp - secure remote copy. This is basically patched BSD rcp which |
4 | * uses ssh to do the data transfer (instead of using rcmd). | 4 | * uses ssh to do the data transfer (instead of using rcmd). |
@@ -96,6 +96,7 @@ | |||
96 | #include <errno.h> | 96 | #include <errno.h> |
97 | #include <fcntl.h> | 97 | #include <fcntl.h> |
98 | #include <limits.h> | 98 | #include <limits.h> |
99 | #include <locale.h> | ||
99 | #include <pwd.h> | 100 | #include <pwd.h> |
100 | #include <signal.h> | 101 | #include <signal.h> |
101 | #include <stdarg.h> | 102 | #include <stdarg.h> |
@@ -114,6 +115,7 @@ | |||
114 | #include "log.h" | 115 | #include "log.h" |
115 | #include "misc.h" | 116 | #include "misc.h" |
116 | #include "progressmeter.h" | 117 | #include "progressmeter.h" |
118 | #include "utf8.h" | ||
117 | 119 | ||
118 | extern char *__progname; | 120 | extern char *__progname; |
119 | 121 | ||
@@ -191,7 +193,7 @@ do_local_cmd(arglist *a) | |||
191 | if (verbose_mode) { | 193 | if (verbose_mode) { |
192 | fprintf(stderr, "Executing:"); | 194 | fprintf(stderr, "Executing:"); |
193 | for (i = 0; i < a->num; i++) | 195 | for (i = 0; i < a->num; i++) |
194 | fprintf(stderr, " %s", a->list[i]); | 196 | fmprintf(stderr, " %s", a->list[i]); |
195 | fprintf(stderr, "\n"); | 197 | fprintf(stderr, "\n"); |
196 | } | 198 | } |
197 | if ((pid = fork()) == -1) | 199 | if ((pid = fork()) == -1) |
@@ -232,7 +234,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) | |||
232 | int pin[2], pout[2], reserved[2]; | 234 | int pin[2], pout[2], reserved[2]; |
233 | 235 | ||
234 | if (verbose_mode) | 236 | if (verbose_mode) |
235 | fprintf(stderr, | 237 | fmprintf(stderr, |
236 | "Executing: program %s host %s, user %s, command %s\n", | 238 | "Executing: program %s host %s, user %s, command %s\n", |
237 | ssh_program, host, | 239 | ssh_program, host, |
238 | remuser ? remuser : "(unspecified)", cmd); | 240 | remuser ? remuser : "(unspecified)", cmd); |
@@ -307,7 +309,7 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) | |||
307 | int status; | 309 | int status; |
308 | 310 | ||
309 | if (verbose_mode) | 311 | if (verbose_mode) |
310 | fprintf(stderr, | 312 | fmprintf(stderr, |
311 | "Executing: 2nd program %s host %s, user %s, command %s\n", | 313 | "Executing: 2nd program %s host %s, user %s, command %s\n", |
312 | ssh_program, host, | 314 | ssh_program, host, |
313 | remuser ? remuser : "(unspecified)", cmd); | 315 | remuser ? remuser : "(unspecified)", cmd); |
@@ -378,6 +380,8 @@ main(int argc, char **argv) | |||
378 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 380 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
379 | sanitise_stdfd(); | 381 | sanitise_stdfd(); |
380 | 382 | ||
383 | setlocale(LC_CTYPE, ""); | ||
384 | |||
381 | /* Copy argv, because we modify it */ | 385 | /* Copy argv, because we modify it */ |
382 | newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv)); | 386 | newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv)); |
383 | for (n = 0; n < argc; n++) | 387 | for (n = 0; n < argc; n++) |
@@ -810,9 +814,8 @@ syserr: run_err("%s: %s", name, strerror(errno)); | |||
810 | snprintf(buf, sizeof buf, "C%04o %lld %s\n", | 814 | snprintf(buf, sizeof buf, "C%04o %lld %s\n", |
811 | (u_int) (stb.st_mode & FILEMODEMASK), | 815 | (u_int) (stb.st_mode & FILEMODEMASK), |
812 | (long long)stb.st_size, last); | 816 | (long long)stb.st_size, last); |
813 | if (verbose_mode) { | 817 | if (verbose_mode) |
814 | fprintf(stderr, "Sending file modes: %s", buf); | 818 | fmprintf(stderr, "Sending file modes: %s", buf); |
815 | } | ||
816 | (void) atomicio(vwrite, remout, buf, strlen(buf)); | 819 | (void) atomicio(vwrite, remout, buf, strlen(buf)); |
817 | if (response() < 0) | 820 | if (response() < 0) |
818 | goto next; | 821 | goto next; |
@@ -889,7 +892,7 @@ rsource(char *name, struct stat *statp) | |||
889 | (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", | 892 | (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", |
890 | (u_int) (statp->st_mode & FILEMODEMASK), 0, last); | 893 | (u_int) (statp->st_mode & FILEMODEMASK), 0, last); |
891 | if (verbose_mode) | 894 | if (verbose_mode) |
892 | fprintf(stderr, "Entering directory: %s", path); | 895 | fmprintf(stderr, "Entering directory: %s", path); |
893 | (void) atomicio(vwrite, remout, path, strlen(path)); | 896 | (void) atomicio(vwrite, remout, path, strlen(path)); |
894 | if (response() < 0) { | 897 | if (response() < 0) { |
895 | closedir(dirp); | 898 | closedir(dirp); |
@@ -929,7 +932,7 @@ sink(int argc, char **argv) | |||
929 | off_t size, statbytes; | 932 | off_t size, statbytes; |
930 | unsigned long long ull; | 933 | unsigned long long ull; |
931 | int setimes, targisdir, wrerrno = 0; | 934 | int setimes, targisdir, wrerrno = 0; |
932 | char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; | 935 | char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; |
933 | struct timeval tv[2]; | 936 | struct timeval tv[2]; |
934 | 937 | ||
935 | #define atime tv[0] | 938 | #define atime tv[0] |
@@ -964,12 +967,15 @@ sink(int argc, char **argv) | |||
964 | } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); | 967 | } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); |
965 | *cp = 0; | 968 | *cp = 0; |
966 | if (verbose_mode) | 969 | if (verbose_mode) |
967 | fprintf(stderr, "Sink: %s", buf); | 970 | fmprintf(stderr, "Sink: %s", buf); |
968 | 971 | ||
969 | if (buf[0] == '\01' || buf[0] == '\02') { | 972 | if (buf[0] == '\01' || buf[0] == '\02') { |
970 | if (iamremote == 0) | 973 | if (iamremote == 0) { |
974 | (void) snmprintf(visbuf, sizeof(visbuf), | ||
975 | NULL, "%s", buf + 1); | ||
971 | (void) atomicio(vwrite, STDERR_FILENO, | 976 | (void) atomicio(vwrite, STDERR_FILENO, |
972 | buf + 1, strlen(buf + 1)); | 977 | visbuf, strlen(visbuf)); |
978 | } | ||
973 | if (buf[0] == '\02') | 979 | if (buf[0] == '\02') |
974 | exit(1); | 980 | exit(1); |
975 | ++errs; | 981 | ++errs; |
@@ -1212,7 +1218,7 @@ screwup: | |||
1212 | int | 1218 | int |
1213 | response(void) | 1219 | response(void) |
1214 | { | 1220 | { |
1215 | char ch, *cp, resp, rbuf[2048]; | 1221 | char ch, *cp, resp, rbuf[2048], visbuf[2048]; |
1216 | 1222 | ||
1217 | if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) | 1223 | if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) |
1218 | lostconn(0); | 1224 | lostconn(0); |
@@ -1232,8 +1238,13 @@ response(void) | |||
1232 | *cp++ = ch; | 1238 | *cp++ = ch; |
1233 | } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); | 1239 | } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); |
1234 | 1240 | ||
1235 | if (!iamremote) | 1241 | if (!iamremote) { |
1236 | (void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf); | 1242 | cp[-1] = '\0'; |
1243 | (void) snmprintf(visbuf, sizeof(visbuf), | ||
1244 | NULL, "%s\n", rbuf); | ||
1245 | (void) atomicio(vwrite, STDERR_FILENO, | ||
1246 | visbuf, strlen(visbuf)); | ||
1247 | } | ||
1237 | ++errs; | 1248 | ++errs; |
1238 | if (resp == 1) | 1249 | if (resp == 1) |
1239 | return (-1); | 1250 | return (-1); |
@@ -1271,7 +1282,7 @@ run_err(const char *fmt,...) | |||
1271 | 1282 | ||
1272 | if (!iamremote) { | 1283 | if (!iamremote) { |
1273 | va_start(ap, fmt); | 1284 | va_start(ap, fmt); |
1274 | vfprintf(stderr, fmt, ap); | 1285 | vfmprintf(stderr, fmt, ap); |
1275 | va_end(ap); | 1286 | va_end(ap); |
1276 | fprintf(stderr, "\n"); | 1287 | fprintf(stderr, "\n"); |
1277 | } | 1288 | } |
@@ -1317,7 +1328,7 @@ okname(char *cp0) | |||
1317 | } while (*++cp); | 1328 | } while (*++cp); |
1318 | return (1); | 1329 | return (1); |
1319 | 1330 | ||
1320 | bad: fprintf(stderr, "%s: invalid user name\n", cp0); | 1331 | bad: fmprintf(stderr, "%s: invalid user name\n", cp0); |
1321 | return (0); | 1332 | return (0); |
1322 | } | 1333 | } |
1323 | 1334 | ||
diff --git a/sftp-client.c b/sftp-client.c index faf14684c..0ca44a4d6 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.123 2016/05/02 08:49:03 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.124 2016/05/25 23:48:45 schwarze Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -53,6 +53,7 @@ | |||
53 | #include "atomicio.h" | 53 | #include "atomicio.h" |
54 | #include "progressmeter.h" | 54 | #include "progressmeter.h" |
55 | #include "misc.h" | 55 | #include "misc.h" |
56 | #include "utf8.h" | ||
56 | 57 | ||
57 | #include "sftp.h" | 58 | #include "sftp.h" |
58 | #include "sftp-common.h" | 59 | #include "sftp-common.h" |
@@ -610,7 +611,7 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, | |||
610 | } | 611 | } |
611 | 612 | ||
612 | if (print_flag) | 613 | if (print_flag) |
613 | printf("%s\n", longname); | 614 | mprintf("%s\n", longname); |
614 | 615 | ||
615 | /* | 616 | /* |
616 | * Directory entries should never contain '/' | 617 | * Directory entries should never contain '/' |
@@ -1460,7 +1461,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, | |||
1460 | return -1; | 1461 | return -1; |
1461 | } | 1462 | } |
1462 | if (print_flag) | 1463 | if (print_flag) |
1463 | printf("Retrieving %s\n", src); | 1464 | mprintf("Retrieving %s\n", src); |
1464 | 1465 | ||
1465 | if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) | 1466 | if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
1466 | mode = dirattrib->perm & 01777; | 1467 | mode = dirattrib->perm & 01777; |
@@ -1793,7 +1794,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, | |||
1793 | return -1; | 1794 | return -1; |
1794 | } | 1795 | } |
1795 | if (print_flag) | 1796 | if (print_flag) |
1796 | printf("Entering %s\n", src); | 1797 | mprintf("Entering %s\n", src); |
1797 | 1798 | ||
1798 | attrib_clear(&a); | 1799 | attrib_clear(&a); |
1799 | stat_to_attrib(&sb, &a); | 1800 | stat_to_attrib(&sb, &a); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.173 2016/04/08 08:19:17 djm Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.174 2016/05/25 23:48:45 schwarze Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -49,6 +49,7 @@ typedef void EditLine; | |||
49 | #endif | 49 | #endif |
50 | #include <limits.h> | 50 | #include <limits.h> |
51 | #include <signal.h> | 51 | #include <signal.h> |
52 | #include <stdarg.h> | ||
52 | #include <stdlib.h> | 53 | #include <stdlib.h> |
53 | #include <stdio.h> | 54 | #include <stdio.h> |
54 | #include <string.h> | 55 | #include <string.h> |
@@ -63,6 +64,7 @@ typedef void EditLine; | |||
63 | #include "log.h" | 64 | #include "log.h" |
64 | #include "pathnames.h" | 65 | #include "pathnames.h" |
65 | #include "misc.h" | 66 | #include "misc.h" |
67 | #include "utf8.h" | ||
66 | 68 | ||
67 | #include "sftp.h" | 69 | #include "sftp.h" |
68 | #include "ssherr.h" | 70 | #include "ssherr.h" |
@@ -644,9 +646,11 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
644 | 646 | ||
645 | resume |= global_aflag; | 647 | resume |= global_aflag; |
646 | if (!quiet && resume) | 648 | if (!quiet && resume) |
647 | printf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst); | 649 | mprintf("Resuming %s to %s\n", |
650 | g.gl_pathv[i], abs_dst); | ||
648 | else if (!quiet && !resume) | 651 | else if (!quiet && !resume) |
649 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); | 652 | mprintf("Fetching %s to %s\n", |
653 | g.gl_pathv[i], abs_dst); | ||
650 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 654 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
651 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, | 655 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, |
652 | pflag || global_pflag, 1, resume, | 656 | pflag || global_pflag, 1, resume, |
@@ -735,10 +739,11 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
735 | 739 | ||
736 | resume |= global_aflag; | 740 | resume |= global_aflag; |
737 | if (!quiet && resume) | 741 | if (!quiet && resume) |
738 | printf("Resuming upload of %s to %s\n", g.gl_pathv[i], | 742 | mprintf("Resuming upload of %s to %s\n", |
739 | abs_dst); | 743 | g.gl_pathv[i], abs_dst); |
740 | else if (!quiet && !resume) | 744 | else if (!quiet && !resume) |
741 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); | 745 | mprintf("Uploading %s to %s\n", |
746 | g.gl_pathv[i], abs_dst); | ||
742 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 747 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
743 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, | 748 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, |
744 | pflag || global_pflag, 1, resume, | 749 | pflag || global_pflag, 1, resume, |
@@ -839,12 +844,12 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
839 | attrib_to_stat(&d[n]->a, &sb); | 844 | attrib_to_stat(&d[n]->a, &sb); |
840 | lname = ls_file(fname, &sb, 1, | 845 | lname = ls_file(fname, &sb, 1, |
841 | (lflag & LS_SI_UNITS)); | 846 | (lflag & LS_SI_UNITS)); |
842 | printf("%s\n", lname); | 847 | mprintf("%s\n", lname); |
843 | free(lname); | 848 | free(lname); |
844 | } else | 849 | } else |
845 | printf("%s\n", d[n]->longname); | 850 | mprintf("%s\n", d[n]->longname); |
846 | } else { | 851 | } else { |
847 | printf("%-*s", colspace, fname); | 852 | mprintf("%-*s", colspace, fname); |
848 | if (c >= columns) { | 853 | if (c >= columns) { |
849 | printf("\n"); | 854 | printf("\n"); |
850 | c = 1; | 855 | c = 1; |
@@ -925,10 +930,10 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
925 | } | 930 | } |
926 | lname = ls_file(fname, g.gl_statv[i], 1, | 931 | lname = ls_file(fname, g.gl_statv[i], 1, |
927 | (lflag & LS_SI_UNITS)); | 932 | (lflag & LS_SI_UNITS)); |
928 | printf("%s\n", lname); | 933 | mprintf("%s\n", lname); |
929 | free(lname); | 934 | free(lname); |
930 | } else { | 935 | } else { |
931 | printf("%-*s", colspace, fname); | 936 | mprintf("%-*s", colspace, fname); |
932 | if (c >= columns) { | 937 | if (c >= columns) { |
933 | printf("\n"); | 938 | printf("\n"); |
934 | c = 1; | 939 | c = 1; |
@@ -1456,7 +1461,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1456 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 1461 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
1457 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 1462 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
1458 | if (!quiet) | 1463 | if (!quiet) |
1459 | printf("Removing %s\n", g.gl_pathv[i]); | 1464 | mprintf("Removing %s\n", g.gl_pathv[i]); |
1460 | err = do_rm(conn, g.gl_pathv[i]); | 1465 | err = do_rm(conn, g.gl_pathv[i]); |
1461 | if (err != 0 && err_abort) | 1466 | if (err != 0 && err_abort) |
1462 | break; | 1467 | break; |
@@ -1556,7 +1561,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1556 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 1561 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
1557 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 1562 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
1558 | if (!quiet) | 1563 | if (!quiet) |
1559 | printf("Changing mode on %s\n", g.gl_pathv[i]); | 1564 | mprintf("Changing mode on %s\n", |
1565 | g.gl_pathv[i]); | ||
1560 | err = do_setstat(conn, g.gl_pathv[i], &a); | 1566 | err = do_setstat(conn, g.gl_pathv[i], &a); |
1561 | if (err != 0 && err_abort) | 1567 | if (err != 0 && err_abort) |
1562 | break; | 1568 | break; |
@@ -1586,12 +1592,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1586 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | 1592 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
1587 | if (cmdnum == I_CHOWN) { | 1593 | if (cmdnum == I_CHOWN) { |
1588 | if (!quiet) | 1594 | if (!quiet) |
1589 | printf("Changing owner on %s\n", | 1595 | mprintf("Changing owner on %s\n", |
1590 | g.gl_pathv[i]); | 1596 | g.gl_pathv[i]); |
1591 | aa->uid = n_arg; | 1597 | aa->uid = n_arg; |
1592 | } else { | 1598 | } else { |
1593 | if (!quiet) | 1599 | if (!quiet) |
1594 | printf("Changing group on %s\n", | 1600 | mprintf("Changing group on %s\n", |
1595 | g.gl_pathv[i]); | 1601 | g.gl_pathv[i]); |
1596 | aa->gid = n_arg; | 1602 | aa->gid = n_arg; |
1597 | } | 1603 | } |
@@ -1601,7 +1607,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1601 | } | 1607 | } |
1602 | break; | 1608 | break; |
1603 | case I_PWD: | 1609 | case I_PWD: |
1604 | printf("Remote working directory: %s\n", *pwd); | 1610 | mprintf("Remote working directory: %s\n", *pwd); |
1605 | break; | 1611 | break; |
1606 | case I_LPWD: | 1612 | case I_LPWD: |
1607 | if (!getcwd(path_buf, sizeof(path_buf))) { | 1613 | if (!getcwd(path_buf, sizeof(path_buf))) { |
@@ -1609,7 +1615,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1609 | err = -1; | 1615 | err = -1; |
1610 | break; | 1616 | break; |
1611 | } | 1617 | } |
1612 | printf("Local working directory: %s\n", path_buf); | 1618 | mprintf("Local working directory: %s\n", path_buf); |
1613 | break; | 1619 | break; |
1614 | case I_QUIT: | 1620 | case I_QUIT: |
1615 | /* Processed below */ | 1621 | /* Processed below */ |
@@ -1678,7 +1684,7 @@ complete_display(char **list, u_int len) | |||
1678 | for (y = 0; list[y]; y++) { | 1684 | for (y = 0; list[y]; y++) { |
1679 | llen = strlen(list[y]); | 1685 | llen = strlen(list[y]); |
1680 | tmp = llen > len ? list[y] + len : ""; | 1686 | tmp = llen > len ? list[y] + len : ""; |
1681 | printf("%-*s", colspace, tmp); | 1687 | mprintf("%-*s", colspace, tmp); |
1682 | if (m >= columns) { | 1688 | if (m >= columns) { |
1683 | printf("\n"); | 1689 | printf("\n"); |
1684 | m = 1; | 1690 | m = 1; |
@@ -2062,7 +2068,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) | |||
2062 | 2068 | ||
2063 | if (remote_is_dir(conn, dir) && file2 == NULL) { | 2069 | if (remote_is_dir(conn, dir) && file2 == NULL) { |
2064 | if (!quiet) | 2070 | if (!quiet) |
2065 | printf("Changing to: %s\n", dir); | 2071 | mprintf("Changing to: %s\n", dir); |
2066 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); | 2072 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); |
2067 | if (parse_dispatch_command(conn, cmd, | 2073 | if (parse_dispatch_command(conn, cmd, |
2068 | &remote_path, 1) != 0) { | 2074 | &remote_path, 1) != 0) { |
@@ -2106,7 +2112,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) | |||
2106 | break; | 2112 | break; |
2107 | } | 2113 | } |
2108 | if (!interactive) { /* Echo command */ | 2114 | if (!interactive) { /* Echo command */ |
2109 | printf("sftp> %s", cmd); | 2115 | mprintf("sftp> %s", cmd); |
2110 | if (strlen(cmd) > 0 && | 2116 | if (strlen(cmd) > 0 && |
2111 | cmd[strlen(cmd) - 1] != '\n') | 2117 | cmd[strlen(cmd) - 1] != '\n') |
2112 | printf("\n"); | 2118 | printf("\n"); |
@@ -0,0 +1,258 @@ | |||
1 | /* $OpenBSD: utf8.c,v 1.1 2016/05/25 23:48:45 schwarze Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Utility functions for multibyte-character handling, | ||
20 | * in particular to sanitize untrusted strings for terminal output. | ||
21 | */ | ||
22 | |||
23 | #include <sys/types.h> | ||
24 | #include <langinfo.h> | ||
25 | #include <limits.h> | ||
26 | #include <stdarg.h> | ||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include <vis.h> | ||
31 | #include <wchar.h> | ||
32 | |||
33 | #include "utf8.h" | ||
34 | |||
35 | static int dangerous_locale(void); | ||
36 | static int vasnmprintf(char **, size_t, int *, const char *, va_list); | ||
37 | |||
38 | |||
39 | /* | ||
40 | * For US-ASCII and UTF-8 encodings, we can safely recover from | ||
41 | * encoding errors and from non-printable characters. For any | ||
42 | * other encodings, err to the side of caution and abort parsing: | ||
43 | * For state-dependent encodings, recovery is impossible. | ||
44 | * For arbitrary encodings, replacement of non-printable | ||
45 | * characters would be non-trivial and too fragile. | ||
46 | */ | ||
47 | |||
48 | static int | ||
49 | dangerous_locale(void) { | ||
50 | char *loc; | ||
51 | |||
52 | loc = nl_langinfo(CODESET); | ||
53 | return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8"); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * The following two functions limit the number of bytes written, | ||
58 | * including the terminating '\0', to sz. Unless wp is NULL, | ||
59 | * they limit the number of display columns occupied to *wp. | ||
60 | * Whichever is reached first terminates the output string. | ||
61 | * To stay close to the standard interfaces, they return the number of | ||
62 | * non-NUL bytes that would have been written if both were unlimited. | ||
63 | * If wp is NULL, newline, carriage return, and tab are allowed; | ||
64 | * otherwise, the actual number of columns occupied by what was | ||
65 | * written is returned in *wp. | ||
66 | */ | ||
67 | |||
68 | static int | ||
69 | vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap) | ||
70 | { | ||
71 | char *src; /* Source string returned from vasprintf. */ | ||
72 | char *sp; /* Pointer into src. */ | ||
73 | char *dst; /* Destination string to be returned. */ | ||
74 | char *dp; /* Pointer into dst. */ | ||
75 | char *tp; /* Temporary pointer for dst. */ | ||
76 | size_t sz; /* Number of bytes allocated for dst. */ | ||
77 | size_t tsz; /* Temporary size while extending dst. */ | ||
78 | wchar_t wc; /* Wide character at sp. */ | ||
79 | int len; /* Number of bytes in the character at sp. */ | ||
80 | int ret; /* Number of bytes needed to format src. */ | ||
81 | int width; /* Display width of the character wc. */ | ||
82 | int total_width, max_width, print; | ||
83 | |||
84 | src = dst = NULL; | ||
85 | if (vasprintf(&src, fmt, ap) <= 0) | ||
86 | goto fail; | ||
87 | |||
88 | sz = strlen(src); | ||
89 | if ((dst = malloc(sz)) == NULL) | ||
90 | goto fail; | ||
91 | |||
92 | if (maxsz > INT_MAX) | ||
93 | maxsz = INT_MAX; | ||
94 | |||
95 | sp = src; | ||
96 | dp = dst; | ||
97 | ret = 0; | ||
98 | print = 1; | ||
99 | total_width = 0; | ||
100 | max_width = wp == NULL ? INT_MAX : *wp; | ||
101 | while (*sp != '\0') { | ||
102 | if ((len = mbtowc(&wc, sp, MB_CUR_MAX)) == -1) { | ||
103 | (void)mbtowc(NULL, NULL, MB_CUR_MAX); | ||
104 | if (dangerous_locale()) { | ||
105 | ret = -1; | ||
106 | break; | ||
107 | } | ||
108 | len = 1; | ||
109 | width = -1; | ||
110 | } else if (wp == NULL && | ||
111 | (wc == L'\n' || wc == L'\r' || wc == L'\t')) { | ||
112 | /* | ||
113 | * Don't use width uninitialized; the actual | ||
114 | * value doesn't matter because total_width | ||
115 | * is only returned for wp != NULL. | ||
116 | */ | ||
117 | width = 0; | ||
118 | } else if ((width = wcwidth(wc)) == -1 && | ||
119 | dangerous_locale()) { | ||
120 | ret = -1; | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | /* Valid, printable character. */ | ||
125 | |||
126 | if (width >= 0) { | ||
127 | if (print && (dp - dst >= (int)maxsz - len || | ||
128 | total_width > max_width - width)) | ||
129 | print = 0; | ||
130 | if (print) { | ||
131 | total_width += width; | ||
132 | memcpy(dp, sp, len); | ||
133 | dp += len; | ||
134 | } | ||
135 | sp += len; | ||
136 | if (ret >= 0) | ||
137 | ret += len; | ||
138 | continue; | ||
139 | } | ||
140 | |||
141 | /* Escaping required. */ | ||
142 | |||
143 | while (len > 0) { | ||
144 | if (print && (dp - dst >= (int)maxsz - 4 || | ||
145 | total_width > max_width - 4)) | ||
146 | print = 0; | ||
147 | if (print) { | ||
148 | if (dp + 4 >= dst + sz) { | ||
149 | tsz = sz + 128; | ||
150 | if (tsz > maxsz) | ||
151 | tsz = maxsz; | ||
152 | tp = realloc(dst, tsz); | ||
153 | if (tp == NULL) { | ||
154 | ret = -1; | ||
155 | break; | ||
156 | } | ||
157 | dp = tp + (dp - dst); | ||
158 | dst = tp; | ||
159 | sz = tsz; | ||
160 | } | ||
161 | tp = vis(dp, *sp, VIS_OCTAL | VIS_ALL, 0); | ||
162 | width = tp - dp; | ||
163 | total_width += width; | ||
164 | dp = tp; | ||
165 | } else | ||
166 | width = 4; | ||
167 | len--; | ||
168 | sp++; | ||
169 | if (ret >= 0) | ||
170 | ret += width; | ||
171 | } | ||
172 | if (len > 0) | ||
173 | break; | ||
174 | } | ||
175 | free(src); | ||
176 | *dp = '\0'; | ||
177 | *str = dst; | ||
178 | if (wp != NULL) | ||
179 | *wp = total_width; | ||
180 | |||
181 | /* | ||
182 | * If the string was truncated by the width limit but | ||
183 | * would have fit into the size limit, the only sane way | ||
184 | * to report the problem is using the return value, such | ||
185 | * that the usual idiom "if (ret < 0 || ret >= sz) error" | ||
186 | * works as expected. | ||
187 | */ | ||
188 | |||
189 | if (ret < (int)maxsz && !print) | ||
190 | ret = -1; | ||
191 | return ret; | ||
192 | |||
193 | fail: | ||
194 | free(src); | ||
195 | free(dst); | ||
196 | *str = NULL; | ||
197 | if (wp != NULL) | ||
198 | *wp = 0; | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | int | ||
203 | snmprintf(char *str, size_t sz, int *wp, const char *fmt, ...) | ||
204 | { | ||
205 | va_list ap; | ||
206 | char *cp; | ||
207 | int ret; | ||
208 | |||
209 | va_start(ap, fmt); | ||
210 | ret = vasnmprintf(&cp, sz, wp, fmt, ap); | ||
211 | va_end(ap); | ||
212 | (void)strlcpy(str, cp, sz); | ||
213 | free(cp); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * To stay close to the standard interfaces, the following functions | ||
219 | * return the number of non-NUL bytes written. | ||
220 | */ | ||
221 | |||
222 | int | ||
223 | vfmprintf(FILE *stream, const char *fmt, va_list ap) | ||
224 | { | ||
225 | char *str; | ||
226 | int ret; | ||
227 | |||
228 | if ((ret = vasnmprintf(&str, INT_MAX, NULL, fmt, ap)) < 0) | ||
229 | return -1; | ||
230 | if (fputs(str, stream) == EOF) | ||
231 | ret = -1; | ||
232 | free(str); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | int | ||
237 | fmprintf(FILE *stream, const char *fmt, ...) | ||
238 | { | ||
239 | va_list ap; | ||
240 | int ret; | ||
241 | |||
242 | va_start(ap, fmt); | ||
243 | ret = vfmprintf(stream, fmt, ap); | ||
244 | va_end(ap); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | int | ||
249 | mprintf(const char *fmt, ...) | ||
250 | { | ||
251 | va_list ap; | ||
252 | int ret; | ||
253 | |||
254 | va_start(ap, fmt); | ||
255 | ret = vfmprintf(stdout, fmt, ap); | ||
256 | va_end(ap); | ||
257 | return ret; | ||
258 | } | ||
@@ -0,0 +1,24 @@ | |||
1 | /* $OpenBSD: utf8.h,v 1.1 2016/05/25 23:48:45 schwarze Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | int mprintf(const char *, ...) | ||
19 | __attribute__((format(printf, 1, 2))); | ||
20 | int fmprintf(FILE *, const char *, ...) | ||
21 | __attribute__((format(printf, 2, 3))); | ||
22 | int vfmprintf(FILE *, const char *, va_list); | ||
23 | int snmprintf(char *, size_t, int *, const char *, ...) | ||
24 | __attribute__((format(printf, 4, 5))); | ||