1 1.30 christos /* $NetBSD: misc.c,v 1.40 2025/10/11 15:45:06 christos Exp $ */ 2 1.40 christos /* $OpenBSD: misc.c,v 1.208 2025/09/25 06:33:19 djm Exp $ */ 3 1.34 christos 4 1.1 christos /* 5 1.1 christos * Copyright (c) 2000 Markus Friedl. All rights reserved. 6 1.24 christos * Copyright (c) 2005-2020 Damien Miller. All rights reserved. 7 1.24 christos * Copyright (c) 2004 Henning Brauer <henning (at) openbsd.org> 8 1.1 christos * 9 1.24 christos * Permission to use, copy, modify, and distribute this software for any 10 1.24 christos * purpose with or without fee is hereby granted, provided that the above 11 1.24 christos * copyright notice and this permission notice appear in all copies. 12 1.1 christos * 13 1.24 christos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 1.24 christos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 1.24 christos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 1.24 christos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 1.24 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 1.24 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 1.24 christos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 1.1 christos */ 21 1.1 christos 22 1.2 christos #include "includes.h" 23 1.30 christos __RCSID("$NetBSD: misc.c,v 1.40 2025/10/11 15:45:06 christos Exp $"); 24 1.24 christos 25 1.1 christos #include <sys/types.h> 26 1.1 christos #include <sys/ioctl.h> 27 1.1 christos #include <sys/socket.h> 28 1.16 christos #include <sys/stat.h> 29 1.12 christos #include <sys/time.h> 30 1.16 christos #include <sys/wait.h> 31 1.9 christos #include <sys/un.h> 32 1.1 christos 33 1.1 christos #include <net/if.h> 34 1.2 christos #include <net/if_tun.h> 35 1.1 christos #include <netinet/in.h> 36 1.5 christos #include <netinet/ip.h> 37 1.1 christos #include <netinet/tcp.h> 38 1.20 christos #include <arpa/inet.h> 39 1.1 christos 40 1.9 christos #include <ctype.h> 41 1.1 christos #include <errno.h> 42 1.1 christos #include <fcntl.h> 43 1.1 christos #include <netdb.h> 44 1.1 christos #include <paths.h> 45 1.1 christos #include <pwd.h> 46 1.16 christos #include <libgen.h> 47 1.10 christos #include <limits.h> 48 1.34 christos #include <nlist.h> 49 1.20 christos #include <poll.h> 50 1.16 christos #include <signal.h> 51 1.1 christos #include <stdarg.h> 52 1.1 christos #include <stdio.h> 53 1.34 christos #include <stdint.h> 54 1.1 christos #include <stdlib.h> 55 1.1 christos #include <string.h> 56 1.1 christos #include <unistd.h> 57 1.1 christos 58 1.1 christos #include "xmalloc.h" 59 1.1 christos #include "misc.h" 60 1.1 christos #include "log.h" 61 1.1 christos #include "ssh.h" 62 1.16 christos #include "sshbuf.h" 63 1.16 christos #include "ssherr.h" 64 1.1 christos 65 1.1 christos /* remove newline at end of string */ 66 1.1 christos char * 67 1.1 christos chop(char *s) 68 1.1 christos { 69 1.1 christos char *t = s; 70 1.1 christos while (*t) { 71 1.1 christos if (*t == '\n' || *t == '\r') { 72 1.1 christos *t = '\0'; 73 1.1 christos return s; 74 1.1 christos } 75 1.1 christos t++; 76 1.1 christos } 77 1.1 christos return s; 78 1.1 christos 79 1.1 christos } 80 1.1 christos 81 1.27 christos /* remove whitespace from end of string */ 82 1.27 christos void 83 1.27 christos rtrim(char *s) 84 1.27 christos { 85 1.27 christos size_t i; 86 1.27 christos 87 1.27 christos if ((i = strlen(s)) == 0) 88 1.27 christos return; 89 1.40 christos do { 90 1.40 christos i--; 91 1.29 christos if (isspace((unsigned char)s[i])) 92 1.27 christos s[i] = '\0'; 93 1.40 christos else 94 1.40 christos break; 95 1.40 christos } while (i > 0); 96 1.27 christos } 97 1.27 christos 98 1.38 christos /* 99 1.38 christos * returns pointer to character after 'prefix' in 's' or otherwise NULL 100 1.38 christos * if the prefix is not present. 101 1.38 christos */ 102 1.38 christos const char * 103 1.38 christos strprefix(const char *s, const char *prefix, int ignorecase) 104 1.38 christos { 105 1.38 christos size_t prefixlen; 106 1.38 christos 107 1.38 christos if ((prefixlen = strlen(prefix)) == 0) 108 1.38 christos return s; 109 1.38 christos if (ignorecase) { 110 1.38 christos if (strncasecmp(s, prefix, prefixlen) != 0) 111 1.38 christos return NULL; 112 1.38 christos } else { 113 1.38 christos if (strncmp(s, prefix, prefixlen) != 0) 114 1.38 christos return NULL; 115 1.38 christos } 116 1.38 christos return s + prefixlen; 117 1.38 christos } 118 1.38 christos 119 1.1 christos /* set/unset filedescriptor to non-blocking */ 120 1.1 christos int 121 1.1 christos set_nonblock(int fd) 122 1.1 christos { 123 1.1 christos int val; 124 1.1 christos 125 1.13 christos val = fcntl(fd, F_GETFL); 126 1.21 christos if (val == -1) { 127 1.13 christos error("fcntl(%d, F_GETFL): %s", fd, strerror(errno)); 128 1.1 christos return (-1); 129 1.1 christos } 130 1.1 christos if (val & O_NONBLOCK) { 131 1.1 christos debug3("fd %d is O_NONBLOCK", fd); 132 1.1 christos return (0); 133 1.1 christos } 134 1.1 christos debug2("fd %d setting O_NONBLOCK", fd); 135 1.1 christos val |= O_NONBLOCK; 136 1.1 christos if (fcntl(fd, F_SETFL, val) == -1) { 137 1.1 christos debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 138 1.1 christos strerror(errno)); 139 1.1 christos return (-1); 140 1.1 christos } 141 1.1 christos return (0); 142 1.1 christos } 143 1.1 christos 144 1.1 christos int 145 1.1 christos unset_nonblock(int fd) 146 1.1 christos { 147 1.1 christos int val; 148 1.1 christos 149 1.13 christos val = fcntl(fd, F_GETFL); 150 1.21 christos if (val == -1) { 151 1.13 christos error("fcntl(%d, F_GETFL): %s", fd, strerror(errno)); 152 1.1 christos return (-1); 153 1.1 christos } 154 1.1 christos if (!(val & O_NONBLOCK)) { 155 1.1 christos debug3("fd %d is not O_NONBLOCK", fd); 156 1.1 christos return (0); 157 1.1 christos } 158 1.1 christos debug("fd %d clearing O_NONBLOCK", fd); 159 1.1 christos val &= ~O_NONBLOCK; 160 1.1 christos if (fcntl(fd, F_SETFL, val) == -1) { 161 1.1 christos debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 162 1.1 christos fd, strerror(errno)); 163 1.1 christos return (-1); 164 1.1 christos } 165 1.1 christos return (0); 166 1.1 christos } 167 1.1 christos 168 1.1 christos const char * 169 1.1 christos ssh_gai_strerror(int gaierr) 170 1.1 christos { 171 1.8 christos if (gaierr == EAI_SYSTEM && errno != 0) 172 1.1 christos return strerror(errno); 173 1.1 christos return gai_strerror(gaierr); 174 1.1 christos } 175 1.1 christos 176 1.1 christos /* disable nagle on socket */ 177 1.1 christos void 178 1.1 christos set_nodelay(int fd) 179 1.1 christos { 180 1.1 christos int opt; 181 1.1 christos socklen_t optlen; 182 1.1 christos 183 1.1 christos optlen = sizeof opt; 184 1.1 christos if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 185 1.1 christos debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 186 1.1 christos return; 187 1.1 christos } 188 1.1 christos if (opt == 1) { 189 1.1 christos debug2("fd %d is TCP_NODELAY", fd); 190 1.1 christos return; 191 1.1 christos } 192 1.1 christos opt = 1; 193 1.1 christos debug2("fd %d setting TCP_NODELAY", fd); 194 1.1 christos if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 195 1.1 christos error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 196 1.1 christos } 197 1.1 christos 198 1.17 christos /* Allow local port reuse in TIME_WAIT */ 199 1.17 christos int 200 1.17 christos set_reuseaddr(int fd) 201 1.17 christos { 202 1.17 christos int on = 1; 203 1.17 christos 204 1.17 christos if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { 205 1.17 christos error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno)); 206 1.17 christos return -1; 207 1.17 christos } 208 1.17 christos return 0; 209 1.17 christos } 210 1.17 christos 211 1.17 christos /* Get/set routing domain */ 212 1.17 christos char * 213 1.17 christos get_rdomain(int fd) 214 1.17 christos { 215 1.17 christos #ifdef SO_RTABLE 216 1.17 christos int rtable; 217 1.17 christos char *ret; 218 1.17 christos socklen_t len = sizeof(rtable); 219 1.17 christos 220 1.17 christos if (getsockopt(fd, SOL_SOCKET, SO_RTABLE, &rtable, &len) == -1) { 221 1.17 christos error("Failed to get routing domain for fd %d: %s", 222 1.17 christos fd, strerror(errno)); 223 1.17 christos return NULL; 224 1.17 christos } 225 1.17 christos xasprintf(&ret, "%d", rtable); 226 1.17 christos return ret; 227 1.17 christos #else 228 1.17 christos return NULL; 229 1.17 christos #endif 230 1.17 christos } 231 1.17 christos 232 1.17 christos int 233 1.17 christos set_rdomain(int fd, const char *name) 234 1.17 christos { 235 1.17 christos #ifdef SO_RTABLE 236 1.17 christos int rtable; 237 1.17 christos const char *errstr; 238 1.17 christos 239 1.17 christos if (name == NULL) 240 1.17 christos return 0; /* default table */ 241 1.17 christos 242 1.17 christos rtable = (int)strtonum(name, 0, 255, &errstr); 243 1.17 christos if (errstr != NULL) { 244 1.17 christos /* Shouldn't happen */ 245 1.17 christos error("Invalid routing domain \"%s\": %s", name, errstr); 246 1.17 christos return -1; 247 1.17 christos } 248 1.17 christos if (setsockopt(fd, SOL_SOCKET, SO_RTABLE, 249 1.17 christos &rtable, sizeof(rtable)) == -1) { 250 1.17 christos error("Failed to set routing domain %d on fd %d: %s", 251 1.17 christos rtable, fd, strerror(errno)); 252 1.17 christos return -1; 253 1.17 christos } 254 1.17 christos return 0; 255 1.17 christos #else 256 1.17 christos return -1; 257 1.17 christos #endif 258 1.17 christos } 259 1.17 christos 260 1.25 christos int 261 1.25 christos get_sock_af(int fd) 262 1.25 christos { 263 1.25 christos struct sockaddr_storage to; 264 1.25 christos socklen_t tolen = sizeof(to); 265 1.25 christos 266 1.25 christos memset(&to, 0, sizeof(to)); 267 1.25 christos if (getsockname(fd, (struct sockaddr *)&to, &tolen) == -1) 268 1.25 christos return -1; 269 1.25 christos return to.ss_family; 270 1.25 christos } 271 1.25 christos 272 1.25 christos void 273 1.25 christos set_sock_tos(int fd, int tos) 274 1.25 christos { 275 1.25 christos int af; 276 1.25 christos 277 1.40 christos if (tos < 0 || tos == INT_MAX) { 278 1.40 christos debug_f("invalid TOS %d", tos); 279 1.40 christos return; 280 1.40 christos } 281 1.25 christos switch ((af = get_sock_af(fd))) { 282 1.25 christos case -1: 283 1.25 christos /* assume not a socket */ 284 1.25 christos break; 285 1.25 christos case AF_INET: 286 1.25 christos debug3_f("set socket %d IP_TOS 0x%02x", fd, tos); 287 1.25 christos if (setsockopt(fd, IPPROTO_IP, IP_TOS, 288 1.25 christos &tos, sizeof(tos)) == -1) { 289 1.33 christos error("setsockopt socket %d IP_TOS %d: %s", 290 1.25 christos fd, tos, strerror(errno)); 291 1.25 christos } 292 1.25 christos break; 293 1.25 christos case AF_INET6: 294 1.25 christos debug3_f("set socket %d IPV6_TCLASS 0x%02x", fd, tos); 295 1.25 christos if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, 296 1.25 christos &tos, sizeof(tos)) == -1) { 297 1.33 christos error("setsockopt socket %d IPV6_TCLASS %d: %s", 298 1.25 christos fd, tos, strerror(errno)); 299 1.25 christos } 300 1.25 christos break; 301 1.25 christos default: 302 1.25 christos debug2_f("unsupported socket family %d", af); 303 1.25 christos break; 304 1.25 christos } 305 1.25 christos } 306 1.25 christos 307 1.20 christos /* 308 1.22 christos * Wait up to *timeoutp milliseconds for events on fd. Updates 309 1.20 christos * *timeoutp with time remaining. 310 1.20 christos * Returns 0 if fd ready or -1 on timeout or error (see errno). 311 1.20 christos */ 312 1.22 christos static int 313 1.34 christos waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop) 314 1.20 christos { 315 1.20 christos struct pollfd pfd; 316 1.34 christos struct timespec timeout; 317 1.20 christos int oerrno, r; 318 1.34 christos sigset_t nsigset, osigset; 319 1.20 christos 320 1.34 christos if (timeoutp && *timeoutp == -1) 321 1.34 christos timeoutp = NULL; 322 1.20 christos pfd.fd = fd; 323 1.22 christos pfd.events = events; 324 1.34 christos ptimeout_init(&timeout); 325 1.34 christos if (timeoutp != NULL) 326 1.34 christos ptimeout_deadline_ms(&timeout, *timeoutp); 327 1.34 christos if (stop != NULL) 328 1.34 christos sigfillset(&nsigset); 329 1.34 christos for (; timeoutp == NULL || *timeoutp >= 0;) { 330 1.34 christos if (stop != NULL) { 331 1.34 christos sigprocmask(SIG_BLOCK, &nsigset, &osigset); 332 1.34 christos if (*stop) { 333 1.34 christos sigprocmask(SIG_SETMASK, &osigset, NULL); 334 1.34 christos errno = EINTR; 335 1.34 christos return -1; 336 1.34 christos } 337 1.34 christos } 338 1.34 christos r = ppoll(&pfd, 1, ptimeout_get_tsp(&timeout), 339 1.34 christos stop != NULL ? &osigset : NULL); 340 1.20 christos oerrno = errno; 341 1.34 christos if (stop != NULL) 342 1.34 christos sigprocmask(SIG_SETMASK, &osigset, NULL); 343 1.34 christos if (timeoutp) 344 1.34 christos *timeoutp = ptimeout_get_ms(&timeout); 345 1.20 christos errno = oerrno; 346 1.20 christos if (r > 0) 347 1.20 christos return 0; 348 1.24 christos else if (r == -1 && errno != EAGAIN && errno != EINTR) 349 1.20 christos return -1; 350 1.20 christos else if (r == 0) 351 1.20 christos break; 352 1.20 christos } 353 1.20 christos /* timeout */ 354 1.20 christos errno = ETIMEDOUT; 355 1.20 christos return -1; 356 1.20 christos } 357 1.20 christos 358 1.20 christos /* 359 1.22 christos * Wait up to *timeoutp milliseconds for fd to be readable. Updates 360 1.22 christos * *timeoutp with time remaining. 361 1.22 christos * Returns 0 if fd ready or -1 on timeout or error (see errno). 362 1.22 christos */ 363 1.22 christos int 364 1.34 christos waitrfd(int fd, int *timeoutp, volatile sig_atomic_t *stop) { 365 1.34 christos return waitfd(fd, timeoutp, POLLIN, stop); 366 1.22 christos } 367 1.22 christos 368 1.22 christos /* 369 1.20 christos * Attempt a non-blocking connect(2) to the specified address, waiting up to 370 1.20 christos * *timeoutp milliseconds for the connection to complete. If the timeout is 371 1.20 christos * <=0, then wait indefinitely. 372 1.20 christos * 373 1.20 christos * Returns 0 on success or -1 on failure. 374 1.20 christos */ 375 1.20 christos int 376 1.20 christos timeout_connect(int sockfd, const struct sockaddr *serv_addr, 377 1.20 christos socklen_t addrlen, int *timeoutp) 378 1.20 christos { 379 1.20 christos int optval = 0; 380 1.20 christos socklen_t optlen = sizeof(optval); 381 1.20 christos 382 1.20 christos /* No timeout: just do a blocking connect() */ 383 1.20 christos if (timeoutp == NULL || *timeoutp <= 0) 384 1.20 christos return connect(sockfd, serv_addr, addrlen); 385 1.20 christos 386 1.20 christos set_nonblock(sockfd); 387 1.24 christos for (;;) { 388 1.24 christos if (connect(sockfd, serv_addr, addrlen) == 0) { 389 1.24 christos /* Succeeded already? */ 390 1.24 christos unset_nonblock(sockfd); 391 1.24 christos return 0; 392 1.24 christos } else if (errno == EINTR) 393 1.24 christos continue; 394 1.24 christos else if (errno != EINPROGRESS) 395 1.24 christos return -1; 396 1.24 christos break; 397 1.24 christos } 398 1.20 christos 399 1.34 christos if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT, NULL) == -1) 400 1.20 christos return -1; 401 1.20 christos 402 1.20 christos /* Completed or failed */ 403 1.20 christos if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) { 404 1.20 christos debug("getsockopt: %s", strerror(errno)); 405 1.20 christos return -1; 406 1.20 christos } 407 1.20 christos if (optval != 0) { 408 1.20 christos errno = optval; 409 1.20 christos return -1; 410 1.20 christos } 411 1.20 christos unset_nonblock(sockfd); 412 1.20 christos return 0; 413 1.20 christos } 414 1.20 christos 415 1.1 christos /* Characters considered whitespace in strsep calls. */ 416 1.1 christos #define WHITESPACE " \t\r\n" 417 1.1 christos #define QUOTE "\"" 418 1.1 christos 419 1.1 christos /* return next token in configuration line */ 420 1.18 christos static char * 421 1.18 christos strdelim_internal(char **s, int split_equals) 422 1.1 christos { 423 1.1 christos char *old; 424 1.1 christos int wspace = 0; 425 1.1 christos 426 1.1 christos if (*s == NULL) 427 1.1 christos return NULL; 428 1.1 christos 429 1.1 christos old = *s; 430 1.1 christos 431 1.18 christos *s = strpbrk(*s, 432 1.18 christos split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE); 433 1.1 christos if (*s == NULL) 434 1.1 christos return (old); 435 1.1 christos 436 1.1 christos if (*s[0] == '\"') { 437 1.1 christos memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 438 1.1 christos /* Find matching quote */ 439 1.1 christos if ((*s = strpbrk(*s, QUOTE)) == NULL) { 440 1.1 christos return (NULL); /* no matching quote */ 441 1.1 christos } else { 442 1.1 christos *s[0] = '\0'; 443 1.4 adam *s += strspn(*s + 1, WHITESPACE) + 1; 444 1.1 christos return (old); 445 1.1 christos } 446 1.1 christos } 447 1.1 christos 448 1.1 christos /* Allow only one '=' to be skipped */ 449 1.18 christos if (split_equals && *s[0] == '=') 450 1.1 christos wspace = 1; 451 1.1 christos *s[0] = '\0'; 452 1.1 christos 453 1.1 christos /* Skip any extra whitespace after first token */ 454 1.1 christos *s += strspn(*s + 1, WHITESPACE) + 1; 455 1.18 christos if (split_equals && *s[0] == '=' && !wspace) 456 1.1 christos *s += strspn(*s + 1, WHITESPACE) + 1; 457 1.1 christos 458 1.1 christos return (old); 459 1.1 christos } 460 1.1 christos 461 1.18 christos /* 462 1.40 christos * Return next token in configuration line; splits on whitespace or a 463 1.18 christos * single '=' character. 464 1.18 christos */ 465 1.18 christos char * 466 1.18 christos strdelim(char **s) 467 1.18 christos { 468 1.18 christos return strdelim_internal(s, 1); 469 1.18 christos } 470 1.18 christos 471 1.18 christos /* 472 1.40 christos * Return next token in configuration line; splits on whitespace only. 473 1.18 christos */ 474 1.18 christos char * 475 1.18 christos strdelimw(char **s) 476 1.18 christos { 477 1.18 christos return strdelim_internal(s, 0); 478 1.18 christos } 479 1.18 christos 480 1.1 christos struct passwd * 481 1.1 christos pwcopy(struct passwd *pw) 482 1.1 christos { 483 1.1 christos struct passwd *copy = xcalloc(1, sizeof(*copy)); 484 1.1 christos 485 1.1 christos copy->pw_name = xstrdup(pw->pw_name); 486 1.1 christos copy->pw_passwd = xstrdup(pw->pw_passwd); 487 1.1 christos copy->pw_gecos = xstrdup(pw->pw_gecos); 488 1.1 christos copy->pw_uid = pw->pw_uid; 489 1.1 christos copy->pw_gid = pw->pw_gid; 490 1.1 christos copy->pw_expire = pw->pw_expire; 491 1.1 christos copy->pw_change = pw->pw_change; 492 1.1 christos copy->pw_class = xstrdup(pw->pw_class); 493 1.1 christos copy->pw_dir = xstrdup(pw->pw_dir); 494 1.1 christos copy->pw_shell = xstrdup(pw->pw_shell); 495 1.1 christos return copy; 496 1.1 christos } 497 1.1 christos 498 1.40 christos void 499 1.40 christos pwfree(struct passwd *pw) 500 1.40 christos { 501 1.40 christos if (pw == NULL) 502 1.40 christos return; 503 1.40 christos free(pw->pw_name); 504 1.40 christos freezero(pw->pw_passwd, 505 1.40 christos pw->pw_passwd == NULL ? 0 : strlen(pw->pw_passwd)); 506 1.40 christos free(pw->pw_gecos); 507 1.40 christos free(pw->pw_class); 508 1.40 christos free(pw->pw_dir); 509 1.40 christos free(pw->pw_shell); 510 1.40 christos freezero(pw, sizeof(*pw)); 511 1.40 christos } 512 1.40 christos 513 1.1 christos /* 514 1.1 christos * Convert ASCII string to TCP/IP port number. 515 1.1 christos * Port must be >=0 and <=65535. 516 1.1 christos * Return -1 if invalid. 517 1.1 christos */ 518 1.1 christos int 519 1.1 christos a2port(const char *s) 520 1.1 christos { 521 1.20 christos struct servent *se; 522 1.1 christos long long port; 523 1.1 christos const char *errstr; 524 1.1 christos 525 1.1 christos port = strtonum(s, 0, 65535, &errstr); 526 1.20 christos if (errstr == NULL) 527 1.20 christos return (int)port; 528 1.20 christos if ((se = getservbyname(s, "tcp")) != NULL) 529 1.20 christos return ntohs(se->s_port); 530 1.20 christos return -1; 531 1.1 christos } 532 1.1 christos 533 1.1 christos int 534 1.1 christos a2tun(const char *s, int *remote) 535 1.1 christos { 536 1.1 christos const char *errstr = NULL; 537 1.1 christos char *sp, *ep; 538 1.1 christos int tun; 539 1.1 christos 540 1.1 christos if (remote != NULL) { 541 1.1 christos *remote = SSH_TUNID_ANY; 542 1.1 christos sp = xstrdup(s); 543 1.1 christos if ((ep = strchr(sp, ':')) == NULL) { 544 1.8 christos free(sp); 545 1.1 christos return (a2tun(s, NULL)); 546 1.1 christos } 547 1.1 christos ep[0] = '\0'; ep++; 548 1.1 christos *remote = a2tun(ep, NULL); 549 1.1 christos tun = a2tun(sp, NULL); 550 1.8 christos free(sp); 551 1.1 christos return (*remote == SSH_TUNID_ERR ? *remote : tun); 552 1.1 christos } 553 1.1 christos 554 1.1 christos if (strcasecmp(s, "any") == 0) 555 1.1 christos return (SSH_TUNID_ANY); 556 1.1 christos 557 1.1 christos tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 558 1.1 christos if (errstr != NULL) 559 1.1 christos return (SSH_TUNID_ERR); 560 1.1 christos 561 1.1 christos return (tun); 562 1.1 christos } 563 1.1 christos 564 1.1 christos #define SECONDS 1 565 1.1 christos #define MINUTES (SECONDS * 60) 566 1.1 christos #define HOURS (MINUTES * 60) 567 1.1 christos #define DAYS (HOURS * 24) 568 1.1 christos #define WEEKS (DAYS * 7) 569 1.1 christos 570 1.37 christos static char * 571 1.37 christos scandigits(char *s) 572 1.37 christos { 573 1.37 christos while (isdigit((unsigned char)*s)) 574 1.37 christos s++; 575 1.37 christos return s; 576 1.37 christos } 577 1.37 christos 578 1.1 christos /* 579 1.1 christos * Convert a time string into seconds; format is 580 1.1 christos * a sequence of: 581 1.1 christos * time[qualifier] 582 1.1 christos * 583 1.1 christos * Valid time qualifiers are: 584 1.1 christos * <none> seconds 585 1.1 christos * s|S seconds 586 1.1 christos * m|M minutes 587 1.1 christos * h|H hours 588 1.1 christos * d|D days 589 1.1 christos * w|W weeks 590 1.1 christos * 591 1.1 christos * Examples: 592 1.1 christos * 90m 90 minutes 593 1.1 christos * 1h30m 90 minutes 594 1.1 christos * 2d 2 days 595 1.1 christos * 1w 1 week 596 1.1 christos * 597 1.1 christos * Return -1 if time string is invalid. 598 1.1 christos */ 599 1.25 christos int 600 1.1 christos convtime(const char *s) 601 1.1 christos { 602 1.37 christos int secs, total = 0, multiplier; 603 1.37 christos char *p, *os, *np, c = 0; 604 1.37 christos const char *errstr; 605 1.1 christos 606 1.37 christos if (s == NULL || *s == '\0') 607 1.37 christos return -1; 608 1.37 christos p = os = strdup(s); /* deal with const */ 609 1.37 christos if (os == NULL) 610 1.1 christos return -1; 611 1.1 christos 612 1.1 christos while (*p) { 613 1.37 christos np = scandigits(p); 614 1.37 christos if (np) { 615 1.37 christos c = *np; 616 1.37 christos *np = '\0'; 617 1.37 christos } 618 1.37 christos secs = (int)strtonum(p, 0, INT_MAX, &errstr); 619 1.37 christos if (errstr) 620 1.37 christos goto fail; 621 1.37 christos *np = c; 622 1.1 christos 623 1.24 christos multiplier = 1; 624 1.37 christos switch (c) { 625 1.1 christos case '\0': 626 1.37 christos np--; /* back up */ 627 1.1 christos break; 628 1.1 christos case 's': 629 1.1 christos case 'S': 630 1.1 christos break; 631 1.1 christos case 'm': 632 1.1 christos case 'M': 633 1.15 christos multiplier = MINUTES; 634 1.1 christos break; 635 1.1 christos case 'h': 636 1.1 christos case 'H': 637 1.15 christos multiplier = HOURS; 638 1.1 christos break; 639 1.1 christos case 'd': 640 1.1 christos case 'D': 641 1.15 christos multiplier = DAYS; 642 1.1 christos break; 643 1.1 christos case 'w': 644 1.1 christos case 'W': 645 1.15 christos multiplier = WEEKS; 646 1.1 christos break; 647 1.1 christos default: 648 1.37 christos goto fail; 649 1.1 christos } 650 1.25 christos if (secs > INT_MAX / multiplier) 651 1.37 christos goto fail; 652 1.15 christos secs *= multiplier; 653 1.25 christos if (total > INT_MAX - secs) 654 1.37 christos goto fail; 655 1.1 christos total += secs; 656 1.1 christos if (total < 0) 657 1.37 christos goto fail; 658 1.37 christos p = ++np; 659 1.1 christos } 660 1.37 christos free(os); 661 1.1 christos return total; 662 1.37 christos fail: 663 1.37 christos free(os); 664 1.37 christos return -1; 665 1.1 christos } 666 1.1 christos 667 1.24 christos #define TF_BUFS 8 668 1.24 christos #define TF_LEN 21 669 1.24 christos 670 1.24 christos const char * 671 1.24 christos fmt_timeframe(time_t t) 672 1.24 christos { 673 1.24 christos char *buf; 674 1.24 christos static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 675 1.24 christos static int idx = 0; 676 1.24 christos unsigned int sec, min, hrs, day; 677 1.24 christos unsigned long long week; 678 1.24 christos 679 1.24 christos buf = tfbuf[idx++]; 680 1.24 christos if (idx == TF_BUFS) 681 1.24 christos idx = 0; 682 1.24 christos 683 1.24 christos week = t; 684 1.24 christos 685 1.24 christos sec = week % 60; 686 1.24 christos week /= 60; 687 1.24 christos min = week % 60; 688 1.24 christos week /= 60; 689 1.24 christos hrs = week % 24; 690 1.24 christos week /= 24; 691 1.24 christos day = week % 7; 692 1.24 christos week /= 7; 693 1.24 christos 694 1.24 christos if (week > 0) 695 1.24 christos snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 696 1.24 christos else if (day > 0) 697 1.24 christos snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 698 1.24 christos else 699 1.24 christos snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 700 1.24 christos 701 1.24 christos return (buf); 702 1.24 christos } 703 1.24 christos 704 1.1 christos /* 705 1.1 christos * Returns a standardized host+port identifier string. 706 1.1 christos * Caller must free returned string. 707 1.1 christos */ 708 1.1 christos char * 709 1.1 christos put_host_port(const char *host, u_short port) 710 1.1 christos { 711 1.1 christos char *hoststr; 712 1.1 christos 713 1.1 christos if (port == 0 || port == SSH_DEFAULT_PORT) 714 1.1 christos return(xstrdup(host)); 715 1.21 christos if (asprintf(&hoststr, "[%s]:%d", host, (int)port) == -1) 716 1.1 christos fatal("put_host_port: asprintf: %s", strerror(errno)); 717 1.1 christos debug3("put_host_port: %s", hoststr); 718 1.1 christos return hoststr; 719 1.1 christos } 720 1.1 christos 721 1.1 christos /* 722 1.1 christos * Search for next delimiter between hostnames/addresses and ports. 723 1.1 christos * Argument may be modified (for termination). 724 1.1 christos * Returns *cp if parsing succeeds. 725 1.17 christos * *cp is set to the start of the next field, if one was found. 726 1.17 christos * The delimiter char, if present, is stored in delim. 727 1.1 christos * If this is the last field, *cp is set to NULL. 728 1.1 christos */ 729 1.20 christos char * 730 1.17 christos hpdelim2(char **cp, char *delim) 731 1.1 christos { 732 1.1 christos char *s, *old; 733 1.1 christos 734 1.1 christos if (cp == NULL || *cp == NULL) 735 1.1 christos return NULL; 736 1.1 christos 737 1.1 christos old = s = *cp; 738 1.1 christos if (*s == '[') { 739 1.1 christos if ((s = strchr(s, ']')) == NULL) 740 1.1 christos return NULL; 741 1.1 christos else 742 1.1 christos s++; 743 1.1 christos } else if ((s = strpbrk(s, ":/")) == NULL) 744 1.1 christos s = *cp + strlen(*cp); /* skip to end (see first case below) */ 745 1.1 christos 746 1.1 christos switch (*s) { 747 1.1 christos case '\0': 748 1.1 christos *cp = NULL; /* no more fields*/ 749 1.1 christos break; 750 1.1 christos 751 1.1 christos case ':': 752 1.1 christos case '/': 753 1.17 christos if (delim != NULL) 754 1.17 christos *delim = *s; 755 1.1 christos *s = '\0'; /* terminate */ 756 1.1 christos *cp = s + 1; 757 1.1 christos break; 758 1.1 christos 759 1.1 christos default: 760 1.1 christos return NULL; 761 1.1 christos } 762 1.1 christos 763 1.1 christos return old; 764 1.1 christos } 765 1.1 christos 766 1.29 christos /* The common case: only accept colon as delimiter. */ 767 1.1 christos char * 768 1.17 christos hpdelim(char **cp) 769 1.17 christos { 770 1.29 christos char *r, delim = '\0'; 771 1.29 christos 772 1.29 christos r = hpdelim2(cp, &delim); 773 1.29 christos if (delim == '/') 774 1.29 christos return NULL; 775 1.29 christos return r; 776 1.17 christos } 777 1.17 christos 778 1.17 christos char * 779 1.1 christos cleanhostname(char *host) 780 1.1 christos { 781 1.1 christos if (*host == '[' && host[strlen(host) - 1] == ']') { 782 1.1 christos host[strlen(host) - 1] = '\0'; 783 1.1 christos return (host + 1); 784 1.1 christos } else 785 1.1 christos return host; 786 1.1 christos } 787 1.1 christos 788 1.1 christos char * 789 1.1 christos colon(char *cp) 790 1.1 christos { 791 1.1 christos int flag = 0; 792 1.1 christos 793 1.1 christos if (*cp == ':') /* Leading colon is part of file name. */ 794 1.4 adam return NULL; 795 1.1 christos if (*cp == '[') 796 1.1 christos flag = 1; 797 1.1 christos 798 1.1 christos for (; *cp; ++cp) { 799 1.1 christos if (*cp == '@' && *(cp+1) == '[') 800 1.1 christos flag = 1; 801 1.1 christos if (*cp == ']' && *(cp+1) == ':' && flag) 802 1.1 christos return (cp+1); 803 1.1 christos if (*cp == ':' && !flag) 804 1.1 christos return (cp); 805 1.1 christos if (*cp == '/') 806 1.4 adam return NULL; 807 1.1 christos } 808 1.4 adam return NULL; 809 1.1 christos } 810 1.1 christos 811 1.13 christos /* 812 1.17 christos * Parse a [user@]host:[path] string. 813 1.17 christos * Caller must free returned user, host and path. 814 1.17 christos * Any of the pointer return arguments may be NULL (useful for syntax checking). 815 1.17 christos * If user was not specified then *userp will be set to NULL. 816 1.17 christos * If host was not specified then *hostp will be set to NULL. 817 1.17 christos * If path was not specified then *pathp will be set to ".". 818 1.17 christos * Returns 0 on success, -1 on failure. 819 1.17 christos */ 820 1.17 christos int 821 1.25 christos parse_user_host_path(const char *s, char **userp, char **hostp, char **pathp) 822 1.17 christos { 823 1.17 christos char *user = NULL, *host = NULL, *path = NULL; 824 1.30 christos char *sdup, *tmp; 825 1.17 christos int ret = -1; 826 1.17 christos 827 1.17 christos if (userp != NULL) 828 1.17 christos *userp = NULL; 829 1.17 christos if (hostp != NULL) 830 1.17 christos *hostp = NULL; 831 1.17 christos if (pathp != NULL) 832 1.17 christos *pathp = NULL; 833 1.17 christos 834 1.17 christos sdup = xstrdup(s); 835 1.17 christos 836 1.17 christos /* Check for remote syntax: [user@]host:[path] */ 837 1.17 christos if ((tmp = colon(sdup)) == NULL) 838 1.17 christos goto out; 839 1.17 christos 840 1.17 christos /* Extract optional path */ 841 1.17 christos *tmp++ = '\0'; 842 1.17 christos if (*tmp == '\0') 843 1.17 christos tmp = __UNCONST("."); 844 1.17 christos path = xstrdup(tmp); 845 1.17 christos 846 1.17 christos /* Extract optional user and mandatory host */ 847 1.17 christos tmp = strrchr(sdup, '@'); 848 1.17 christos if (tmp != NULL) { 849 1.17 christos *tmp++ = '\0'; 850 1.17 christos host = xstrdup(cleanhostname(tmp)); 851 1.17 christos if (*sdup != '\0') 852 1.17 christos user = xstrdup(sdup); 853 1.17 christos } else { 854 1.17 christos host = xstrdup(cleanhostname(sdup)); 855 1.17 christos user = NULL; 856 1.17 christos } 857 1.17 christos 858 1.17 christos /* Success */ 859 1.17 christos if (userp != NULL) { 860 1.17 christos *userp = user; 861 1.17 christos user = NULL; 862 1.17 christos } 863 1.17 christos if (hostp != NULL) { 864 1.17 christos *hostp = host; 865 1.17 christos host = NULL; 866 1.17 christos } 867 1.17 christos if (pathp != NULL) { 868 1.17 christos *pathp = path; 869 1.17 christos path = NULL; 870 1.17 christos } 871 1.17 christos ret = 0; 872 1.17 christos out: 873 1.17 christos free(sdup); 874 1.17 christos free(user); 875 1.17 christos free(host); 876 1.17 christos free(path); 877 1.17 christos return ret; 878 1.17 christos } 879 1.17 christos 880 1.17 christos /* 881 1.13 christos * Parse a [user@]host[:port] string. 882 1.13 christos * Caller must free returned user and host. 883 1.13 christos * Any of the pointer return arguments may be NULL (useful for syntax checking). 884 1.13 christos * If user was not specified then *userp will be set to NULL. 885 1.13 christos * If port was not specified then *portp will be -1. 886 1.13 christos * Returns 0 on success, -1 on failure. 887 1.13 christos */ 888 1.13 christos int 889 1.13 christos parse_user_host_port(const char *s, char **userp, char **hostp, int *portp) 890 1.13 christos { 891 1.13 christos char *sdup, *cp, *tmp; 892 1.13 christos char *user = NULL, *host = NULL; 893 1.13 christos int port = -1, ret = -1; 894 1.13 christos 895 1.13 christos if (userp != NULL) 896 1.13 christos *userp = NULL; 897 1.13 christos if (hostp != NULL) 898 1.13 christos *hostp = NULL; 899 1.13 christos if (portp != NULL) 900 1.13 christos *portp = -1; 901 1.13 christos 902 1.13 christos if ((sdup = tmp = strdup(s)) == NULL) 903 1.13 christos return -1; 904 1.13 christos /* Extract optional username */ 905 1.17 christos if ((cp = strrchr(tmp, '@')) != NULL) { 906 1.13 christos *cp = '\0'; 907 1.13 christos if (*tmp == '\0') 908 1.13 christos goto out; 909 1.13 christos if ((user = strdup(tmp)) == NULL) 910 1.13 christos goto out; 911 1.13 christos tmp = cp + 1; 912 1.13 christos } 913 1.13 christos /* Extract mandatory hostname */ 914 1.13 christos if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0') 915 1.13 christos goto out; 916 1.13 christos host = xstrdup(cleanhostname(cp)); 917 1.13 christos /* Convert and verify optional port */ 918 1.13 christos if (tmp != NULL && *tmp != '\0') { 919 1.13 christos if ((port = a2port(tmp)) <= 0) 920 1.13 christos goto out; 921 1.13 christos } 922 1.13 christos /* Success */ 923 1.13 christos if (userp != NULL) { 924 1.13 christos *userp = user; 925 1.13 christos user = NULL; 926 1.13 christos } 927 1.13 christos if (hostp != NULL) { 928 1.13 christos *hostp = host; 929 1.13 christos host = NULL; 930 1.13 christos } 931 1.13 christos if (portp != NULL) 932 1.13 christos *portp = port; 933 1.13 christos ret = 0; 934 1.13 christos out: 935 1.13 christos free(sdup); 936 1.13 christos free(user); 937 1.13 christos free(host); 938 1.13 christos return ret; 939 1.13 christos } 940 1.13 christos 941 1.17 christos /* 942 1.17 christos * Converts a two-byte hex string to decimal. 943 1.17 christos * Returns the decimal value or -1 for invalid input. 944 1.17 christos */ 945 1.17 christos static int 946 1.17 christos hexchar(const char *s) 947 1.17 christos { 948 1.17 christos unsigned char result[2]; 949 1.17 christos int i; 950 1.17 christos 951 1.17 christos for (i = 0; i < 2; i++) { 952 1.17 christos if (s[i] >= '0' && s[i] <= '9') 953 1.17 christos result[i] = (unsigned char)(s[i] - '0'); 954 1.17 christos else if (s[i] >= 'a' && s[i] <= 'f') 955 1.17 christos result[i] = (unsigned char)(s[i] - 'a') + 10; 956 1.17 christos else if (s[i] >= 'A' && s[i] <= 'F') 957 1.17 christos result[i] = (unsigned char)(s[i] - 'A') + 10; 958 1.17 christos else 959 1.17 christos return -1; 960 1.17 christos } 961 1.17 christos return (result[0] << 4) | result[1]; 962 1.17 christos } 963 1.17 christos 964 1.17 christos /* 965 1.17 christos * Decode an url-encoded string. 966 1.17 christos * Returns a newly allocated string on success or NULL on failure. 967 1.17 christos */ 968 1.17 christos static char * 969 1.17 christos urldecode(const char *src) 970 1.17 christos { 971 1.17 christos char *ret, *dst; 972 1.17 christos int ch; 973 1.34 christos size_t srclen; 974 1.17 christos 975 1.34 christos if ((srclen = strlen(src)) >= SIZE_MAX) 976 1.40 christos return NULL; 977 1.34 christos ret = xmalloc(srclen + 1); 978 1.17 christos for (dst = ret; *src != '\0'; src++) { 979 1.17 christos switch (*src) { 980 1.17 christos case '+': 981 1.17 christos *dst++ = ' '; 982 1.17 christos break; 983 1.17 christos case '%': 984 1.40 christos /* note: don't allow \0 characters */ 985 1.17 christos if (!isxdigit((unsigned char)src[1]) || 986 1.17 christos !isxdigit((unsigned char)src[2]) || 987 1.40 christos (ch = hexchar(src + 1)) == -1 || ch == 0) { 988 1.17 christos free(ret); 989 1.17 christos return NULL; 990 1.17 christos } 991 1.17 christos *dst++ = ch; 992 1.17 christos src += 2; 993 1.17 christos break; 994 1.17 christos default: 995 1.17 christos *dst++ = *src; 996 1.17 christos break; 997 1.17 christos } 998 1.17 christos } 999 1.17 christos *dst = '\0'; 1000 1.17 christos 1001 1.17 christos return ret; 1002 1.17 christos } 1003 1.17 christos 1004 1.17 christos /* 1005 1.17 christos * Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI. 1006 1.17 christos * See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04 1007 1.17 christos * Either user or path may be url-encoded (but not host or port). 1008 1.17 christos * Caller must free returned user, host and path. 1009 1.17 christos * Any of the pointer return arguments may be NULL (useful for syntax checking) 1010 1.17 christos * but the scheme must always be specified. 1011 1.17 christos * If user was not specified then *userp will be set to NULL. 1012 1.17 christos * If port was not specified then *portp will be -1. 1013 1.17 christos * If path was not specified then *pathp will be set to NULL. 1014 1.17 christos * Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri. 1015 1.17 christos */ 1016 1.17 christos int 1017 1.17 christos parse_uri(const char *scheme, const char *uri, char **userp, char **hostp, 1018 1.25 christos int *portp, char **pathp) 1019 1.17 christos { 1020 1.17 christos char *uridup, *cp, *tmp, ch; 1021 1.17 christos char *user = NULL, *host = NULL, *path = NULL; 1022 1.17 christos int port = -1, ret = -1; 1023 1.17 christos size_t len; 1024 1.17 christos 1025 1.17 christos len = strlen(scheme); 1026 1.17 christos if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0) 1027 1.17 christos return 1; 1028 1.17 christos uri += len + 3; 1029 1.17 christos 1030 1.17 christos if (userp != NULL) 1031 1.17 christos *userp = NULL; 1032 1.17 christos if (hostp != NULL) 1033 1.17 christos *hostp = NULL; 1034 1.17 christos if (portp != NULL) 1035 1.17 christos *portp = -1; 1036 1.17 christos if (pathp != NULL) 1037 1.17 christos *pathp = NULL; 1038 1.17 christos 1039 1.17 christos uridup = tmp = xstrdup(uri); 1040 1.17 christos 1041 1.17 christos /* Extract optional ssh-info (username + connection params) */ 1042 1.17 christos if ((cp = strchr(tmp, '@')) != NULL) { 1043 1.17 christos char *delim; 1044 1.17 christos 1045 1.17 christos *cp = '\0'; 1046 1.17 christos /* Extract username and connection params */ 1047 1.17 christos if ((delim = strchr(tmp, ';')) != NULL) { 1048 1.17 christos /* Just ignore connection params for now */ 1049 1.17 christos *delim = '\0'; 1050 1.17 christos } 1051 1.17 christos if (*tmp == '\0') { 1052 1.17 christos /* Empty username */ 1053 1.17 christos goto out; 1054 1.17 christos } 1055 1.17 christos if ((user = urldecode(tmp)) == NULL) 1056 1.17 christos goto out; 1057 1.17 christos tmp = cp + 1; 1058 1.17 christos } 1059 1.17 christos 1060 1.17 christos /* Extract mandatory hostname */ 1061 1.17 christos if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0') 1062 1.17 christos goto out; 1063 1.17 christos host = xstrdup(cleanhostname(cp)); 1064 1.17 christos if (!valid_domain(host, 0, NULL)) 1065 1.17 christos goto out; 1066 1.17 christos 1067 1.17 christos if (tmp != NULL && *tmp != '\0') { 1068 1.17 christos if (ch == ':') { 1069 1.17 christos /* Convert and verify port. */ 1070 1.17 christos if ((cp = strchr(tmp, '/')) != NULL) 1071 1.17 christos *cp = '\0'; 1072 1.17 christos if ((port = a2port(tmp)) <= 0) 1073 1.17 christos goto out; 1074 1.17 christos tmp = cp ? cp + 1 : NULL; 1075 1.17 christos } 1076 1.17 christos if (tmp != NULL && *tmp != '\0') { 1077 1.17 christos /* Extract optional path */ 1078 1.17 christos if ((path = urldecode(tmp)) == NULL) 1079 1.17 christos goto out; 1080 1.17 christos } 1081 1.17 christos } 1082 1.17 christos 1083 1.17 christos /* Success */ 1084 1.17 christos if (userp != NULL) { 1085 1.17 christos *userp = user; 1086 1.17 christos user = NULL; 1087 1.17 christos } 1088 1.17 christos if (hostp != NULL) { 1089 1.17 christos *hostp = host; 1090 1.17 christos host = NULL; 1091 1.17 christos } 1092 1.17 christos if (portp != NULL) 1093 1.17 christos *portp = port; 1094 1.17 christos if (pathp != NULL) { 1095 1.17 christos *pathp = path; 1096 1.17 christos path = NULL; 1097 1.17 christos } 1098 1.17 christos ret = 0; 1099 1.17 christos out: 1100 1.17 christos free(uridup); 1101 1.17 christos free(user); 1102 1.17 christos free(host); 1103 1.17 christos free(path); 1104 1.17 christos return ret; 1105 1.17 christos } 1106 1.17 christos 1107 1.1 christos /* function to assist building execv() arguments */ 1108 1.1 christos void 1109 1.5 christos addargs(arglist *args, const char *fmt, ...) 1110 1.1 christos { 1111 1.1 christos va_list ap; 1112 1.1 christos char *cp; 1113 1.1 christos u_int nalloc; 1114 1.1 christos int r; 1115 1.1 christos 1116 1.1 christos va_start(ap, fmt); 1117 1.1 christos r = vasprintf(&cp, fmt, ap); 1118 1.1 christos va_end(ap); 1119 1.1 christos if (r == -1) 1120 1.31 christos fatal_f("argument too long"); 1121 1.1 christos 1122 1.1 christos nalloc = args->nalloc; 1123 1.1 christos if (args->list == NULL) { 1124 1.1 christos nalloc = 32; 1125 1.1 christos args->num = 0; 1126 1.31 christos } else if (args->num > (256 * 1024)) 1127 1.31 christos fatal_f("too many arguments"); 1128 1.31 christos else if (args->num >= args->nalloc) 1129 1.31 christos fatal_f("arglist corrupt"); 1130 1.31 christos else if (args->num+2 >= nalloc) 1131 1.1 christos nalloc *= 2; 1132 1.1 christos 1133 1.31 christos args->list = xrecallocarray(args->list, args->nalloc, 1134 1.31 christos nalloc, sizeof(char *)); 1135 1.1 christos args->nalloc = nalloc; 1136 1.1 christos args->list[args->num++] = cp; 1137 1.1 christos args->list[args->num] = NULL; 1138 1.1 christos } 1139 1.1 christos 1140 1.1 christos void 1141 1.5 christos replacearg(arglist *args, u_int which, const char *fmt, ...) 1142 1.1 christos { 1143 1.1 christos va_list ap; 1144 1.1 christos char *cp; 1145 1.1 christos int r; 1146 1.1 christos 1147 1.1 christos va_start(ap, fmt); 1148 1.1 christos r = vasprintf(&cp, fmt, ap); 1149 1.1 christos va_end(ap); 1150 1.1 christos if (r == -1) 1151 1.31 christos fatal_f("argument too long"); 1152 1.31 christos if (args->list == NULL || args->num >= args->nalloc) 1153 1.31 christos fatal_f("arglist corrupt"); 1154 1.1 christos 1155 1.1 christos if (which >= args->num) 1156 1.31 christos fatal_f("tried to replace invalid arg %d >= %d", 1157 1.1 christos which, args->num); 1158 1.8 christos free(args->list[which]); 1159 1.1 christos args->list[which] = cp; 1160 1.1 christos } 1161 1.1 christos 1162 1.1 christos void 1163 1.1 christos freeargs(arglist *args) 1164 1.1 christos { 1165 1.1 christos u_int i; 1166 1.1 christos 1167 1.31 christos if (args == NULL) 1168 1.31 christos return; 1169 1.31 christos if (args->list != NULL && args->num < args->nalloc) { 1170 1.1 christos for (i = 0; i < args->num; i++) 1171 1.8 christos free(args->list[i]); 1172 1.8 christos free(args->list); 1173 1.1 christos } 1174 1.31 christos args->nalloc = args->num = 0; 1175 1.31 christos args->list = NULL; 1176 1.1 christos } 1177 1.1 christos 1178 1.1 christos /* 1179 1.1 christos * Expands tildes in the file name. Returns data allocated by xmalloc. 1180 1.1 christos * Warning: this calls getpw*. 1181 1.1 christos */ 1182 1.27 christos int 1183 1.27 christos tilde_expand(const char *filename, uid_t uid, char **retp) 1184 1.1 christos { 1185 1.29 christos char *ocopy = NULL, *copy, *s = NULL; 1186 1.29 christos const char *path = NULL, *user = NULL; 1187 1.1 christos struct passwd *pw; 1188 1.29 christos size_t len; 1189 1.30 christos int ret = -1, r, slash; 1190 1.1 christos 1191 1.29 christos *retp = NULL; 1192 1.27 christos if (*filename != '~') { 1193 1.27 christos *retp = xstrdup(filename); 1194 1.27 christos return 0; 1195 1.27 christos } 1196 1.29 christos ocopy = copy = xstrdup(filename + 1); 1197 1.1 christos 1198 1.29 christos if (*copy == '\0') /* ~ */ 1199 1.29 christos path = NULL; 1200 1.29 christos else if (*copy == '/') { 1201 1.29 christos copy += strspn(copy, "/"); 1202 1.29 christos if (*copy == '\0') 1203 1.29 christos path = NULL; /* ~/ */ 1204 1.29 christos else 1205 1.29 christos path = copy; /* ~/path */ 1206 1.29 christos } else { 1207 1.29 christos user = copy; 1208 1.29 christos if ((path = strchr(copy, '/')) != NULL) { 1209 1.29 christos copy[path - copy] = '\0'; 1210 1.29 christos path++; 1211 1.29 christos path += strspn(path, "/"); 1212 1.29 christos if (*path == '\0') /* ~user/ */ 1213 1.29 christos path = NULL; 1214 1.29 christos /* else ~user/path */ 1215 1.27 christos } 1216 1.29 christos /* else ~user */ 1217 1.29 christos } 1218 1.29 christos if (user != NULL) { 1219 1.27 christos if ((pw = getpwnam(user)) == NULL) { 1220 1.27 christos error_f("No such user %s", user); 1221 1.29 christos goto out; 1222 1.27 christos } 1223 1.30 christos } else if ((pw = getpwuid(uid)) == NULL) { 1224 1.30 christos error_f("No such uid %ld", (long)uid); 1225 1.30 christos goto out; 1226 1.2 christos } 1227 1.1 christos 1228 1.1 christos /* Make sure directory has a trailing '/' */ 1229 1.30 christos slash = (len = strlen(pw->pw_dir)) == 0 || pw->pw_dir[len - 1] != '/'; 1230 1.8 christos 1231 1.30 christos if ((r = xasprintf(&s, "%s%s%s", pw->pw_dir, 1232 1.30 christos slash ? "/" : "", path != NULL ? path : "")) <= 0) { 1233 1.29 christos error_f("xasprintf failed"); 1234 1.29 christos goto out; 1235 1.29 christos } 1236 1.29 christos if (r >= PATH_MAX) { 1237 1.27 christos error_f("Path too long"); 1238 1.29 christos goto out; 1239 1.27 christos } 1240 1.29 christos /* success */ 1241 1.29 christos ret = 0; 1242 1.29 christos *retp = s; 1243 1.29 christos s = NULL; 1244 1.29 christos out: 1245 1.29 christos free(s); 1246 1.29 christos free(ocopy); 1247 1.29 christos return ret; 1248 1.27 christos } 1249 1.27 christos 1250 1.27 christos char * 1251 1.27 christos tilde_expand_filename(const char *filename, uid_t uid) 1252 1.27 christos { 1253 1.27 christos char *ret; 1254 1.27 christos 1255 1.27 christos if (tilde_expand(filename, uid, &ret) != 0) 1256 1.27 christos cleanup_exit(255); 1257 1.27 christos return ret; 1258 1.1 christos } 1259 1.1 christos 1260 1.1 christos /* 1261 1.24 christos * Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT} 1262 1.24 christos * substitutions. A number of escapes may be specified as 1263 1.24 christos * (char *escape_chars, char *replacement) pairs. The list must be terminated 1264 1.24 christos * by a NULL escape_char. Returns replaced string in memory allocated by 1265 1.24 christos * xmalloc which the caller must free. 1266 1.1 christos */ 1267 1.24 christos static char * 1268 1.24 christos vdollar_percent_expand(int *parseerror, int dollar, int percent, 1269 1.24 christos const char *string, va_list ap) 1270 1.1 christos { 1271 1.35 christos #define EXPAND_MAX_KEYS 64 1272 1.24 christos u_int num_keys = 0, i; 1273 1.1 christos struct { 1274 1.1 christos const char *key; 1275 1.1 christos const char *repl; 1276 1.1 christos } keys[EXPAND_MAX_KEYS]; 1277 1.21 christos struct sshbuf *buf; 1278 1.24 christos int r, missingvar = 0; 1279 1.24 christos char *ret = NULL, *var, *varend, *val; 1280 1.24 christos size_t len; 1281 1.21 christos 1282 1.21 christos if ((buf = sshbuf_new()) == NULL) 1283 1.25 christos fatal_f("sshbuf_new failed"); 1284 1.24 christos if (parseerror == NULL) 1285 1.25 christos fatal_f("null parseerror arg"); 1286 1.24 christos *parseerror = 1; 1287 1.24 christos 1288 1.24 christos /* Gather keys if we're doing percent expansion. */ 1289 1.24 christos if (percent) { 1290 1.24 christos for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 1291 1.24 christos keys[num_keys].key = va_arg(ap, char *); 1292 1.24 christos if (keys[num_keys].key == NULL) 1293 1.24 christos break; 1294 1.24 christos keys[num_keys].repl = va_arg(ap, char *); 1295 1.25 christos if (keys[num_keys].repl == NULL) { 1296 1.25 christos fatal_f("NULL replacement for token %s", 1297 1.25 christos keys[num_keys].key); 1298 1.25 christos } 1299 1.24 christos } 1300 1.24 christos if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) 1301 1.25 christos fatal_f("too many keys"); 1302 1.24 christos if (num_keys == 0) 1303 1.25 christos fatal_f("percent expansion without token list"); 1304 1.1 christos } 1305 1.1 christos 1306 1.1 christos /* Expand string */ 1307 1.1 christos for (i = 0; *string != '\0'; string++) { 1308 1.24 christos /* Optionally process ${ENVIRONMENT} expansions. */ 1309 1.24 christos if (dollar && string[0] == '$' && string[1] == '{') { 1310 1.24 christos string += 2; /* skip over '${' */ 1311 1.24 christos if ((varend = strchr(string, '}')) == NULL) { 1312 1.25 christos error_f("environment variable '%s' missing " 1313 1.26 christos "closing '}'", string); 1314 1.24 christos goto out; 1315 1.24 christos } 1316 1.24 christos len = varend - string; 1317 1.24 christos if (len == 0) { 1318 1.25 christos error_f("zero-length environment variable"); 1319 1.24 christos goto out; 1320 1.24 christos } 1321 1.24 christos var = xmalloc(len + 1); 1322 1.24 christos (void)strlcpy(var, string, len + 1); 1323 1.24 christos if ((val = getenv(var)) == NULL) { 1324 1.25 christos error_f("env var ${%s} has no value", var); 1325 1.24 christos missingvar = 1; 1326 1.24 christos } else { 1327 1.25 christos debug3_f("expand ${%s} -> '%s'", var, val); 1328 1.24 christos if ((r = sshbuf_put(buf, val, strlen(val))) !=0) 1329 1.25 christos fatal_fr(r, "sshbuf_put ${}"); 1330 1.24 christos } 1331 1.24 christos free(var); 1332 1.24 christos string += len; 1333 1.24 christos continue; 1334 1.24 christos } 1335 1.24 christos 1336 1.24 christos /* 1337 1.24 christos * Process percent expansions if we have a list of TOKENs. 1338 1.24 christos * If we're not doing percent expansion everything just gets 1339 1.24 christos * appended here. 1340 1.24 christos */ 1341 1.24 christos if (*string != '%' || !percent) { 1342 1.1 christos append: 1343 1.25 christos if ((r = sshbuf_put_u8(buf, *string)) != 0) 1344 1.25 christos fatal_fr(r, "sshbuf_put_u8 %%"); 1345 1.1 christos continue; 1346 1.1 christos } 1347 1.1 christos string++; 1348 1.4 adam /* %% case */ 1349 1.1 christos if (*string == '%') 1350 1.1 christos goto append; 1351 1.24 christos if (*string == '\0') { 1352 1.25 christos error_f("invalid format"); 1353 1.24 christos goto out; 1354 1.24 christos } 1355 1.21 christos for (i = 0; i < num_keys; i++) { 1356 1.21 christos if (strchr(keys[i].key, *string) != NULL) { 1357 1.21 christos if ((r = sshbuf_put(buf, keys[i].repl, 1358 1.25 christos strlen(keys[i].repl))) != 0) 1359 1.25 christos fatal_fr(r, "sshbuf_put %%-repl"); 1360 1.1 christos break; 1361 1.1 christos } 1362 1.1 christos } 1363 1.24 christos if (i >= num_keys) { 1364 1.25 christos error_f("unknown key %%%c", *string); 1365 1.24 christos goto out; 1366 1.24 christos } 1367 1.1 christos } 1368 1.24 christos if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL) 1369 1.25 christos fatal_f("sshbuf_dup_string failed"); 1370 1.24 christos *parseerror = 0; 1371 1.24 christos out: 1372 1.21 christos sshbuf_free(buf); 1373 1.24 christos return *parseerror ? NULL : ret; 1374 1.24 christos #undef EXPAND_MAX_KEYS 1375 1.24 christos } 1376 1.24 christos 1377 1.24 christos /* 1378 1.24 christos * Expand only environment variables. 1379 1.24 christos * Note that although this function is variadic like the other similar 1380 1.24 christos * functions, any such arguments will be unused. 1381 1.24 christos */ 1382 1.24 christos 1383 1.24 christos char * 1384 1.24 christos dollar_expand(int *parseerr, const char *string, ...) 1385 1.24 christos { 1386 1.24 christos char *ret; 1387 1.24 christos int err; 1388 1.24 christos va_list ap; 1389 1.24 christos 1390 1.24 christos va_start(ap, string); 1391 1.24 christos ret = vdollar_percent_expand(&err, 1, 0, string, ap); 1392 1.24 christos va_end(ap); 1393 1.24 christos if (parseerr != NULL) 1394 1.24 christos *parseerr = err; 1395 1.24 christos return ret; 1396 1.24 christos } 1397 1.24 christos 1398 1.24 christos /* 1399 1.24 christos * Returns expanded string or NULL if a specified environment variable is 1400 1.24 christos * not defined, or calls fatal if the string is invalid. 1401 1.24 christos */ 1402 1.24 christos char * 1403 1.24 christos percent_expand(const char *string, ...) 1404 1.24 christos { 1405 1.24 christos char *ret; 1406 1.24 christos int err; 1407 1.24 christos va_list ap; 1408 1.24 christos 1409 1.24 christos va_start(ap, string); 1410 1.24 christos ret = vdollar_percent_expand(&err, 0, 1, string, ap); 1411 1.24 christos va_end(ap); 1412 1.24 christos if (err) 1413 1.25 christos fatal_f("failed"); 1414 1.24 christos return ret; 1415 1.24 christos } 1416 1.24 christos 1417 1.24 christos /* 1418 1.24 christos * Returns expanded string or NULL if a specified environment variable is 1419 1.24 christos * not defined, or calls fatal if the string is invalid. 1420 1.24 christos */ 1421 1.24 christos char * 1422 1.24 christos percent_dollar_expand(const char *string, ...) 1423 1.24 christos { 1424 1.24 christos char *ret; 1425 1.24 christos int err; 1426 1.24 christos va_list ap; 1427 1.24 christos 1428 1.24 christos va_start(ap, string); 1429 1.24 christos ret = vdollar_percent_expand(&err, 1, 1, string, ap); 1430 1.24 christos va_end(ap); 1431 1.24 christos if (err) 1432 1.25 christos fatal_f("failed"); 1433 1.21 christos return ret; 1434 1.1 christos } 1435 1.1 christos 1436 1.1 christos int 1437 1.17 christos tun_open(int tun, int mode, char **ifname) 1438 1.1 christos { 1439 1.1 christos struct ifreq ifr; 1440 1.12 christos char name[100]; 1441 1.12 christos int fd = -1, sock; 1442 1.12 christos const char *tunbase = "tun"; 1443 1.12 christos 1444 1.17 christos if (ifname != NULL) 1445 1.17 christos *ifname = NULL; 1446 1.17 christos 1447 1.12 christos if (mode == SSH_TUNMODE_ETHERNET) 1448 1.12 christos tunbase = "tap"; 1449 1.1 christos 1450 1.1 christos /* Open the tunnel device */ 1451 1.1 christos if (tun <= SSH_TUNID_MAX) { 1452 1.12 christos snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 1453 1.12 christos fd = open(name, O_RDWR); 1454 1.1 christos } else if (tun == SSH_TUNID_ANY) { 1455 1.1 christos for (tun = 100; tun >= 0; tun--) { 1456 1.12 christos snprintf(name, sizeof(name), "/dev/%s%d", 1457 1.12 christos tunbase, tun); 1458 1.12 christos if ((fd = open(name, O_RDWR)) >= 0) 1459 1.1 christos break; 1460 1.1 christos } 1461 1.1 christos } else { 1462 1.25 christos debug_f("invalid tunnel %u", tun); 1463 1.12 christos return -1; 1464 1.1 christos } 1465 1.1 christos 1466 1.21 christos if (fd == -1) { 1467 1.25 christos debug_f("%s open: %s", name, strerror(errno)); 1468 1.12 christos return -1; 1469 1.1 christos } 1470 1.1 christos 1471 1.25 christos debug_f("%s mode %d fd %d", name, mode, fd); 1472 1.1 christos 1473 1.12 christos #ifdef TUNSIFHEAD 1474 1.2 christos /* Turn on tunnel headers */ 1475 1.12 christos int flag = 1; 1476 1.2 christos if (mode != SSH_TUNMODE_ETHERNET && 1477 1.2 christos ioctl(fd, TUNSIFHEAD, &flag) == -1) { 1478 1.2 christos debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd, 1479 1.2 christos strerror(errno)); 1480 1.2 christos close(fd); 1481 1.2 christos return -1; 1482 1.2 christos } 1483 1.12 christos #endif 1484 1.2 christos 1485 1.2 christos debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); 1486 1.12 christos /* Bring interface up if it is not already */ 1487 1.3 jnemeth snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 1488 1.1 christos if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 1489 1.1 christos goto failed; 1490 1.1 christos 1491 1.12 christos if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { 1492 1.25 christos debug_f("get interface %s flags: %s", ifr.ifr_name, 1493 1.25 christos strerror(errno)); 1494 1.1 christos goto failed; 1495 1.12 christos } 1496 1.1 christos 1497 1.12 christos if (!(ifr.ifr_flags & IFF_UP)) { 1498 1.12 christos ifr.ifr_flags |= IFF_UP; 1499 1.12 christos if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) { 1500 1.25 christos debug_f("activate interface %s: %s", ifr.ifr_name, 1501 1.25 christos strerror(errno)); 1502 1.12 christos goto failed; 1503 1.12 christos } 1504 1.12 christos } 1505 1.1 christos 1506 1.17 christos if (ifname != NULL) 1507 1.17 christos *ifname = xstrdup(ifr.ifr_name); 1508 1.17 christos 1509 1.1 christos close(sock); 1510 1.12 christos return fd; 1511 1.1 christos 1512 1.1 christos failed: 1513 1.1 christos if (fd >= 0) 1514 1.1 christos close(fd); 1515 1.1 christos if (sock >= 0) 1516 1.1 christos close(sock); 1517 1.2 christos debug("%s: failed to set %s mode %d: %s", __func__, ifr.ifr_name, 1518 1.1 christos mode, strerror(errno)); 1519 1.12 christos return -1; 1520 1.1 christos } 1521 1.1 christos 1522 1.1 christos void 1523 1.1 christos sanitise_stdfd(void) 1524 1.1 christos { 1525 1.1 christos int nullfd, dupfd; 1526 1.1 christos 1527 1.1 christos if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 1528 1.1 christos fprintf(stderr, "Couldn't open /dev/null: %s\n", 1529 1.1 christos strerror(errno)); 1530 1.1 christos exit(1); 1531 1.1 christos } 1532 1.13 christos while (++dupfd <= STDERR_FILENO) { 1533 1.13 christos /* Only populate closed fds. */ 1534 1.13 christos if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) { 1535 1.13 christos if (dup2(nullfd, dupfd) == -1) { 1536 1.13 christos fprintf(stderr, "dup2: %s\n", strerror(errno)); 1537 1.13 christos exit(1); 1538 1.13 christos } 1539 1.1 christos } 1540 1.1 christos } 1541 1.13 christos if (nullfd > STDERR_FILENO) 1542 1.1 christos close(nullfd); 1543 1.1 christos } 1544 1.1 christos 1545 1.1 christos char * 1546 1.1 christos tohex(const void *vp, size_t l) 1547 1.1 christos { 1548 1.1 christos const u_char *p = (const u_char *)vp; 1549 1.1 christos char b[3], *r; 1550 1.1 christos size_t i, hl; 1551 1.1 christos 1552 1.1 christos if (l > 65536) 1553 1.1 christos return xstrdup("tohex: length > 65536"); 1554 1.1 christos 1555 1.1 christos hl = l * 2 + 1; 1556 1.1 christos r = xcalloc(1, hl); 1557 1.1 christos for (i = 0; i < l; i++) { 1558 1.1 christos snprintf(b, sizeof(b), "%02x", p[i]); 1559 1.1 christos strlcat(r, b, hl); 1560 1.1 christos } 1561 1.1 christos return (r); 1562 1.1 christos } 1563 1.1 christos 1564 1.22 christos /* 1565 1.22 christos * Extend string *sp by the specified format. If *sp is not NULL (or empty), 1566 1.22 christos * then the separator 'sep' will be prepended before the formatted arguments. 1567 1.22 christos * Extended strings are heap allocated. 1568 1.22 christos */ 1569 1.22 christos void 1570 1.22 christos xextendf(char **sp, const char *sep, const char *fmt, ...) 1571 1.22 christos { 1572 1.22 christos va_list ap; 1573 1.22 christos char *tmp1, *tmp2; 1574 1.22 christos 1575 1.22 christos va_start(ap, fmt); 1576 1.22 christos xvasprintf(&tmp1, fmt, ap); 1577 1.22 christos va_end(ap); 1578 1.22 christos 1579 1.22 christos if (*sp == NULL || **sp == '\0') { 1580 1.22 christos free(*sp); 1581 1.22 christos *sp = tmp1; 1582 1.22 christos return; 1583 1.22 christos } 1584 1.22 christos xasprintf(&tmp2, "%s%s%s", *sp, sep == NULL ? "" : sep, tmp1); 1585 1.22 christos free(tmp1); 1586 1.22 christos free(*sp); 1587 1.22 christos *sp = tmp2; 1588 1.22 christos } 1589 1.22 christos 1590 1.22 christos 1591 1.1 christos u_int64_t 1592 1.1 christos get_u64(const void *vp) 1593 1.1 christos { 1594 1.1 christos const u_char *p = (const u_char *)vp; 1595 1.1 christos u_int64_t v; 1596 1.1 christos 1597 1.1 christos v = (u_int64_t)p[0] << 56; 1598 1.1 christos v |= (u_int64_t)p[1] << 48; 1599 1.1 christos v |= (u_int64_t)p[2] << 40; 1600 1.1 christos v |= (u_int64_t)p[3] << 32; 1601 1.1 christos v |= (u_int64_t)p[4] << 24; 1602 1.1 christos v |= (u_int64_t)p[5] << 16; 1603 1.1 christos v |= (u_int64_t)p[6] << 8; 1604 1.1 christos v |= (u_int64_t)p[7]; 1605 1.1 christos 1606 1.1 christos return (v); 1607 1.1 christos } 1608 1.1 christos 1609 1.1 christos u_int32_t 1610 1.1 christos get_u32(const void *vp) 1611 1.1 christos { 1612 1.1 christos const u_char *p = (const u_char *)vp; 1613 1.1 christos u_int32_t v; 1614 1.1 christos 1615 1.1 christos v = (u_int32_t)p[0] << 24; 1616 1.1 christos v |= (u_int32_t)p[1] << 16; 1617 1.1 christos v |= (u_int32_t)p[2] << 8; 1618 1.1 christos v |= (u_int32_t)p[3]; 1619 1.1 christos 1620 1.1 christos return (v); 1621 1.1 christos } 1622 1.1 christos 1623 1.9 christos u_int32_t 1624 1.9 christos get_u32_le(const void *vp) 1625 1.9 christos { 1626 1.9 christos const u_char *p = (const u_char *)vp; 1627 1.9 christos u_int32_t v; 1628 1.9 christos 1629 1.9 christos v = (u_int32_t)p[0]; 1630 1.9 christos v |= (u_int32_t)p[1] << 8; 1631 1.9 christos v |= (u_int32_t)p[2] << 16; 1632 1.9 christos v |= (u_int32_t)p[3] << 24; 1633 1.9 christos 1634 1.9 christos return (v); 1635 1.9 christos } 1636 1.9 christos 1637 1.1 christos u_int16_t 1638 1.1 christos get_u16(const void *vp) 1639 1.1 christos { 1640 1.1 christos const u_char *p = (const u_char *)vp; 1641 1.1 christos u_int16_t v; 1642 1.1 christos 1643 1.1 christos v = (u_int16_t)p[0] << 8; 1644 1.1 christos v |= (u_int16_t)p[1]; 1645 1.1 christos 1646 1.1 christos return (v); 1647 1.1 christos } 1648 1.1 christos 1649 1.1 christos void 1650 1.1 christos put_u64(void *vp, u_int64_t v) 1651 1.1 christos { 1652 1.1 christos u_char *p = (u_char *)vp; 1653 1.1 christos 1654 1.1 christos p[0] = (u_char)(v >> 56) & 0xff; 1655 1.1 christos p[1] = (u_char)(v >> 48) & 0xff; 1656 1.1 christos p[2] = (u_char)(v >> 40) & 0xff; 1657 1.1 christos p[3] = (u_char)(v >> 32) & 0xff; 1658 1.1 christos p[4] = (u_char)(v >> 24) & 0xff; 1659 1.1 christos p[5] = (u_char)(v >> 16) & 0xff; 1660 1.1 christos p[6] = (u_char)(v >> 8) & 0xff; 1661 1.1 christos p[7] = (u_char)v & 0xff; 1662 1.1 christos } 1663 1.1 christos 1664 1.1 christos void 1665 1.1 christos put_u32(void *vp, u_int32_t v) 1666 1.1 christos { 1667 1.1 christos u_char *p = (u_char *)vp; 1668 1.1 christos 1669 1.1 christos p[0] = (u_char)(v >> 24) & 0xff; 1670 1.1 christos p[1] = (u_char)(v >> 16) & 0xff; 1671 1.1 christos p[2] = (u_char)(v >> 8) & 0xff; 1672 1.1 christos p[3] = (u_char)v & 0xff; 1673 1.1 christos } 1674 1.1 christos 1675 1.9 christos void 1676 1.9 christos put_u32_le(void *vp, u_int32_t v) 1677 1.9 christos { 1678 1.9 christos u_char *p = (u_char *)vp; 1679 1.9 christos 1680 1.9 christos p[0] = (u_char)v & 0xff; 1681 1.9 christos p[1] = (u_char)(v >> 8) & 0xff; 1682 1.9 christos p[2] = (u_char)(v >> 16) & 0xff; 1683 1.9 christos p[3] = (u_char)(v >> 24) & 0xff; 1684 1.9 christos } 1685 1.1 christos 1686 1.1 christos void 1687 1.1 christos put_u16(void *vp, u_int16_t v) 1688 1.1 christos { 1689 1.1 christos u_char *p = (u_char *)vp; 1690 1.1 christos 1691 1.1 christos p[0] = (u_char)(v >> 8) & 0xff; 1692 1.1 christos p[1] = (u_char)v & 0xff; 1693 1.1 christos } 1694 1.1 christos 1695 1.1 christos void 1696 1.1 christos ms_subtract_diff(struct timeval *start, int *ms) 1697 1.1 christos { 1698 1.1 christos struct timeval diff, finish; 1699 1.1 christos 1700 1.17 christos monotime_tv(&finish); 1701 1.17 christos timersub(&finish, start, &diff); 1702 1.1 christos *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); 1703 1.1 christos } 1704 1.1 christos 1705 1.1 christos void 1706 1.29 christos ms_to_timespec(struct timespec *ts, int ms) 1707 1.1 christos { 1708 1.1 christos if (ms < 0) 1709 1.1 christos ms = 0; 1710 1.29 christos ts->tv_sec = ms / 1000; 1711 1.29 christos ts->tv_nsec = (ms % 1000) * 1000 * 1000; 1712 1.1 christos } 1713 1.1 christos 1714 1.17 christos void 1715 1.17 christos monotime_ts(struct timespec *ts) 1716 1.17 christos { 1717 1.17 christos if (clock_gettime(CLOCK_MONOTONIC, ts) != 0) 1718 1.17 christos fatal("clock_gettime: %s", strerror(errno)); 1719 1.17 christos } 1720 1.17 christos 1721 1.17 christos void 1722 1.17 christos monotime_tv(struct timeval *tv) 1723 1.17 christos { 1724 1.17 christos struct timespec ts; 1725 1.17 christos 1726 1.17 christos monotime_ts(&ts); 1727 1.17 christos tv->tv_sec = ts.tv_sec; 1728 1.17 christos tv->tv_usec = ts.tv_nsec / 1000; 1729 1.17 christos } 1730 1.17 christos 1731 1.8 christos time_t 1732 1.8 christos monotime(void) 1733 1.8 christos { 1734 1.8 christos struct timespec ts; 1735 1.8 christos 1736 1.17 christos monotime_ts(&ts); 1737 1.8 christos return (ts.tv_sec); 1738 1.8 christos } 1739 1.8 christos 1740 1.13 christos double 1741 1.13 christos monotime_double(void) 1742 1.13 christos { 1743 1.13 christos struct timespec ts; 1744 1.13 christos 1745 1.17 christos monotime_ts(&ts); 1746 1.17 christos return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; 1747 1.13 christos } 1748 1.13 christos 1749 1.5 christos void 1750 1.5 christos bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen) 1751 1.5 christos { 1752 1.5 christos bw->buflen = buflen; 1753 1.5 christos bw->rate = kbps; 1754 1.20 christos bw->thresh = buflen; 1755 1.5 christos bw->lamt = 0; 1756 1.5 christos timerclear(&bw->bwstart); 1757 1.5 christos timerclear(&bw->bwend); 1758 1.20 christos } 1759 1.5 christos 1760 1.5 christos /* Callback from read/write loop to insert bandwidth-limiting delays */ 1761 1.5 christos void 1762 1.5 christos bandwidth_limit(struct bwlimit *bw, size_t read_len) 1763 1.5 christos { 1764 1.5 christos u_int64_t waitlen; 1765 1.5 christos struct timespec ts, rm; 1766 1.5 christos 1767 1.20 christos bw->lamt += read_len; 1768 1.5 christos if (!timerisset(&bw->bwstart)) { 1769 1.17 christos monotime_tv(&bw->bwstart); 1770 1.5 christos return; 1771 1.5 christos } 1772 1.5 christos if (bw->lamt < bw->thresh) 1773 1.5 christos return; 1774 1.5 christos 1775 1.17 christos monotime_tv(&bw->bwend); 1776 1.5 christos timersub(&bw->bwend, &bw->bwstart, &bw->bwend); 1777 1.5 christos if (!timerisset(&bw->bwend)) 1778 1.5 christos return; 1779 1.5 christos 1780 1.5 christos bw->lamt *= 8; 1781 1.5 christos waitlen = (double)1000000L * bw->lamt / bw->rate; 1782 1.5 christos 1783 1.5 christos bw->bwstart.tv_sec = waitlen / 1000000L; 1784 1.5 christos bw->bwstart.tv_usec = waitlen % 1000000L; 1785 1.5 christos 1786 1.5 christos if (timercmp(&bw->bwstart, &bw->bwend, >)) { 1787 1.5 christos timersub(&bw->bwstart, &bw->bwend, &bw->bwend); 1788 1.5 christos 1789 1.5 christos /* Adjust the wait time */ 1790 1.5 christos if (bw->bwend.tv_sec) { 1791 1.5 christos bw->thresh /= 2; 1792 1.5 christos if (bw->thresh < bw->buflen / 4) 1793 1.5 christos bw->thresh = bw->buflen / 4; 1794 1.5 christos } else if (bw->bwend.tv_usec < 10000) { 1795 1.5 christos bw->thresh *= 2; 1796 1.5 christos if (bw->thresh > bw->buflen * 8) 1797 1.5 christos bw->thresh = bw->buflen * 8; 1798 1.5 christos } 1799 1.5 christos 1800 1.5 christos TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts); 1801 1.5 christos while (nanosleep(&ts, &rm) == -1) { 1802 1.5 christos if (errno != EINTR) 1803 1.5 christos break; 1804 1.5 christos ts = rm; 1805 1.5 christos } 1806 1.5 christos } 1807 1.5 christos 1808 1.5 christos bw->lamt = 0; 1809 1.17 christos monotime_tv(&bw->bwstart); 1810 1.5 christos } 1811 1.5 christos 1812 1.5 christos /* Make a template filename for mk[sd]temp() */ 1813 1.5 christos void 1814 1.5 christos mktemp_proto(char *s, size_t len) 1815 1.5 christos { 1816 1.5 christos const char *tmpdir; 1817 1.5 christos int r; 1818 1.5 christos 1819 1.5 christos if ((tmpdir = getenv("TMPDIR")) != NULL) { 1820 1.5 christos r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir); 1821 1.5 christos if (r > 0 && (size_t)r < len) 1822 1.5 christos return; 1823 1.5 christos } 1824 1.5 christos r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); 1825 1.5 christos if (r < 0 || (size_t)r >= len) 1826 1.25 christos fatal_f("template string too short"); 1827 1.5 christos } 1828 1.5 christos 1829 1.5 christos static const struct { 1830 1.5 christos const char *name; 1831 1.5 christos int value; 1832 1.5 christos } ipqos[] = { 1833 1.16 christos { "none", INT_MAX }, /* can't use 0 here; that's CS0 */ 1834 1.5 christos { "af11", IPTOS_DSCP_AF11 }, 1835 1.5 christos { "af12", IPTOS_DSCP_AF12 }, 1836 1.5 christos { "af13", IPTOS_DSCP_AF13 }, 1837 1.7 christos { "af21", IPTOS_DSCP_AF21 }, 1838 1.5 christos { "af22", IPTOS_DSCP_AF22 }, 1839 1.5 christos { "af23", IPTOS_DSCP_AF23 }, 1840 1.5 christos { "af31", IPTOS_DSCP_AF31 }, 1841 1.5 christos { "af32", IPTOS_DSCP_AF32 }, 1842 1.5 christos { "af33", IPTOS_DSCP_AF33 }, 1843 1.5 christos { "af41", IPTOS_DSCP_AF41 }, 1844 1.5 christos { "af42", IPTOS_DSCP_AF42 }, 1845 1.5 christos { "af43", IPTOS_DSCP_AF43 }, 1846 1.5 christos { "cs0", IPTOS_DSCP_CS0 }, 1847 1.5 christos { "cs1", IPTOS_DSCP_CS1 }, 1848 1.5 christos { "cs2", IPTOS_DSCP_CS2 }, 1849 1.5 christos { "cs3", IPTOS_DSCP_CS3 }, 1850 1.5 christos { "cs4", IPTOS_DSCP_CS4 }, 1851 1.5 christos { "cs5", IPTOS_DSCP_CS5 }, 1852 1.5 christos { "cs6", IPTOS_DSCP_CS6 }, 1853 1.5 christos { "cs7", IPTOS_DSCP_CS7 }, 1854 1.5 christos { "ef", IPTOS_DSCP_EF }, 1855 1.22 christos #ifdef IPTOS_DSCP_LE 1856 1.22 christos { "le", IPTOS_DSCP_LE }, 1857 1.22 christos #endif 1858 1.40 christos { "lowdelay", INT_MIN }, /* deprecated */ 1859 1.40 christos { "throughput", INT_MIN }, /* deprecated */ 1860 1.40 christos { "reliability", INT_MIN }, /* deprecated */ 1861 1.5 christos { NULL, -1 } 1862 1.5 christos }; 1863 1.5 christos 1864 1.5 christos int 1865 1.5 christos parse_ipqos(const char *cp) 1866 1.5 christos { 1867 1.37 christos const char *errstr; 1868 1.5 christos u_int i; 1869 1.37 christos int val; 1870 1.5 christos 1871 1.5 christos if (cp == NULL) 1872 1.5 christos return -1; 1873 1.5 christos for (i = 0; ipqos[i].name != NULL; i++) { 1874 1.5 christos if (strcasecmp(cp, ipqos[i].name) == 0) 1875 1.5 christos return ipqos[i].value; 1876 1.5 christos } 1877 1.5 christos /* Try parsing as an integer */ 1878 1.37 christos val = (int)strtonum(cp, 0, 255, &errstr); 1879 1.37 christos if (errstr) 1880 1.5 christos return -1; 1881 1.5 christos return val; 1882 1.5 christos } 1883 1.5 christos 1884 1.6 christos const char * 1885 1.6 christos iptos2str(int iptos) 1886 1.6 christos { 1887 1.6 christos int i; 1888 1.6 christos static char iptos_str[sizeof "0xff"]; 1889 1.6 christos 1890 1.6 christos for (i = 0; ipqos[i].name != NULL; i++) { 1891 1.6 christos if (ipqos[i].value == iptos) 1892 1.6 christos return ipqos[i].name; 1893 1.6 christos } 1894 1.6 christos snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos); 1895 1.6 christos return iptos_str; 1896 1.6 christos } 1897 1.6 christos 1898 1.9 christos void 1899 1.9 christos lowercase(char *s) 1900 1.9 christos { 1901 1.9 christos for (; *s; s++) 1902 1.9 christos *s = tolower((u_char)*s); 1903 1.9 christos } 1904 1.9 christos 1905 1.4 adam int 1906 1.9 christos unix_listener(const char *path, int backlog, int unlink_first) 1907 1.4 adam { 1908 1.9 christos struct sockaddr_un sunaddr; 1909 1.9 christos int saved_errno, sock; 1910 1.4 adam 1911 1.9 christos memset(&sunaddr, 0, sizeof(sunaddr)); 1912 1.9 christos sunaddr.sun_family = AF_UNIX; 1913 1.17 christos if (strlcpy(sunaddr.sun_path, path, 1914 1.17 christos sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { 1915 1.25 christos error_f("path \"%s\" too long for Unix domain socket", path); 1916 1.9 christos errno = ENAMETOOLONG; 1917 1.9 christos return -1; 1918 1.9 christos } 1919 1.9 christos 1920 1.9 christos sock = socket(PF_UNIX, SOCK_STREAM, 0); 1921 1.21 christos if (sock == -1) { 1922 1.9 christos saved_errno = errno; 1923 1.25 christos error_f("socket: %.100s", strerror(errno)); 1924 1.9 christos errno = saved_errno; 1925 1.9 christos return -1; 1926 1.9 christos } 1927 1.9 christos if (unlink_first == 1) { 1928 1.9 christos if (unlink(path) != 0 && errno != ENOENT) 1929 1.9 christos error("unlink(%s): %.100s", path, strerror(errno)); 1930 1.9 christos } 1931 1.21 christos if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { 1932 1.9 christos saved_errno = errno; 1933 1.25 christos error_f("cannot bind to path %s: %s", path, strerror(errno)); 1934 1.9 christos close(sock); 1935 1.9 christos errno = saved_errno; 1936 1.9 christos return -1; 1937 1.9 christos } 1938 1.21 christos if (listen(sock, backlog) == -1) { 1939 1.9 christos saved_errno = errno; 1940 1.25 christos error_f("cannot listen on path %s: %s", path, strerror(errno)); 1941 1.9 christos close(sock); 1942 1.9 christos unlink(path); 1943 1.9 christos errno = saved_errno; 1944 1.9 christos return -1; 1945 1.9 christos } 1946 1.9 christos return sock; 1947 1.4 adam } 1948 1.13 christos 1949 1.13 christos /* 1950 1.13 christos * Compares two strings that maybe be NULL. Returns non-zero if strings 1951 1.13 christos * are both NULL or are identical, returns zero otherwise. 1952 1.13 christos */ 1953 1.13 christos static int 1954 1.13 christos strcmp_maybe_null(const char *a, const char *b) 1955 1.13 christos { 1956 1.13 christos if ((a == NULL && b != NULL) || (a != NULL && b == NULL)) 1957 1.13 christos return 0; 1958 1.13 christos if (a != NULL && strcmp(a, b) != 0) 1959 1.13 christos return 0; 1960 1.13 christos return 1; 1961 1.13 christos } 1962 1.13 christos 1963 1.13 christos /* 1964 1.13 christos * Compare two forwards, returning non-zero if they are identical or 1965 1.13 christos * zero otherwise. 1966 1.13 christos */ 1967 1.13 christos int 1968 1.13 christos forward_equals(const struct Forward *a, const struct Forward *b) 1969 1.13 christos { 1970 1.13 christos if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0) 1971 1.13 christos return 0; 1972 1.13 christos if (a->listen_port != b->listen_port) 1973 1.13 christos return 0; 1974 1.13 christos if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0) 1975 1.13 christos return 0; 1976 1.13 christos if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0) 1977 1.13 christos return 0; 1978 1.13 christos if (a->connect_port != b->connect_port) 1979 1.13 christos return 0; 1980 1.13 christos if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0) 1981 1.13 christos return 0; 1982 1.13 christos /* allocated_port and handle are not checked */ 1983 1.13 christos return 1; 1984 1.13 christos } 1985 1.13 christos 1986 1.37 christos /* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ 1987 1.37 christos int 1988 1.37 christos permitopen_port(const char *p) 1989 1.37 christos { 1990 1.37 christos int port; 1991 1.37 christos 1992 1.37 christos if (strcmp(p, "*") == 0) 1993 1.37 christos return FWD_PERMIT_ANY_PORT; 1994 1.37 christos if ((port = a2port(p)) > 0) 1995 1.37 christos return port; 1996 1.37 christos return -1; 1997 1.37 christos } 1998 1.37 christos 1999 1.14 christos /* returns 1 if process is already daemonized, 0 otherwise */ 2000 1.14 christos int 2001 1.14 christos daemonized(void) 2002 1.14 christos { 2003 1.14 christos int fd; 2004 1.14 christos 2005 1.14 christos if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) { 2006 1.14 christos close(fd); 2007 1.14 christos return 0; /* have controlling terminal */ 2008 1.14 christos } 2009 1.14 christos if (getppid() != 1) 2010 1.14 christos return 0; /* parent is not init */ 2011 1.14 christos if (getsid(0) != getpid()) 2012 1.14 christos return 0; /* not session leader */ 2013 1.14 christos debug3("already daemonized"); 2014 1.14 christos return 1; 2015 1.14 christos } 2016 1.16 christos 2017 1.16 christos /* 2018 1.16 christos * Splits 's' into an argument vector. Handles quoted string and basic 2019 1.16 christos * escape characters (\\, \", \'). Caller must free the argument vector 2020 1.16 christos * and its members. 2021 1.16 christos */ 2022 1.16 christos int 2023 1.27 christos argv_split(const char *s, int *argcp, char ***argvp, int terminate_on_comment) 2024 1.16 christos { 2025 1.16 christos int r = SSH_ERR_INTERNAL_ERROR; 2026 1.16 christos int argc = 0, quote, i, j; 2027 1.16 christos char *arg, **argv = xcalloc(1, sizeof(*argv)); 2028 1.16 christos 2029 1.16 christos *argvp = NULL; 2030 1.16 christos *argcp = 0; 2031 1.16 christos 2032 1.16 christos for (i = 0; s[i] != '\0'; i++) { 2033 1.16 christos /* Skip leading whitespace */ 2034 1.16 christos if (s[i] == ' ' || s[i] == '\t') 2035 1.16 christos continue; 2036 1.27 christos if (terminate_on_comment && s[i] == '#') 2037 1.27 christos break; 2038 1.16 christos /* Start of a token */ 2039 1.16 christos quote = 0; 2040 1.16 christos 2041 1.16 christos argv = xreallocarray(argv, (argc + 2), sizeof(*argv)); 2042 1.16 christos arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1); 2043 1.16 christos argv[argc] = NULL; 2044 1.16 christos 2045 1.16 christos /* Copy the token in, removing escapes */ 2046 1.16 christos for (j = 0; s[i] != '\0'; i++) { 2047 1.16 christos if (s[i] == '\\') { 2048 1.16 christos if (s[i + 1] == '\'' || 2049 1.16 christos s[i + 1] == '\"' || 2050 1.27 christos s[i + 1] == '\\' || 2051 1.27 christos (quote == 0 && s[i + 1] == ' ')) { 2052 1.16 christos i++; /* Skip '\' */ 2053 1.16 christos arg[j++] = s[i]; 2054 1.16 christos } else { 2055 1.16 christos /* Unrecognised escape */ 2056 1.16 christos arg[j++] = s[i]; 2057 1.16 christos } 2058 1.16 christos } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t')) 2059 1.16 christos break; /* done */ 2060 1.26 christos else if (quote == 0 && (s[i] == '\"' || s[i] == '\'')) 2061 1.26 christos quote = s[i]; /* quote start */ 2062 1.16 christos else if (quote != 0 && s[i] == quote) 2063 1.26 christos quote = 0; /* quote end */ 2064 1.16 christos else 2065 1.16 christos arg[j++] = s[i]; 2066 1.16 christos } 2067 1.16 christos if (s[i] == '\0') { 2068 1.16 christos if (quote != 0) { 2069 1.16 christos /* Ran out of string looking for close quote */ 2070 1.16 christos r = SSH_ERR_INVALID_FORMAT; 2071 1.16 christos goto out; 2072 1.16 christos } 2073 1.16 christos break; 2074 1.16 christos } 2075 1.16 christos } 2076 1.16 christos /* Success */ 2077 1.16 christos *argcp = argc; 2078 1.16 christos *argvp = argv; 2079 1.16 christos argc = 0; 2080 1.16 christos argv = NULL; 2081 1.16 christos r = 0; 2082 1.16 christos out: 2083 1.16 christos if (argc != 0 && argv != NULL) { 2084 1.16 christos for (i = 0; i < argc; i++) 2085 1.16 christos free(argv[i]); 2086 1.16 christos free(argv); 2087 1.16 christos } 2088 1.16 christos return r; 2089 1.16 christos } 2090 1.16 christos 2091 1.16 christos /* 2092 1.16 christos * Reassemble an argument vector into a string, quoting and escaping as 2093 1.16 christos * necessary. Caller must free returned string. 2094 1.16 christos */ 2095 1.16 christos char * 2096 1.16 christos argv_assemble(int argc, char **argv) 2097 1.16 christos { 2098 1.16 christos int i, j, ws, r; 2099 1.16 christos char c, *ret; 2100 1.16 christos struct sshbuf *buf, *arg; 2101 1.16 christos 2102 1.16 christos if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) 2103 1.25 christos fatal_f("sshbuf_new failed"); 2104 1.16 christos 2105 1.16 christos for (i = 0; i < argc; i++) { 2106 1.16 christos ws = 0; 2107 1.16 christos sshbuf_reset(arg); 2108 1.16 christos for (j = 0; argv[i][j] != '\0'; j++) { 2109 1.16 christos r = 0; 2110 1.16 christos c = argv[i][j]; 2111 1.16 christos switch (c) { 2112 1.16 christos case ' ': 2113 1.16 christos case '\t': 2114 1.16 christos ws = 1; 2115 1.16 christos r = sshbuf_put_u8(arg, c); 2116 1.16 christos break; 2117 1.16 christos case '\\': 2118 1.16 christos case '\'': 2119 1.16 christos case '"': 2120 1.16 christos if ((r = sshbuf_put_u8(arg, '\\')) != 0) 2121 1.16 christos break; 2122 1.16 christos /* FALLTHROUGH */ 2123 1.16 christos default: 2124 1.16 christos r = sshbuf_put_u8(arg, c); 2125 1.16 christos break; 2126 1.16 christos } 2127 1.16 christos if (r != 0) 2128 1.25 christos fatal_fr(r, "sshbuf_put_u8"); 2129 1.16 christos } 2130 1.16 christos if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || 2131 1.16 christos (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || 2132 1.16 christos (r = sshbuf_putb(buf, arg)) != 0 || 2133 1.16 christos (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) 2134 1.25 christos fatal_fr(r, "assemble"); 2135 1.16 christos } 2136 1.16 christos if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) 2137 1.25 christos fatal_f("malloc failed"); 2138 1.16 christos memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); 2139 1.16 christos ret[sshbuf_len(buf)] = '\0'; 2140 1.16 christos sshbuf_free(buf); 2141 1.16 christos sshbuf_free(arg); 2142 1.16 christos return ret; 2143 1.16 christos } 2144 1.16 christos 2145 1.27 christos char * 2146 1.27 christos argv_next(int *argcp, char ***argvp) 2147 1.27 christos { 2148 1.27 christos char *ret = (*argvp)[0]; 2149 1.27 christos 2150 1.27 christos if (*argcp > 0 && ret != NULL) { 2151 1.27 christos (*argcp)--; 2152 1.27 christos (*argvp)++; 2153 1.27 christos } 2154 1.27 christos return ret; 2155 1.27 christos } 2156 1.27 christos 2157 1.27 christos void 2158 1.27 christos argv_consume(int *argcp) 2159 1.27 christos { 2160 1.27 christos *argcp = 0; 2161 1.27 christos } 2162 1.27 christos 2163 1.27 christos void 2164 1.27 christos argv_free(char **av, int ac) 2165 1.27 christos { 2166 1.27 christos int i; 2167 1.27 christos 2168 1.27 christos if (av == NULL) 2169 1.27 christos return; 2170 1.27 christos for (i = 0; i < ac; i++) 2171 1.27 christos free(av[i]); 2172 1.27 christos free(av); 2173 1.27 christos } 2174 1.27 christos 2175 1.16 christos /* Returns 0 if pid exited cleanly, non-zero otherwise */ 2176 1.16 christos int 2177 1.16 christos exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet) 2178 1.16 christos { 2179 1.16 christos int status; 2180 1.16 christos 2181 1.16 christos while (waitpid(pid, &status, 0) == -1) { 2182 1.16 christos if (errno != EINTR) { 2183 1.25 christos error("%s waitpid: %s", tag, strerror(errno)); 2184 1.16 christos return -1; 2185 1.16 christos } 2186 1.16 christos } 2187 1.16 christos if (WIFSIGNALED(status)) { 2188 1.16 christos error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status)); 2189 1.16 christos return -1; 2190 1.16 christos } else if (WEXITSTATUS(status) != 0) { 2191 1.16 christos do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO, 2192 1.16 christos "%s %s failed, status %d", tag, cmd, WEXITSTATUS(status)); 2193 1.16 christos return -1; 2194 1.16 christos } 2195 1.16 christos return 0; 2196 1.16 christos } 2197 1.16 christos 2198 1.16 christos /* 2199 1.16 christos * Check a given path for security. This is defined as all components 2200 1.16 christos * of the path to the file must be owned by either the owner of 2201 1.16 christos * of the file or root and no directories must be group or world writable. 2202 1.16 christos * 2203 1.16 christos * XXX Should any specific check be done for sym links ? 2204 1.16 christos * 2205 1.16 christos * Takes a file name, its stat information (preferably from fstat() to 2206 1.16 christos * avoid races), the uid of the expected owner, their home directory and an 2207 1.16 christos * error buffer plus max size as arguments. 2208 1.16 christos * 2209 1.16 christos * Returns 0 on success and -1 on failure 2210 1.16 christos */ 2211 1.16 christos int 2212 1.16 christos safe_path(const char *name, struct stat *stp, const char *pw_dir, 2213 1.16 christos uid_t uid, char *err, size_t errlen) 2214 1.16 christos { 2215 1.40 christos char buf[PATH_MAX], buf2[PATH_MAX], homedir[PATH_MAX]; 2216 1.16 christos char *cp; 2217 1.16 christos int comparehome = 0; 2218 1.16 christos struct stat st; 2219 1.16 christos 2220 1.16 christos if (realpath(name, buf) == NULL) { 2221 1.16 christos snprintf(err, errlen, "realpath %s failed: %s", name, 2222 1.16 christos strerror(errno)); 2223 1.16 christos return -1; 2224 1.16 christos } 2225 1.16 christos if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) 2226 1.16 christos comparehome = 1; 2227 1.16 christos 2228 1.16 christos if (!S_ISREG(stp->st_mode)) { 2229 1.16 christos snprintf(err, errlen, "%s is not a regular file", buf); 2230 1.16 christos return -1; 2231 1.16 christos } 2232 1.16 christos if ((stp->st_uid != 0 && stp->st_uid != uid) || 2233 1.16 christos (stp->st_mode & 022) != 0) { 2234 1.16 christos snprintf(err, errlen, "bad ownership or modes for file %s", 2235 1.16 christos buf); 2236 1.16 christos return -1; 2237 1.16 christos } 2238 1.16 christos 2239 1.16 christos /* for each component of the canonical path, walking upwards */ 2240 1.16 christos for (;;) { 2241 1.40 christos /* 2242 1.40 christos * POSIX allows dirname to modify its argument and return a 2243 1.40 christos * pointer into it, so make a copy to avoid overlapping strlcpy. 2244 1.40 christos */ 2245 1.40 christos strlcpy(buf2, buf, sizeof(buf2)); 2246 1.40 christos if ((cp = dirname(buf2)) == NULL) { 2247 1.16 christos snprintf(err, errlen, "dirname() failed"); 2248 1.16 christos return -1; 2249 1.16 christos } 2250 1.16 christos strlcpy(buf, cp, sizeof(buf)); 2251 1.16 christos 2252 1.21 christos if (stat(buf, &st) == -1 || 2253 1.16 christos (st.st_uid != 0 && st.st_uid != uid) || 2254 1.16 christos (st.st_mode & 022) != 0) { 2255 1.16 christos snprintf(err, errlen, 2256 1.16 christos "bad ownership or modes for directory %s", buf); 2257 1.16 christos return -1; 2258 1.16 christos } 2259 1.16 christos 2260 1.16 christos /* If are past the homedir then we can stop */ 2261 1.16 christos if (comparehome && strcmp(homedir, buf) == 0) 2262 1.16 christos break; 2263 1.16 christos 2264 1.16 christos /* 2265 1.16 christos * dirname should always complete with a "/" path, 2266 1.16 christos * but we can be paranoid and check for "." too 2267 1.16 christos */ 2268 1.16 christos if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 2269 1.16 christos break; 2270 1.16 christos } 2271 1.16 christos return 0; 2272 1.16 christos } 2273 1.16 christos 2274 1.16 christos /* 2275 1.16 christos * Version of safe_path() that accepts an open file descriptor to 2276 1.16 christos * avoid races. 2277 1.16 christos * 2278 1.16 christos * Returns 0 on success and -1 on failure 2279 1.16 christos */ 2280 1.16 christos int 2281 1.16 christos safe_path_fd(int fd, const char *file, struct passwd *pw, 2282 1.16 christos char *err, size_t errlen) 2283 1.16 christos { 2284 1.16 christos struct stat st; 2285 1.16 christos 2286 1.16 christos /* check the open file to avoid races */ 2287 1.21 christos if (fstat(fd, &st) == -1) { 2288 1.16 christos snprintf(err, errlen, "cannot stat file %s: %s", 2289 1.16 christos file, strerror(errno)); 2290 1.16 christos return -1; 2291 1.16 christos } 2292 1.16 christos return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); 2293 1.16 christos } 2294 1.16 christos 2295 1.16 christos /* 2296 1.16 christos * Sets the value of the given variable in the environment. If the variable 2297 1.16 christos * already exists, its value is overridden. 2298 1.16 christos */ 2299 1.16 christos void 2300 1.16 christos child_set_env(char ***envp, u_int *envsizep, const char *name, 2301 1.16 christos const char *value) 2302 1.16 christos { 2303 1.16 christos char **env; 2304 1.16 christos u_int envsize; 2305 1.16 christos u_int i, namelen; 2306 1.16 christos 2307 1.16 christos if (strchr(name, '=') != NULL) { 2308 1.16 christos error("Invalid environment variable \"%.100s\"", name); 2309 1.16 christos return; 2310 1.16 christos } 2311 1.16 christos 2312 1.16 christos /* 2313 1.16 christos * Find the slot where the value should be stored. If the variable 2314 1.16 christos * already exists, we reuse the slot; otherwise we append a new slot 2315 1.16 christos * at the end of the array, expanding if necessary. 2316 1.16 christos */ 2317 1.16 christos env = *envp; 2318 1.16 christos namelen = strlen(name); 2319 1.16 christos for (i = 0; env[i]; i++) 2320 1.16 christos if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 2321 1.16 christos break; 2322 1.16 christos if (env[i]) { 2323 1.16 christos /* Reuse the slot. */ 2324 1.16 christos free(env[i]); 2325 1.16 christos } else { 2326 1.16 christos /* New variable. Expand if necessary. */ 2327 1.16 christos envsize = *envsizep; 2328 1.16 christos if (i >= envsize - 1) { 2329 1.16 christos if (envsize >= 1000) 2330 1.16 christos fatal("child_set_env: too many env vars"); 2331 1.16 christos envsize += 50; 2332 1.16 christos env = (*envp) = xreallocarray(env, envsize, sizeof(char *)); 2333 1.16 christos *envsizep = envsize; 2334 1.16 christos } 2335 1.16 christos /* Need to set the NULL pointer at end of array beyond the new slot. */ 2336 1.16 christos env[i + 1] = NULL; 2337 1.16 christos } 2338 1.16 christos 2339 1.16 christos /* Allocate space and format the variable in the appropriate slot. */ 2340 1.17 christos /* XXX xasprintf */ 2341 1.16 christos env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 2342 1.16 christos snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 2343 1.16 christos } 2344 1.16 christos 2345 1.17 christos /* 2346 1.17 christos * Check and optionally lowercase a domain name, also removes trailing '.' 2347 1.17 christos * Returns 1 on success and 0 on failure, storing an error message in errstr. 2348 1.17 christos */ 2349 1.17 christos int 2350 1.17 christos valid_domain(char *name, int makelower, const char **errstr) 2351 1.17 christos { 2352 1.17 christos size_t i, l = strlen(name); 2353 1.17 christos u_char c, last = '\0'; 2354 1.17 christos static char errbuf[256]; 2355 1.17 christos 2356 1.17 christos if (l == 0) { 2357 1.17 christos strlcpy(errbuf, "empty domain name", sizeof(errbuf)); 2358 1.17 christos goto bad; 2359 1.17 christos } 2360 1.39 christos if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]) && 2361 1.39 christos name[0] != '_' /* technically invalid, but common */) { 2362 1.17 christos snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" " 2363 1.17 christos "starts with invalid character", name); 2364 1.17 christos goto bad; 2365 1.17 christos } 2366 1.17 christos for (i = 0; i < l; i++) { 2367 1.17 christos c = tolower((u_char)name[i]); 2368 1.17 christos if (makelower) 2369 1.17 christos name[i] = (char)c; 2370 1.17 christos if (last == '.' && c == '.') { 2371 1.17 christos snprintf(errbuf, sizeof(errbuf), "domain name " 2372 1.17 christos "\"%.100s\" contains consecutive separators", name); 2373 1.17 christos goto bad; 2374 1.17 christos } 2375 1.17 christos if (c != '.' && c != '-' && !isalnum(c) && 2376 1.17 christos c != '_') /* technically invalid, but common */ { 2377 1.17 christos snprintf(errbuf, sizeof(errbuf), "domain name " 2378 1.17 christos "\"%.100s\" contains invalid characters", name); 2379 1.17 christos goto bad; 2380 1.17 christos } 2381 1.17 christos last = c; 2382 1.17 christos } 2383 1.17 christos if (name[l - 1] == '.') 2384 1.17 christos name[l - 1] = '\0'; 2385 1.17 christos if (errstr != NULL) 2386 1.17 christos *errstr = NULL; 2387 1.17 christos return 1; 2388 1.17 christos bad: 2389 1.17 christos if (errstr != NULL) 2390 1.17 christos *errstr = errbuf; 2391 1.17 christos return 0; 2392 1.17 christos } 2393 1.17 christos 2394 1.20 christos /* 2395 1.20 christos * Verify that a environment variable name (not including initial '$') is 2396 1.20 christos * valid; consisting of one or more alphanumeric or underscore characters only. 2397 1.20 christos * Returns 1 on valid, 0 otherwise. 2398 1.20 christos */ 2399 1.20 christos int 2400 1.20 christos valid_env_name(const char *name) 2401 1.20 christos { 2402 1.20 christos const char *cp; 2403 1.20 christos 2404 1.20 christos if (name[0] == '\0') 2405 1.20 christos return 0; 2406 1.20 christos for (cp = name; *cp != '\0'; cp++) { 2407 1.20 christos if (!isalnum((u_char)*cp) && *cp != '_') 2408 1.20 christos return 0; 2409 1.20 christos } 2410 1.20 christos return 1; 2411 1.20 christos } 2412 1.20 christos 2413 1.17 christos const char * 2414 1.17 christos atoi_err(const char *nptr, int *val) 2415 1.17 christos { 2416 1.17 christos const char *errstr = NULL; 2417 1.17 christos 2418 1.17 christos if (nptr == NULL || *nptr == '\0') 2419 1.17 christos return "missing"; 2420 1.37 christos *val = strtonum(nptr, 0, INT_MAX, &errstr); 2421 1.17 christos return errstr; 2422 1.17 christos } 2423 1.17 christos 2424 1.17 christos int 2425 1.17 christos parse_absolute_time(const char *s, uint64_t *tp) 2426 1.17 christos { 2427 1.17 christos struct tm tm; 2428 1.17 christos time_t tt; 2429 1.17 christos char buf[32]; 2430 1.32 christos const char *fmt, *cp; 2431 1.32 christos size_t l; 2432 1.32 christos int is_utc = 0; 2433 1.17 christos 2434 1.17 christos *tp = 0; 2435 1.17 christos 2436 1.32 christos l = strlen(s); 2437 1.32 christos if (l > 1 && strcasecmp(s + l - 1, "Z") == 0) { 2438 1.32 christos is_utc = 1; 2439 1.32 christos l--; 2440 1.32 christos } else if (l > 3 && strcasecmp(s + l - 3, "UTC") == 0) { 2441 1.32 christos is_utc = 1; 2442 1.32 christos l -= 3; 2443 1.32 christos } 2444 1.17 christos /* 2445 1.17 christos * POSIX strptime says "The application shall ensure that there 2446 1.17 christos * is white-space or other non-alphanumeric characters between 2447 1.17 christos * any two conversion specifications" so arrange things this way. 2448 1.17 christos */ 2449 1.32 christos switch (l) { 2450 1.17 christos case 8: /* YYYYMMDD */ 2451 1.17 christos fmt = "%Y-%m-%d"; 2452 1.17 christos snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); 2453 1.17 christos break; 2454 1.17 christos case 12: /* YYYYMMDDHHMM */ 2455 1.17 christos fmt = "%Y-%m-%dT%H:%M"; 2456 1.17 christos snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s", 2457 1.17 christos s, s + 4, s + 6, s + 8, s + 10); 2458 1.17 christos break; 2459 1.17 christos case 14: /* YYYYMMDDHHMMSS */ 2460 1.17 christos fmt = "%Y-%m-%dT%H:%M:%S"; 2461 1.17 christos snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", 2462 1.17 christos s, s + 4, s + 6, s + 8, s + 10, s + 12); 2463 1.17 christos break; 2464 1.17 christos default: 2465 1.17 christos return SSH_ERR_INVALID_FORMAT; 2466 1.17 christos } 2467 1.17 christos 2468 1.17 christos memset(&tm, 0, sizeof(tm)); 2469 1.32 christos if ((cp = strptime(buf, fmt, &tm)) == NULL || *cp != '\0') 2470 1.17 christos return SSH_ERR_INVALID_FORMAT; 2471 1.32 christos if (is_utc) { 2472 1.32 christos if ((tt = timegm(&tm)) < 0) 2473 1.32 christos return SSH_ERR_INVALID_FORMAT; 2474 1.32 christos } else { 2475 1.32 christos if ((tt = mktime(&tm)) < 0) 2476 1.32 christos return SSH_ERR_INVALID_FORMAT; 2477 1.32 christos } 2478 1.17 christos /* success */ 2479 1.17 christos *tp = (uint64_t)tt; 2480 1.17 christos return 0; 2481 1.17 christos } 2482 1.17 christos 2483 1.17 christos void 2484 1.17 christos format_absolute_time(uint64_t t, char *buf, size_t len) 2485 1.17 christos { 2486 1.27 christos time_t tt = t > SSH_TIME_T_MAX ? SSH_TIME_T_MAX : t; 2487 1.17 christos struct tm tm; 2488 1.17 christos 2489 1.40 christos if (localtime_r(&tt, &tm) == NULL) 2490 1.40 christos strlcpy(buf, "UNKNOWN-TIME", len); 2491 1.40 christos else 2492 1.40 christos strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm); 2493 1.17 christos } 2494 1.20 christos 2495 1.35 christos /* 2496 1.35 christos * Parse a "pattern=interval" clause (e.g. a ChannelTimeout). 2497 1.35 christos * Returns 0 on success or non-zero on failure. 2498 1.35 christos * Caller must free *typep. 2499 1.35 christos */ 2500 1.35 christos int 2501 1.35 christos parse_pattern_interval(const char *s, char **typep, int *secsp) 2502 1.35 christos { 2503 1.35 christos char *cp, *sdup; 2504 1.35 christos int secs; 2505 1.35 christos 2506 1.35 christos if (typep != NULL) 2507 1.35 christos *typep = NULL; 2508 1.35 christos if (secsp != NULL) 2509 1.35 christos *secsp = 0; 2510 1.35 christos if (s == NULL) 2511 1.35 christos return -1; 2512 1.35 christos sdup = xstrdup(s); 2513 1.35 christos 2514 1.35 christos if ((cp = strchr(sdup, '=')) == NULL || cp == sdup) { 2515 1.35 christos free(sdup); 2516 1.35 christos return -1; 2517 1.35 christos } 2518 1.35 christos *cp++ = '\0'; 2519 1.35 christos if ((secs = convtime(cp)) < 0) { 2520 1.35 christos free(sdup); 2521 1.35 christos return -1; 2522 1.35 christos } 2523 1.35 christos /* success */ 2524 1.35 christos if (typep != NULL) 2525 1.35 christos *typep = xstrdup(sdup); 2526 1.35 christos if (secsp != NULL) 2527 1.35 christos *secsp = secs; 2528 1.35 christos free(sdup); 2529 1.35 christos return 0; 2530 1.35 christos } 2531 1.35 christos 2532 1.20 christos /* check if path is absolute */ 2533 1.20 christos int 2534 1.20 christos path_absolute(const char *path) 2535 1.20 christos { 2536 1.20 christos return (*path == '/') ? 1 : 0; 2537 1.20 christos } 2538 1.21 christos 2539 1.21 christos void 2540 1.21 christos skip_space(char **cpp) 2541 1.21 christos { 2542 1.21 christos char *cp; 2543 1.21 christos 2544 1.21 christos for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 2545 1.21 christos ; 2546 1.21 christos *cpp = cp; 2547 1.21 christos } 2548 1.21 christos 2549 1.21 christos /* authorized_key-style options parsing helpers */ 2550 1.21 christos 2551 1.21 christos /* 2552 1.21 christos * Match flag 'opt' in *optsp, and if allow_negate is set then also match 2553 1.21 christos * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0 2554 1.21 christos * if negated option matches. 2555 1.21 christos * If the option or negated option matches, then *optsp is updated to 2556 1.21 christos * point to the first character after the option. 2557 1.21 christos */ 2558 1.21 christos int 2559 1.21 christos opt_flag(const char *opt, int allow_negate, const char **optsp) 2560 1.21 christos { 2561 1.21 christos size_t opt_len = strlen(opt); 2562 1.21 christos const char *opts = *optsp; 2563 1.21 christos int negate = 0; 2564 1.21 christos 2565 1.21 christos if (allow_negate && strncasecmp(opts, "no-", 3) == 0) { 2566 1.21 christos opts += 3; 2567 1.21 christos negate = 1; 2568 1.21 christos } 2569 1.21 christos if (strncasecmp(opts, opt, opt_len) == 0) { 2570 1.21 christos *optsp = opts + opt_len; 2571 1.21 christos return negate ? 0 : 1; 2572 1.21 christos } 2573 1.21 christos return -1; 2574 1.21 christos } 2575 1.21 christos 2576 1.21 christos char * 2577 1.21 christos opt_dequote(const char **sp, const char **errstrp) 2578 1.21 christos { 2579 1.21 christos const char *s = *sp; 2580 1.21 christos char *ret; 2581 1.21 christos size_t i; 2582 1.21 christos 2583 1.21 christos *errstrp = NULL; 2584 1.21 christos if (*s != '"') { 2585 1.21 christos *errstrp = "missing start quote"; 2586 1.21 christos return NULL; 2587 1.21 christos } 2588 1.21 christos s++; 2589 1.21 christos if ((ret = malloc(strlen((s)) + 1)) == NULL) { 2590 1.21 christos *errstrp = "memory allocation failed"; 2591 1.21 christos return NULL; 2592 1.21 christos } 2593 1.21 christos for (i = 0; *s != '\0' && *s != '"';) { 2594 1.21 christos if (s[0] == '\\' && s[1] == '"') 2595 1.21 christos s++; 2596 1.21 christos ret[i++] = *s++; 2597 1.21 christos } 2598 1.21 christos if (*s == '\0') { 2599 1.21 christos *errstrp = "missing end quote"; 2600 1.21 christos free(ret); 2601 1.21 christos return NULL; 2602 1.21 christos } 2603 1.21 christos ret[i] = '\0'; 2604 1.21 christos s++; 2605 1.21 christos *sp = s; 2606 1.21 christos return ret; 2607 1.21 christos } 2608 1.21 christos 2609 1.21 christos int 2610 1.21 christos opt_match(const char **opts, const char *term) 2611 1.21 christos { 2612 1.21 christos if (strncasecmp((*opts), term, strlen(term)) == 0 && 2613 1.21 christos (*opts)[strlen(term)] == '=') { 2614 1.21 christos *opts += strlen(term) + 1; 2615 1.21 christos return 1; 2616 1.21 christos } 2617 1.21 christos return 0; 2618 1.21 christos } 2619 1.21 christos 2620 1.25 christos void 2621 1.25 christos opt_array_append2(const char *file, const int line, const char *directive, 2622 1.25 christos char ***array, int **iarray, u_int *lp, const char *s, int i) 2623 1.25 christos { 2624 1.25 christos 2625 1.25 christos if (*lp >= INT_MAX) 2626 1.25 christos fatal("%s line %d: Too many %s entries", file, line, directive); 2627 1.25 christos 2628 1.25 christos if (iarray != NULL) { 2629 1.25 christos *iarray = xrecallocarray(*iarray, *lp, *lp + 1, 2630 1.25 christos sizeof(**iarray)); 2631 1.25 christos (*iarray)[*lp] = i; 2632 1.25 christos } 2633 1.25 christos 2634 1.25 christos *array = xrecallocarray(*array, *lp, *lp + 1, sizeof(**array)); 2635 1.25 christos (*array)[*lp] = xstrdup(s); 2636 1.25 christos (*lp)++; 2637 1.25 christos } 2638 1.25 christos 2639 1.25 christos void 2640 1.25 christos opt_array_append(const char *file, const int line, const char *directive, 2641 1.25 christos char ***array, u_int *lp, const char *s) 2642 1.25 christos { 2643 1.25 christos opt_array_append2(file, line, directive, array, NULL, lp, s, 0); 2644 1.25 christos } 2645 1.25 christos 2646 1.36 christos void 2647 1.36 christos opt_array_free2(char **array, int **iarray, u_int l) 2648 1.36 christos { 2649 1.36 christos u_int i; 2650 1.36 christos 2651 1.36 christos if (array == NULL || l == 0) 2652 1.36 christos return; 2653 1.36 christos for (i = 0; i < l; i++) 2654 1.36 christos free(array[i]); 2655 1.36 christos free(array); 2656 1.36 christos free(iarray); 2657 1.36 christos } 2658 1.36 christos 2659 1.22 christos sshsig_t 2660 1.22 christos ssh_signal(int signum, sshsig_t handler) 2661 1.22 christos { 2662 1.22 christos struct sigaction sa, osa; 2663 1.22 christos 2664 1.22 christos /* mask all other signals while in handler */ 2665 1.23 christos memset(&sa, 0, sizeof(sa)); 2666 1.22 christos sa.sa_handler = handler; 2667 1.22 christos sigfillset(&sa.sa_mask); 2668 1.22 christos if (signum != SIGALRM) 2669 1.22 christos sa.sa_flags = SA_RESTART; 2670 1.22 christos if (sigaction(signum, &sa, &osa) == -1) { 2671 1.22 christos debug3("sigaction(%s): %s", strsignal(signum), strerror(errno)); 2672 1.22 christos return SIG_ERR; 2673 1.22 christos } 2674 1.22 christos return osa.sa_handler; 2675 1.22 christos } 2676 1.25 christos 2677 1.25 christos int 2678 1.25 christos stdfd_devnull(int do_stdin, int do_stdout, int do_stderr) 2679 1.25 christos { 2680 1.25 christos int devnull, ret = 0; 2681 1.25 christos 2682 1.25 christos if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 2683 1.25 christos error_f("open %s: %s", _PATH_DEVNULL, 2684 1.25 christos strerror(errno)); 2685 1.25 christos return -1; 2686 1.25 christos } 2687 1.25 christos if ((do_stdin && dup2(devnull, STDIN_FILENO) == -1) || 2688 1.25 christos (do_stdout && dup2(devnull, STDOUT_FILENO) == -1) || 2689 1.25 christos (do_stderr && dup2(devnull, STDERR_FILENO) == -1)) { 2690 1.25 christos error_f("dup2: %s", strerror(errno)); 2691 1.25 christos ret = -1; 2692 1.25 christos } 2693 1.25 christos if (devnull > STDERR_FILENO) 2694 1.25 christos close(devnull); 2695 1.25 christos return ret; 2696 1.25 christos } 2697 1.25 christos 2698 1.25 christos /* 2699 1.25 christos * Runs command in a subprocess with a minimal environment. 2700 1.25 christos * Returns pid on success, 0 on failure. 2701 1.25 christos * The child stdout and stderr maybe captured, left attached or sent to 2702 1.25 christos * /dev/null depending on the contents of flags. 2703 1.25 christos * "tag" is prepended to log messages. 2704 1.25 christos * NB. "command" is only used for logging; the actual command executed is 2705 1.25 christos * av[0]. 2706 1.25 christos */ 2707 1.25 christos pid_t 2708 1.25 christos subprocess(const char *tag, const char *command, 2709 1.25 christos int ac, char **av, FILE **child, u_int flags, 2710 1.25 christos struct passwd *pw, privdrop_fn *drop_privs, privrestore_fn *restore_privs) 2711 1.25 christos { 2712 1.25 christos FILE *f = NULL; 2713 1.25 christos struct stat st; 2714 1.25 christos int fd, devnull, p[2], i; 2715 1.25 christos pid_t pid; 2716 1.25 christos char *cp, errmsg[512]; 2717 1.25 christos u_int nenv = 0; 2718 1.25 christos char **env = NULL; 2719 1.25 christos 2720 1.25 christos /* If dropping privs, then must specify user and restore function */ 2721 1.25 christos if (drop_privs != NULL && (pw == NULL || restore_privs == NULL)) { 2722 1.25 christos error("%s: inconsistent arguments", tag); /* XXX fatal? */ 2723 1.25 christos return 0; 2724 1.25 christos } 2725 1.25 christos if (pw == NULL && (pw = getpwuid(getuid())) == NULL) { 2726 1.25 christos error("%s: no user for current uid", tag); 2727 1.25 christos return 0; 2728 1.25 christos } 2729 1.25 christos if (child != NULL) 2730 1.25 christos *child = NULL; 2731 1.25 christos 2732 1.25 christos debug3_f("%s command \"%s\" running as %s (flags 0x%x)", 2733 1.25 christos tag, command, pw->pw_name, flags); 2734 1.25 christos 2735 1.25 christos /* Check consistency */ 2736 1.25 christos if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && 2737 1.25 christos (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) { 2738 1.25 christos error_f("inconsistent flags"); 2739 1.25 christos return 0; 2740 1.25 christos } 2741 1.25 christos if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) { 2742 1.25 christos error_f("inconsistent flags/output"); 2743 1.25 christos return 0; 2744 1.25 christos } 2745 1.25 christos 2746 1.25 christos /* 2747 1.25 christos * If executing an explicit binary, then verify the it exists 2748 1.25 christos * and appears safe-ish to execute 2749 1.25 christos */ 2750 1.25 christos if (!path_absolute(av[0])) { 2751 1.25 christos error("%s path is not absolute", tag); 2752 1.25 christos return 0; 2753 1.25 christos } 2754 1.25 christos if (drop_privs != NULL) 2755 1.25 christos drop_privs(pw); 2756 1.25 christos if (stat(av[0], &st) == -1) { 2757 1.25 christos error("Could not stat %s \"%s\": %s", tag, 2758 1.25 christos av[0], strerror(errno)); 2759 1.25 christos goto restore_return; 2760 1.25 christos } 2761 1.25 christos if ((flags & SSH_SUBPROCESS_UNSAFE_PATH) == 0 && 2762 1.25 christos safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { 2763 1.25 christos error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); 2764 1.25 christos goto restore_return; 2765 1.25 christos } 2766 1.25 christos /* Prepare to keep the child's stdout if requested */ 2767 1.25 christos if (pipe(p) == -1) { 2768 1.25 christos error("%s: pipe: %s", tag, strerror(errno)); 2769 1.25 christos restore_return: 2770 1.25 christos if (restore_privs != NULL) 2771 1.25 christos restore_privs(); 2772 1.25 christos return 0; 2773 1.25 christos } 2774 1.25 christos if (restore_privs != NULL) 2775 1.25 christos restore_privs(); 2776 1.25 christos 2777 1.25 christos switch ((pid = fork())) { 2778 1.25 christos case -1: /* error */ 2779 1.25 christos error("%s: fork: %s", tag, strerror(errno)); 2780 1.25 christos close(p[0]); 2781 1.25 christos close(p[1]); 2782 1.25 christos return 0; 2783 1.25 christos case 0: /* child */ 2784 1.25 christos /* Prepare a minimal environment for the child. */ 2785 1.25 christos if ((flags & SSH_SUBPROCESS_PRESERVE_ENV) == 0) { 2786 1.25 christos nenv = 5; 2787 1.25 christos env = xcalloc(sizeof(*env), nenv); 2788 1.25 christos child_set_env(&env, &nenv, "PATH", _PATH_STDPATH); 2789 1.25 christos child_set_env(&env, &nenv, "USER", pw->pw_name); 2790 1.25 christos child_set_env(&env, &nenv, "LOGNAME", pw->pw_name); 2791 1.25 christos child_set_env(&env, &nenv, "HOME", pw->pw_dir); 2792 1.25 christos if ((cp = getenv("LANG")) != NULL) 2793 1.25 christos child_set_env(&env, &nenv, "LANG", cp); 2794 1.25 christos } 2795 1.25 christos 2796 1.25 christos for (i = 1; i < NSIG; i++) 2797 1.25 christos ssh_signal(i, SIG_DFL); 2798 1.25 christos 2799 1.25 christos if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 2800 1.25 christos error("%s: open %s: %s", tag, _PATH_DEVNULL, 2801 1.25 christos strerror(errno)); 2802 1.25 christos _exit(1); 2803 1.25 christos } 2804 1.25 christos if (dup2(devnull, STDIN_FILENO) == -1) { 2805 1.25 christos error("%s: dup2: %s", tag, strerror(errno)); 2806 1.25 christos _exit(1); 2807 1.25 christos } 2808 1.25 christos 2809 1.25 christos /* Set up stdout as requested; leave stderr in place for now. */ 2810 1.25 christos fd = -1; 2811 1.25 christos if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) 2812 1.25 christos fd = p[1]; 2813 1.25 christos else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0) 2814 1.25 christos fd = devnull; 2815 1.25 christos if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) { 2816 1.25 christos error("%s: dup2: %s", tag, strerror(errno)); 2817 1.25 christos _exit(1); 2818 1.25 christos } 2819 1.25 christos closefrom(STDERR_FILENO + 1); 2820 1.25 christos 2821 1.25 christos #ifdef __NetBSD__ 2822 1.25 christos #define setresgid(a, b, c) setgid(a) 2823 1.25 christos #define setresuid(a, b, c) setuid(a) 2824 1.25 christos #endif 2825 1.25 christos 2826 1.28 christos if (geteuid() == 0 && 2827 1.28 christos initgroups(pw->pw_name, pw->pw_gid) == -1) { 2828 1.28 christos error("%s: initgroups(%s, %u): %s", tag, 2829 1.28 christos pw->pw_name, (u_int)pw->pw_gid, strerror(errno)); 2830 1.28 christos _exit(1); 2831 1.28 christos } 2832 1.25 christos if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) { 2833 1.25 christos error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, 2834 1.25 christos strerror(errno)); 2835 1.25 christos _exit(1); 2836 1.25 christos } 2837 1.25 christos if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) { 2838 1.25 christos error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, 2839 1.25 christos strerror(errno)); 2840 1.25 christos _exit(1); 2841 1.25 christos } 2842 1.25 christos /* stdin is pointed to /dev/null at this point */ 2843 1.25 christos if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && 2844 1.25 christos dup2(STDIN_FILENO, STDERR_FILENO) == -1) { 2845 1.25 christos error("%s: dup2: %s", tag, strerror(errno)); 2846 1.25 christos _exit(1); 2847 1.25 christos } 2848 1.25 christos if (env != NULL) 2849 1.25 christos execve(av[0], av, env); 2850 1.25 christos else 2851 1.25 christos execv(av[0], av); 2852 1.25 christos error("%s %s \"%s\": %s", tag, env == NULL ? "execv" : "execve", 2853 1.25 christos command, strerror(errno)); 2854 1.25 christos _exit(127); 2855 1.25 christos default: /* parent */ 2856 1.25 christos break; 2857 1.25 christos } 2858 1.25 christos 2859 1.25 christos close(p[1]); 2860 1.25 christos if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) 2861 1.25 christos close(p[0]); 2862 1.25 christos else if ((f = fdopen(p[0], "r")) == NULL) { 2863 1.25 christos error("%s: fdopen: %s", tag, strerror(errno)); 2864 1.25 christos close(p[0]); 2865 1.25 christos /* Don't leave zombie child */ 2866 1.25 christos kill(pid, SIGTERM); 2867 1.25 christos while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 2868 1.25 christos ; 2869 1.25 christos return 0; 2870 1.25 christos } 2871 1.25 christos /* Success */ 2872 1.25 christos debug3_f("%s pid %ld", tag, (long)pid); 2873 1.25 christos if (child != NULL) 2874 1.25 christos *child = f; 2875 1.25 christos return pid; 2876 1.25 christos } 2877 1.27 christos 2878 1.27 christos const char * 2879 1.27 christos lookup_env_in_list(const char *env, char * const *envs, size_t nenvs) 2880 1.27 christos { 2881 1.27 christos size_t i, envlen; 2882 1.27 christos 2883 1.27 christos envlen = strlen(env); 2884 1.27 christos for (i = 0; i < nenvs; i++) { 2885 1.27 christos if (strncmp(envs[i], env, envlen) == 0 && 2886 1.27 christos envs[i][envlen] == '=') { 2887 1.27 christos return envs[i] + envlen + 1; 2888 1.27 christos } 2889 1.27 christos } 2890 1.27 christos return NULL; 2891 1.27 christos } 2892 1.32 christos 2893 1.32 christos const char * 2894 1.32 christos lookup_setenv_in_list(const char *env, char * const *envs, size_t nenvs) 2895 1.32 christos { 2896 1.32 christos char *name, *cp; 2897 1.32 christos const char *ret; 2898 1.32 christos 2899 1.32 christos name = xstrdup(env); 2900 1.32 christos if ((cp = strchr(name, '=')) == NULL) { 2901 1.32 christos free(name); 2902 1.32 christos return NULL; /* not env=val */ 2903 1.32 christos } 2904 1.32 christos *cp = '\0'; 2905 1.32 christos ret = lookup_env_in_list(name, envs, nenvs); 2906 1.32 christos free(name); 2907 1.32 christos return ret; 2908 1.32 christos } 2909 1.33 christos 2910 1.33 christos /* 2911 1.33 christos * Helpers for managing poll(2)/ppoll(2) timeouts 2912 1.33 christos * Will remember the earliest deadline and return it for use in poll/ppoll. 2913 1.33 christos */ 2914 1.33 christos 2915 1.33 christos /* Initialise a poll/ppoll timeout with an indefinite deadline */ 2916 1.33 christos void 2917 1.33 christos ptimeout_init(struct timespec *pt) 2918 1.33 christos { 2919 1.33 christos /* 2920 1.33 christos * Deliberately invalid for ppoll(2). 2921 1.33 christos * Will be converted to NULL in ptimeout_get_tspec() later. 2922 1.33 christos */ 2923 1.33 christos pt->tv_sec = -1; 2924 1.33 christos pt->tv_nsec = 0; 2925 1.33 christos } 2926 1.33 christos 2927 1.33 christos /* Specify a poll/ppoll deadline of at most 'sec' seconds */ 2928 1.33 christos void 2929 1.33 christos ptimeout_deadline_sec(struct timespec *pt, long sec) 2930 1.33 christos { 2931 1.33 christos if (pt->tv_sec == -1 || pt->tv_sec >= sec) { 2932 1.33 christos pt->tv_sec = sec; 2933 1.33 christos pt->tv_nsec = 0; 2934 1.33 christos } 2935 1.33 christos } 2936 1.33 christos 2937 1.33 christos /* Specify a poll/ppoll deadline of at most 'p' (timespec) */ 2938 1.33 christos static void 2939 1.33 christos ptimeout_deadline_tsp(struct timespec *pt, struct timespec *p) 2940 1.33 christos { 2941 1.33 christos if (pt->tv_sec == -1 || timespeccmp(pt, p, >=)) 2942 1.33 christos *pt = *p; 2943 1.33 christos } 2944 1.33 christos 2945 1.33 christos /* Specify a poll/ppoll deadline of at most 'ms' milliseconds */ 2946 1.33 christos void 2947 1.33 christos ptimeout_deadline_ms(struct timespec *pt, long ms) 2948 1.33 christos { 2949 1.33 christos struct timespec p; 2950 1.33 christos 2951 1.33 christos p.tv_sec = ms / 1000; 2952 1.33 christos p.tv_nsec = (ms % 1000) * 1000000; 2953 1.33 christos ptimeout_deadline_tsp(pt, &p); 2954 1.33 christos } 2955 1.33 christos 2956 1.34 christos /* Specify a poll/ppoll deadline at wall clock monotime 'when' (timespec) */ 2957 1.33 christos void 2958 1.34 christos ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when) 2959 1.33 christos { 2960 1.33 christos struct timespec now, t; 2961 1.33 christos 2962 1.33 christos monotime_ts(&now); 2963 1.33 christos 2964 1.34 christos if (timespeccmp(&now, when, >=)) { 2965 1.34 christos /* 'when' is now or in the past. Timeout ASAP */ 2966 1.34 christos pt->tv_sec = 0; 2967 1.34 christos pt->tv_nsec = 0; 2968 1.34 christos } else { 2969 1.34 christos timespecsub(when, &now, &t); 2970 1.33 christos ptimeout_deadline_tsp(pt, &t); 2971 1.33 christos } 2972 1.33 christos } 2973 1.33 christos 2974 1.34 christos /* Specify a poll/ppoll deadline at wall clock monotime 'when' */ 2975 1.34 christos void 2976 1.34 christos ptimeout_deadline_monotime(struct timespec *pt, time_t when) 2977 1.34 christos { 2978 1.34 christos struct timespec t; 2979 1.34 christos 2980 1.34 christos t.tv_sec = when; 2981 1.34 christos t.tv_nsec = 0; 2982 1.34 christos ptimeout_deadline_monotime_tsp(pt, &t); 2983 1.34 christos } 2984 1.34 christos 2985 1.33 christos /* Get a poll(2) timeout value in milliseconds */ 2986 1.33 christos int 2987 1.33 christos ptimeout_get_ms(struct timespec *pt) 2988 1.33 christos { 2989 1.33 christos if (pt->tv_sec == -1) 2990 1.33 christos return -1; 2991 1.33 christos if (pt->tv_sec >= (INT_MAX - (pt->tv_nsec / 1000000)) / 1000) 2992 1.33 christos return INT_MAX; 2993 1.33 christos return (pt->tv_sec * 1000) + (pt->tv_nsec / 1000000); 2994 1.33 christos } 2995 1.33 christos 2996 1.33 christos /* Get a ppoll(2) timeout value as a timespec pointer */ 2997 1.33 christos struct timespec * 2998 1.33 christos ptimeout_get_tsp(struct timespec *pt) 2999 1.33 christos { 3000 1.33 christos return pt->tv_sec == -1 ? NULL : pt; 3001 1.33 christos } 3002 1.33 christos 3003 1.33 christos /* Returns non-zero if a timeout has been set (i.e. is not indefinite) */ 3004 1.33 christos int 3005 1.33 christos ptimeout_isset(struct timespec *pt) 3006 1.33 christos { 3007 1.33 christos return pt->tv_sec != -1; 3008 1.33 christos } 3009 1.34 christos 3010 1.34 christos /* 3011 1.34 christos * Returns zero if the library at 'path' contains symbol 's', nonzero 3012 1.34 christos * otherwise. 3013 1.34 christos */ 3014 1.34 christos int 3015 1.34 christos lib_contains_symbol(const char *path, const char *s) 3016 1.34 christos { 3017 1.34 christos struct nlist nl[2]; 3018 1.34 christos int ret = -1, r; 3019 1.34 christos char *name; 3020 1.34 christos 3021 1.34 christos memset(nl, 0, sizeof(nl)); 3022 1.34 christos nl[0].n_name = name = xstrdup(s); 3023 1.34 christos nl[1].n_name = NULL; 3024 1.34 christos if ((r = nlist(path, nl)) == -1) { 3025 1.34 christos error_f("nlist failed for %s", path); 3026 1.34 christos goto out; 3027 1.34 christos } 3028 1.34 christos if (r != 0 || nl[0].n_value == 0 || nl[0].n_type == 0) { 3029 1.34 christos error_f("library %s does not contain symbol %s", path, s); 3030 1.34 christos goto out; 3031 1.34 christos } 3032 1.34 christos /* success */ 3033 1.34 christos ret = 0; 3034 1.34 christos out: 3035 1.34 christos free(name); 3036 1.34 christos return ret; 3037 1.34 christos } 3038 1.37 christos 3039 1.37 christos int 3040 1.37 christos signal_is_crash(int sig) 3041 1.37 christos { 3042 1.37 christos switch (sig) { 3043 1.37 christos case SIGSEGV: 3044 1.37 christos case SIGBUS: 3045 1.37 christos case SIGTRAP: 3046 1.37 christos case SIGSYS: 3047 1.37 christos case SIGFPE: 3048 1.37 christos case SIGILL: 3049 1.37 christos case SIGABRT: 3050 1.37 christos return 1; 3051 1.37 christos } 3052 1.37 christos return 0; 3053 1.37 christos } 3054 1.40 christos 3055 1.40 christos char * 3056 1.40 christos get_homedir(void) 3057 1.40 christos { 3058 1.40 christos char *cp; 3059 1.40 christos struct passwd *pw; 3060 1.40 christos 3061 1.40 christos if ((cp = getenv("HOME")) != NULL && *cp != '\0') 3062 1.40 christos return xstrdup(cp); 3063 1.40 christos 3064 1.40 christos if ((pw = getpwuid(getuid())) != NULL && *pw->pw_dir != '\0') 3065 1.40 christos return xstrdup(pw->pw_dir); 3066 1.40 christos 3067 1.40 christos return NULL; 3068 1.40 christos } 3069