1 /* $OpenBSD: misc.c,v 1.198 2024/10/24 03:14:37 djm Exp $ */
3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2005-2020 Damien Miller. All rights reserved.
5 * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
26 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/tcp.h>
57 #include <arpa/inet.h>
68 #ifdef SSH_TUN_OPENBSD
80 /* remove newline at end of string */
86 if (*t
== '\n' || *t
== '\r') {
96 /* remove whitespace from end of string */
102 if ((i
= strlen(s
)) == 0)
104 for (i
--; i
> 0; i
--) {
105 if (isspace((unsigned char)s
[i
]))
111 * returns pointer to character after 'prefix' in 's' or otherwise NULL
112 * if the prefix is not present.
115 strprefix(const char *s
, const char *prefix
, int ignorecase
)
119 if ((prefixlen
= strlen(prefix
)) == 0)
122 if (strncasecmp(s
, prefix
, prefixlen
) != 0)
125 if (strncmp(s
, prefix
, prefixlen
) != 0)
128 return s
+ prefixlen
;
131 /* set/unset filedescriptor to non-blocking */
137 val
= fcntl(fd
, F_GETFL
);
139 error("fcntl(%d, F_GETFL): %s", fd
, strerror(errno
));
142 if (val
& O_NONBLOCK
) {
143 debug3("fd %d is O_NONBLOCK", fd
);
146 debug2("fd %d setting O_NONBLOCK", fd
);
148 if (fcntl(fd
, F_SETFL
, val
) == -1) {
149 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd
,
157 unset_nonblock(int fd
)
161 val
= fcntl(fd
, F_GETFL
);
163 error("fcntl(%d, F_GETFL): %s", fd
, strerror(errno
));
166 if (!(val
& O_NONBLOCK
)) {
167 debug3("fd %d is not O_NONBLOCK", fd
);
170 debug("fd %d clearing O_NONBLOCK", fd
);
172 if (fcntl(fd
, F_SETFL
, val
) == -1) {
173 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
174 fd
, strerror(errno
));
181 ssh_gai_strerror(int gaierr
)
183 if (gaierr
== EAI_SYSTEM
&& errno
!= 0)
184 return strerror(errno
);
185 return gai_strerror(gaierr
);
188 /* disable nagle on socket */
196 if (getsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &opt
, &optlen
) == -1) {
197 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno
));
201 debug2("fd %d is TCP_NODELAY", fd
);
205 debug2("fd %d setting TCP_NODELAY", fd
);
206 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &opt
, sizeof opt
) == -1)
207 error("setsockopt TCP_NODELAY: %.100s", strerror(errno
));
210 /* Allow local port reuse in TIME_WAIT */
212 set_reuseaddr(int fd
)
216 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) {
217 error("setsockopt SO_REUSEADDR fd %d: %s", fd
, strerror(errno
));
223 /* Get/set routing domain */
227 #if defined(HAVE_SYS_GET_RDOMAIN)
228 return sys_get_rdomain(fd
);
229 #elif defined(__OpenBSD__)
232 socklen_t len
= sizeof(rtable
);
234 if (getsockopt(fd
, SOL_SOCKET
, SO_RTABLE
, &rtable
, &len
) == -1) {
235 error("Failed to get routing domain for fd %d: %s",
236 fd
, strerror(errno
));
239 xasprintf(&ret
, "%d", rtable
);
241 #else /* defined(__OpenBSD__) */
247 set_rdomain(int fd
, const char *name
)
249 #if defined(HAVE_SYS_SET_RDOMAIN)
250 return sys_set_rdomain(fd
, name
);
251 #elif defined(__OpenBSD__)
256 return 0; /* default table */
258 rtable
= (int)strtonum(name
, 0, 255, &errstr
);
259 if (errstr
!= NULL
) {
260 /* Shouldn't happen */
261 error("Invalid routing domain \"%s\": %s", name
, errstr
);
264 if (setsockopt(fd
, SOL_SOCKET
, SO_RTABLE
,
265 &rtable
, sizeof(rtable
)) == -1) {
266 error("Failed to set routing domain %d on fd %d: %s",
267 rtable
, fd
, strerror(errno
));
271 #else /* defined(__OpenBSD__) */
272 error("Setting routing domain is not supported on this platform");
280 struct sockaddr_storage to
;
281 socklen_t tolen
= sizeof(to
);
283 memset(&to
, 0, sizeof(to
));
284 if (getsockname(fd
, (struct sockaddr
*)&to
, &tolen
) == -1)
287 if (to
.ss_family
== AF_INET6
&&
288 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6
*)&to
)->sin6_addr
))
295 set_sock_tos(int fd
, int tos
)
297 #ifndef IP_TOS_IS_BROKEN
300 switch ((af
= get_sock_af(fd
))) {
302 /* assume not a socket */
306 debug3_f("set socket %d IP_TOS 0x%02x", fd
, tos
);
307 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
,
308 &tos
, sizeof(tos
)) == -1) {
309 error("setsockopt socket %d IP_TOS %d: %s",
310 fd
, tos
, strerror(errno
));
316 debug3_f("set socket %d IPV6_TCLASS 0x%02x", fd
, tos
);
317 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
,
318 &tos
, sizeof(tos
)) == -1) {
319 error("setsockopt socket %d IPV6_TCLASS %d: %s",
320 fd
, tos
, strerror(errno
));
322 # endif /* IPV6_TCLASS */
325 debug2_f("unsupported socket family %d", af
);
328 #endif /* IP_TOS_IS_BROKEN */
332 * Wait up to *timeoutp milliseconds for events on fd. Updates
333 * *timeoutp with time remaining.
334 * Returns 0 if fd ready or -1 on timeout or error (see errno).
337 waitfd(int fd
, int *timeoutp
, short events
, volatile sig_atomic_t *stop
)
340 struct timespec timeout
;
342 sigset_t nsigset
, osigset
;
344 if (timeoutp
&& *timeoutp
== -1)
348 ptimeout_init(&timeout
);
349 if (timeoutp
!= NULL
)
350 ptimeout_deadline_ms(&timeout
, *timeoutp
);
352 sigfillset(&nsigset
);
353 for (; timeoutp
== NULL
|| *timeoutp
>= 0;) {
355 sigprocmask(SIG_BLOCK
, &nsigset
, &osigset
);
357 sigprocmask(SIG_SETMASK
, &osigset
, NULL
);
362 r
= ppoll(&pfd
, 1, ptimeout_get_tsp(&timeout
),
363 stop
!= NULL
? &osigset
: NULL
);
366 sigprocmask(SIG_SETMASK
, &osigset
, NULL
);
368 *timeoutp
= ptimeout_get_ms(&timeout
);
372 else if (r
== -1 && errno
!= EAGAIN
&& errno
!= EINTR
)
383 * Wait up to *timeoutp milliseconds for fd to be readable. Updates
384 * *timeoutp with time remaining.
385 * Returns 0 if fd ready or -1 on timeout or error (see errno).
388 waitrfd(int fd
, int *timeoutp
, volatile sig_atomic_t *stop
) {
389 return waitfd(fd
, timeoutp
, POLLIN
, stop
);
393 * Attempt a non-blocking connect(2) to the specified address, waiting up to
394 * *timeoutp milliseconds for the connection to complete. If the timeout is
395 * <=0, then wait indefinitely.
397 * Returns 0 on success or -1 on failure.
400 timeout_connect(int sockfd
, const struct sockaddr
*serv_addr
,
401 socklen_t addrlen
, int *timeoutp
)
404 socklen_t optlen
= sizeof(optval
);
406 /* No timeout: just do a blocking connect() */
407 if (timeoutp
== NULL
|| *timeoutp
<= 0)
408 return connect(sockfd
, serv_addr
, addrlen
);
410 set_nonblock(sockfd
);
412 if (connect(sockfd
, serv_addr
, addrlen
) == 0) {
413 /* Succeeded already? */
414 unset_nonblock(sockfd
);
416 } else if (errno
== EINTR
)
418 else if (errno
!= EINPROGRESS
)
423 if (waitfd(sockfd
, timeoutp
, POLLIN
| POLLOUT
, NULL
) == -1)
426 /* Completed or failed */
427 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, &optval
, &optlen
) == -1) {
428 debug("getsockopt: %s", strerror(errno
));
435 unset_nonblock(sockfd
);
439 /* Characters considered whitespace in strsep calls. */
440 #define WHITESPACE " \t\r\n"
443 /* return next token in configuration line */
445 strdelim_internal(char **s
, int split_equals
)
456 split_equals
? WHITESPACE QUOTE
"=" : WHITESPACE QUOTE
);
461 memmove(*s
, *s
+ 1, strlen(*s
)); /* move nul too */
462 /* Find matching quote */
463 if ((*s
= strpbrk(*s
, QUOTE
)) == NULL
) {
464 return (NULL
); /* no matching quote */
467 *s
+= strspn(*s
+ 1, WHITESPACE
) + 1;
472 /* Allow only one '=' to be skipped */
473 if (split_equals
&& *s
[0] == '=')
477 /* Skip any extra whitespace after first token */
478 *s
+= strspn(*s
+ 1, WHITESPACE
) + 1;
479 if (split_equals
&& *s
[0] == '=' && !wspace
)
480 *s
+= strspn(*s
+ 1, WHITESPACE
) + 1;
486 * Return next token in configuration line; splts on whitespace or a
487 * single '=' character.
492 return strdelim_internal(s
, 1);
496 * Return next token in configuration line; splts on whitespace only.
501 return strdelim_internal(s
, 0);
505 pwcopy(struct passwd
*pw
)
507 struct passwd
*copy
= xcalloc(1, sizeof(*copy
));
509 copy
->pw_name
= xstrdup(pw
->pw_name
);
510 copy
->pw_passwd
= xstrdup(pw
->pw_passwd
== NULL
? "*" : pw
->pw_passwd
);
511 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
512 copy
->pw_gecos
= xstrdup(pw
->pw_gecos
);
514 copy
->pw_uid
= pw
->pw_uid
;
515 copy
->pw_gid
= pw
->pw_gid
;
516 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
517 copy
->pw_expire
= pw
->pw_expire
;
519 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
520 copy
->pw_change
= pw
->pw_change
;
522 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
523 copy
->pw_class
= xstrdup(pw
->pw_class
);
525 copy
->pw_dir
= xstrdup(pw
->pw_dir
);
526 copy
->pw_shell
= xstrdup(pw
->pw_shell
);
531 * Convert ASCII string to TCP/IP port number.
532 * Port must be >=0 and <=65535.
533 * Return -1 if invalid.
536 a2port(const char *s
)
542 port
= strtonum(s
, 0, 65535, &errstr
);
545 if ((se
= getservbyname(s
, "tcp")) != NULL
)
546 return ntohs(se
->s_port
);
551 a2tun(const char *s
, int *remote
)
553 const char *errstr
= NULL
;
557 if (remote
!= NULL
) {
558 *remote
= SSH_TUNID_ANY
;
560 if ((ep
= strchr(sp
, ':')) == NULL
) {
562 return (a2tun(s
, NULL
));
565 *remote
= a2tun(ep
, NULL
);
566 tun
= a2tun(sp
, NULL
);
568 return (*remote
== SSH_TUNID_ERR
? *remote
: tun
);
571 if (strcasecmp(s
, "any") == 0)
572 return (SSH_TUNID_ANY
);
574 tun
= strtonum(s
, 0, SSH_TUNID_MAX
, &errstr
);
576 return (SSH_TUNID_ERR
);
582 #define MINUTES (SECONDS * 60)
583 #define HOURS (MINUTES * 60)
584 #define DAYS (HOURS * 24)
585 #define WEEKS (DAYS * 7)
590 while (isdigit((unsigned char)*s
))
596 * Convert a time string into seconds; format is
600 * Valid time qualifiers are:
614 * Return -1 if time string is invalid.
617 convtime(const char *s
)
619 int secs
, total
= 0, multiplier
;
620 char *p
, *os
, *np
, c
= 0;
623 if (s
== NULL
|| *s
== '\0')
625 p
= os
= strdup(s
); /* deal with const */
635 secs
= (int)strtonum(p
, 0, INT_MAX
, &errstr
);
650 multiplier
= MINUTES
;
667 if (secs
> INT_MAX
/ multiplier
)
670 if (total
> INT_MAX
- secs
)
688 fmt_timeframe(time_t t
)
691 static char tfbuf
[TF_BUFS
][TF_LEN
]; /* ring buffer */
693 unsigned int sec
, min
, hrs
, day
;
694 unsigned long long week
;
712 snprintf(buf
, TF_LEN
, "%02lluw%01ud%02uh", week
, day
, hrs
);
714 snprintf(buf
, TF_LEN
, "%01ud%02uh%02um", day
, hrs
, min
);
716 snprintf(buf
, TF_LEN
, "%02u:%02u:%02u", hrs
, min
, sec
);
722 * Returns a standardized host+port identifier string.
723 * Caller must free returned string.
726 put_host_port(const char *host
, u_short port
)
730 if (port
== 0 || port
== SSH_DEFAULT_PORT
)
731 return(xstrdup(host
));
732 if (asprintf(&hoststr
, "[%s]:%d", host
, (int)port
) == -1)
733 fatal("put_host_port: asprintf: %s", strerror(errno
));
734 debug3("put_host_port: %s", hoststr
);
739 * Search for next delimiter between hostnames/addresses and ports.
740 * Argument may be modified (for termination).
741 * Returns *cp if parsing succeeds.
742 * *cp is set to the start of the next field, if one was found.
743 * The delimiter char, if present, is stored in delim.
744 * If this is the last field, *cp is set to NULL.
747 hpdelim2(char **cp
, char *delim
)
751 if (cp
== NULL
|| *cp
== NULL
)
756 if ((s
= strchr(s
, ']')) == NULL
)
760 } else if ((s
= strpbrk(s
, ":/")) == NULL
)
761 s
= *cp
+ strlen(*cp
); /* skip to end (see first case below) */
765 *cp
= NULL
; /* no more fields*/
772 *s
= '\0'; /* terminate */
783 /* The common case: only accept colon as delimiter. */
787 char *r
, delim
= '\0';
789 r
= hpdelim2(cp
, &delim
);
796 cleanhostname(char *host
)
798 if (*host
== '[' && host
[strlen(host
) - 1] == ']') {
799 host
[strlen(host
) - 1] = '\0';
810 if (*cp
== ':') /* Leading colon is part of file name. */
816 if (*cp
== '@' && *(cp
+1) == '[')
818 if (*cp
== ']' && *(cp
+1) == ':' && flag
)
820 if (*cp
== ':' && !flag
)
829 * Parse a [user@]host:[path] string.
830 * Caller must free returned user, host and path.
831 * Any of the pointer return arguments may be NULL (useful for syntax checking).
832 * If user was not specified then *userp will be set to NULL.
833 * If host was not specified then *hostp will be set to NULL.
834 * If path was not specified then *pathp will be set to ".".
835 * Returns 0 on success, -1 on failure.
838 parse_user_host_path(const char *s
, char **userp
, char **hostp
, char **pathp
)
840 char *user
= NULL
, *host
= NULL
, *path
= NULL
;
853 /* Check for remote syntax: [user@]host:[path] */
854 if ((tmp
= colon(sdup
)) == NULL
)
857 /* Extract optional path */
863 /* Extract optional user and mandatory host */
864 tmp
= strrchr(sdup
, '@');
867 host
= xstrdup(cleanhostname(tmp
));
869 user
= xstrdup(sdup
);
871 host
= xstrdup(cleanhostname(sdup
));
898 * Parse a [user@]host[:port] string.
899 * Caller must free returned user and host.
900 * Any of the pointer return arguments may be NULL (useful for syntax checking).
901 * If user was not specified then *userp will be set to NULL.
902 * If port was not specified then *portp will be -1.
903 * Returns 0 on success, -1 on failure.
906 parse_user_host_port(const char *s
, char **userp
, char **hostp
, int *portp
)
908 char *sdup
, *cp
, *tmp
;
909 char *user
= NULL
, *host
= NULL
;
910 int port
= -1, ret
= -1;
919 if ((sdup
= tmp
= strdup(s
)) == NULL
)
921 /* Extract optional username */
922 if ((cp
= strrchr(tmp
, '@')) != NULL
) {
926 if ((user
= strdup(tmp
)) == NULL
)
930 /* Extract mandatory hostname */
931 if ((cp
= hpdelim(&tmp
)) == NULL
|| *cp
== '\0')
933 host
= xstrdup(cleanhostname(cp
));
934 /* Convert and verify optional port */
935 if (tmp
!= NULL
&& *tmp
!= '\0') {
936 if ((port
= a2port(tmp
)) <= 0)
959 * Converts a two-byte hex string to decimal.
960 * Returns the decimal value or -1 for invalid input.
963 hexchar(const char *s
)
965 unsigned char result
[2];
968 for (i
= 0; i
< 2; i
++) {
969 if (s
[i
] >= '0' && s
[i
] <= '9')
970 result
[i
] = (unsigned char)(s
[i
] - '0');
971 else if (s
[i
] >= 'a' && s
[i
] <= 'f')
972 result
[i
] = (unsigned char)(s
[i
] - 'a') + 10;
973 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
974 result
[i
] = (unsigned char)(s
[i
] - 'A') + 10;
978 return (result
[0] << 4) | result
[1];
982 * Decode an url-encoded string.
983 * Returns a newly allocated string on success or NULL on failure.
986 urldecode(const char *src
)
992 if ((srclen
= strlen(src
)) >= SIZE_MAX
)
993 fatal_f("input too large");
994 ret
= xmalloc(srclen
+ 1);
995 for (dst
= ret
; *src
!= '\0'; src
++) {
1001 if (!isxdigit((unsigned char)src
[1]) ||
1002 !isxdigit((unsigned char)src
[2]) ||
1003 (ch
= hexchar(src
+ 1)) == -1) {
1021 * Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI.
1022 * See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
1023 * Either user or path may be url-encoded (but not host or port).
1024 * Caller must free returned user, host and path.
1025 * Any of the pointer return arguments may be NULL (useful for syntax checking)
1026 * but the scheme must always be specified.
1027 * If user was not specified then *userp will be set to NULL.
1028 * If port was not specified then *portp will be -1.
1029 * If path was not specified then *pathp will be set to NULL.
1030 * Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri.
1033 parse_uri(const char *scheme
, const char *uri
, char **userp
, char **hostp
,
1034 int *portp
, char **pathp
)
1036 char *uridup
, *cp
, *tmp
, ch
;
1037 char *user
= NULL
, *host
= NULL
, *path
= NULL
;
1038 int port
= -1, ret
= -1;
1041 len
= strlen(scheme
);
1042 if (strncmp(uri
, scheme
, len
) != 0 || strncmp(uri
+ len
, "://", 3) != 0)
1055 uridup
= tmp
= xstrdup(uri
);
1057 /* Extract optional ssh-info (username + connection params) */
1058 if ((cp
= strchr(tmp
, '@')) != NULL
) {
1062 /* Extract username and connection params */
1063 if ((delim
= strchr(tmp
, ';')) != NULL
) {
1064 /* Just ignore connection params for now */
1068 /* Empty username */
1071 if ((user
= urldecode(tmp
)) == NULL
)
1076 /* Extract mandatory hostname */
1077 if ((cp
= hpdelim2(&tmp
, &ch
)) == NULL
|| *cp
== '\0')
1079 host
= xstrdup(cleanhostname(cp
));
1080 if (!valid_domain(host
, 0, NULL
))
1083 if (tmp
!= NULL
&& *tmp
!= '\0') {
1085 /* Convert and verify port. */
1086 if ((cp
= strchr(tmp
, '/')) != NULL
)
1088 if ((port
= a2port(tmp
)) <= 0)
1090 tmp
= cp
? cp
+ 1 : NULL
;
1092 if (tmp
!= NULL
&& *tmp
!= '\0') {
1093 /* Extract optional path */
1094 if ((path
= urldecode(tmp
)) == NULL
)
1100 if (userp
!= NULL
) {
1104 if (hostp
!= NULL
) {
1110 if (pathp
!= NULL
) {
1123 /* function to assist building execv() arguments */
1125 addargs(arglist
*args
, char *fmt
, ...)
1133 r
= vasprintf(&cp
, fmt
, ap
);
1136 fatal_f("argument too long");
1138 nalloc
= args
->nalloc
;
1139 if (args
->list
== NULL
) {
1142 } else if (args
->num
> (256 * 1024))
1143 fatal_f("too many arguments");
1144 else if (args
->num
>= args
->nalloc
)
1145 fatal_f("arglist corrupt");
1146 else if (args
->num
+2 >= nalloc
)
1149 args
->list
= xrecallocarray(args
->list
, args
->nalloc
,
1150 nalloc
, sizeof(char *));
1151 args
->nalloc
= nalloc
;
1152 args
->list
[args
->num
++] = cp
;
1153 args
->list
[args
->num
] = NULL
;
1157 replacearg(arglist
*args
, u_int which
, char *fmt
, ...)
1164 r
= vasprintf(&cp
, fmt
, ap
);
1167 fatal_f("argument too long");
1168 if (args
->list
== NULL
|| args
->num
>= args
->nalloc
)
1169 fatal_f("arglist corrupt");
1171 if (which
>= args
->num
)
1172 fatal_f("tried to replace invalid arg %d >= %d",
1174 free(args
->list
[which
]);
1175 args
->list
[which
] = cp
;
1179 freeargs(arglist
*args
)
1185 if (args
->list
!= NULL
&& args
->num
< args
->nalloc
) {
1186 for (i
= 0; i
< args
->num
; i
++)
1187 free(args
->list
[i
]);
1190 args
->nalloc
= args
->num
= 0;
1195 * Expands tildes in the file name. Returns data allocated by xmalloc.
1196 * Warning: this calls getpw*.
1199 tilde_expand(const char *filename
, uid_t uid
, char **retp
)
1201 char *ocopy
= NULL
, *copy
, *s
= NULL
;
1202 const char *path
= NULL
, *user
= NULL
;
1205 int ret
= -1, r
, slash
;
1208 if (*filename
!= '~') {
1209 *retp
= xstrdup(filename
);
1212 ocopy
= copy
= xstrdup(filename
+ 1);
1214 if (*copy
== '\0') /* ~ */
1216 else if (*copy
== '/') {
1217 copy
+= strspn(copy
, "/");
1219 path
= NULL
; /* ~/ */
1221 path
= copy
; /* ~/path */
1224 if ((path
= strchr(copy
, '/')) != NULL
) {
1225 copy
[path
- copy
] = '\0';
1227 path
+= strspn(path
, "/");
1228 if (*path
== '\0') /* ~user/ */
1230 /* else ~user/path */
1235 if ((pw
= getpwnam(user
)) == NULL
) {
1236 error_f("No such user %s", user
);
1239 } else if ((pw
= getpwuid(uid
)) == NULL
) {
1240 error_f("No such uid %ld", (long)uid
);
1244 /* Make sure directory has a trailing '/' */
1245 slash
= (len
= strlen(pw
->pw_dir
)) == 0 || pw
->pw_dir
[len
- 1] != '/';
1247 if ((r
= xasprintf(&s
, "%s%s%s", pw
->pw_dir
,
1248 slash
? "/" : "", path
!= NULL
? path
: "")) <= 0) {
1249 error_f("xasprintf failed");
1252 if (r
>= PATH_MAX
) {
1253 error_f("Path too long");
1267 tilde_expand_filename(const char *filename
, uid_t uid
)
1271 if (tilde_expand(filename
, uid
, &ret
) != 0)
1277 * Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT}
1278 * substitutions. A number of escapes may be specified as
1279 * (char *escape_chars, char *replacement) pairs. The list must be terminated
1280 * by a NULL escape_char. Returns replaced string in memory allocated by
1281 * xmalloc which the caller must free.
1284 vdollar_percent_expand(int *parseerror
, int dollar
, int percent
,
1285 const char *string
, va_list ap
)
1287 #define EXPAND_MAX_KEYS 64
1288 u_int num_keys
= 0, i
;
1292 } keys
[EXPAND_MAX_KEYS
];
1294 int r
, missingvar
= 0;
1295 char *ret
= NULL
, *var
, *varend
, *val
;
1298 if ((buf
= sshbuf_new()) == NULL
)
1299 fatal_f("sshbuf_new failed");
1300 if (parseerror
== NULL
)
1301 fatal_f("null parseerror arg");
1304 /* Gather keys if we're doing percent expansion. */
1306 for (num_keys
= 0; num_keys
< EXPAND_MAX_KEYS
; num_keys
++) {
1307 keys
[num_keys
].key
= va_arg(ap
, char *);
1308 if (keys
[num_keys
].key
== NULL
)
1310 keys
[num_keys
].repl
= va_arg(ap
, char *);
1311 if (keys
[num_keys
].repl
== NULL
) {
1312 fatal_f("NULL replacement for token %s",
1313 keys
[num_keys
].key
);
1316 if (num_keys
== EXPAND_MAX_KEYS
&& va_arg(ap
, char *) != NULL
)
1317 fatal_f("too many keys");
1319 fatal_f("percent expansion without token list");
1323 for (i
= 0; *string
!= '\0'; string
++) {
1324 /* Optionally process ${ENVIRONMENT} expansions. */
1325 if (dollar
&& string
[0] == '$' && string
[1] == '{') {
1326 string
+= 2; /* skip over '${' */
1327 if ((varend
= strchr(string
, '}')) == NULL
) {
1328 error_f("environment variable '%s' missing "
1329 "closing '}'", string
);
1332 len
= varend
- string
;
1334 error_f("zero-length environment variable");
1337 var
= xmalloc(len
+ 1);
1338 (void)strlcpy(var
, string
, len
+ 1);
1339 if ((val
= getenv(var
)) == NULL
) {
1340 error_f("env var ${%s} has no value", var
);
1343 debug3_f("expand ${%s} -> '%s'", var
, val
);
1344 if ((r
= sshbuf_put(buf
, val
, strlen(val
))) !=0)
1345 fatal_fr(r
, "sshbuf_put ${}");
1353 * Process percent expansions if we have a list of TOKENs.
1354 * If we're not doing percent expansion everything just gets
1357 if (*string
!= '%' || !percent
) {
1359 if ((r
= sshbuf_put_u8(buf
, *string
)) != 0)
1360 fatal_fr(r
, "sshbuf_put_u8 %%");
1367 if (*string
== '\0') {
1368 error_f("invalid format");
1371 for (i
= 0; i
< num_keys
; i
++) {
1372 if (strchr(keys
[i
].key
, *string
) != NULL
) {
1373 if ((r
= sshbuf_put(buf
, keys
[i
].repl
,
1374 strlen(keys
[i
].repl
))) != 0)
1375 fatal_fr(r
, "sshbuf_put %%-repl");
1379 if (i
>= num_keys
) {
1380 error_f("unknown key %%%c", *string
);
1384 if (!missingvar
&& (ret
= sshbuf_dup_string(buf
)) == NULL
)
1385 fatal_f("sshbuf_dup_string failed");
1389 return *parseerror
? NULL
: ret
;
1390 #undef EXPAND_MAX_KEYS
1394 * Expand only environment variables.
1395 * Note that although this function is variadic like the other similar
1396 * functions, any such arguments will be unused.
1400 dollar_expand(int *parseerr
, const char *string
, ...)
1406 va_start(ap
, string
);
1407 ret
= vdollar_percent_expand(&err
, 1, 0, string
, ap
);
1409 if (parseerr
!= NULL
)
1415 * Returns expanded string or NULL if a specified environment variable is
1416 * not defined, or calls fatal if the string is invalid.
1419 percent_expand(const char *string
, ...)
1425 va_start(ap
, string
);
1426 ret
= vdollar_percent_expand(&err
, 0, 1, string
, ap
);
1434 * Returns expanded string or NULL if a specified environment variable is
1435 * not defined, or calls fatal if the string is invalid.
1438 percent_dollar_expand(const char *string
, ...)
1444 va_start(ap
, string
);
1445 ret
= vdollar_percent_expand(&err
, 1, 1, string
, ap
);
1453 tun_open(int tun
, int mode
, char **ifname
)
1455 #if defined(CUSTOM_SYS_TUN_OPEN)
1456 return (sys_tun_open(tun
, mode
, ifname
));
1457 #elif defined(SSH_TUN_OPENBSD)
1461 const char *tunbase
= "tun";
1466 if (mode
== SSH_TUNMODE_ETHERNET
)
1469 /* Open the tunnel device */
1470 if (tun
<= SSH_TUNID_MAX
) {
1471 snprintf(name
, sizeof(name
), "/dev/%s%d", tunbase
, tun
);
1472 fd
= open(name
, O_RDWR
);
1473 } else if (tun
== SSH_TUNID_ANY
) {
1474 for (tun
= 100; tun
>= 0; tun
--) {
1475 snprintf(name
, sizeof(name
), "/dev/%s%d",
1477 if ((fd
= open(name
, O_RDWR
)) >= 0)
1481 debug_f("invalid tunnel %u", tun
);
1486 debug_f("%s open: %s", name
, strerror(errno
));
1490 debug_f("%s mode %d fd %d", name
, mode
, fd
);
1492 /* Bring interface up if it is not already */
1493 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d", tunbase
, tun
);
1494 if ((sock
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1)
1497 if (ioctl(sock
, SIOCGIFFLAGS
, &ifr
) == -1) {
1498 debug_f("get interface %s flags: %s", ifr
.ifr_name
,
1503 if (!(ifr
.ifr_flags
& IFF_UP
)) {
1504 ifr
.ifr_flags
|= IFF_UP
;
1505 if (ioctl(sock
, SIOCSIFFLAGS
, &ifr
) == -1) {
1506 debug_f("activate interface %s: %s", ifr
.ifr_name
,
1513 *ifname
= xstrdup(ifr
.ifr_name
);
1525 error("Tunnel interfaces are not supported on this platform");
1531 sanitise_stdfd(void)
1535 if ((nullfd
= dupfd
= open(_PATH_DEVNULL
, O_RDWR
)) == -1) {
1536 fprintf(stderr
, "Couldn't open /dev/null: %s\n",
1540 while (++dupfd
<= STDERR_FILENO
) {
1541 /* Only populate closed fds. */
1542 if (fcntl(dupfd
, F_GETFL
) == -1 && errno
== EBADF
) {
1543 if (dup2(nullfd
, dupfd
) == -1) {
1544 fprintf(stderr
, "dup2: %s\n", strerror(errno
));
1549 if (nullfd
> STDERR_FILENO
)
1554 tohex(const void *vp
, size_t l
)
1556 const u_char
*p
= (const u_char
*)vp
;
1561 return xstrdup("tohex: length > 65536");
1565 for (i
= 0; i
< l
; i
++) {
1566 snprintf(b
, sizeof(b
), "%02x", p
[i
]);
1573 * Extend string *sp by the specified format. If *sp is not NULL (or empty),
1574 * then the separator 'sep' will be prepended before the formatted arguments.
1575 * Extended strings are heap allocated.
1578 xextendf(char **sp
, const char *sep
, const char *fmt
, ...)
1584 xvasprintf(&tmp1
, fmt
, ap
);
1587 if (*sp
== NULL
|| **sp
== '\0') {
1592 xasprintf(&tmp2
, "%s%s%s", *sp
, sep
== NULL
? "" : sep
, tmp1
);
1600 get_u64(const void *vp
)
1602 const u_char
*p
= (const u_char
*)vp
;
1605 v
= (u_int64_t
)p
[0] << 56;
1606 v
|= (u_int64_t
)p
[1] << 48;
1607 v
|= (u_int64_t
)p
[2] << 40;
1608 v
|= (u_int64_t
)p
[3] << 32;
1609 v
|= (u_int64_t
)p
[4] << 24;
1610 v
|= (u_int64_t
)p
[5] << 16;
1611 v
|= (u_int64_t
)p
[6] << 8;
1612 v
|= (u_int64_t
)p
[7];
1618 get_u32(const void *vp
)
1620 const u_char
*p
= (const u_char
*)vp
;
1623 v
= (u_int32_t
)p
[0] << 24;
1624 v
|= (u_int32_t
)p
[1] << 16;
1625 v
|= (u_int32_t
)p
[2] << 8;
1626 v
|= (u_int32_t
)p
[3];
1632 get_u32_le(const void *vp
)
1634 const u_char
*p
= (const u_char
*)vp
;
1637 v
= (u_int32_t
)p
[0];
1638 v
|= (u_int32_t
)p
[1] << 8;
1639 v
|= (u_int32_t
)p
[2] << 16;
1640 v
|= (u_int32_t
)p
[3] << 24;
1646 get_u16(const void *vp
)
1648 const u_char
*p
= (const u_char
*)vp
;
1651 v
= (u_int16_t
)p
[0] << 8;
1652 v
|= (u_int16_t
)p
[1];
1658 put_u64(void *vp
, u_int64_t v
)
1660 u_char
*p
= (u_char
*)vp
;
1662 p
[0] = (u_char
)(v
>> 56) & 0xff;
1663 p
[1] = (u_char
)(v
>> 48) & 0xff;
1664 p
[2] = (u_char
)(v
>> 40) & 0xff;
1665 p
[3] = (u_char
)(v
>> 32) & 0xff;
1666 p
[4] = (u_char
)(v
>> 24) & 0xff;
1667 p
[5] = (u_char
)(v
>> 16) & 0xff;
1668 p
[6] = (u_char
)(v
>> 8) & 0xff;
1669 p
[7] = (u_char
)v
& 0xff;
1673 put_u32(void *vp
, u_int32_t v
)
1675 u_char
*p
= (u_char
*)vp
;
1677 p
[0] = (u_char
)(v
>> 24) & 0xff;
1678 p
[1] = (u_char
)(v
>> 16) & 0xff;
1679 p
[2] = (u_char
)(v
>> 8) & 0xff;
1680 p
[3] = (u_char
)v
& 0xff;
1684 put_u32_le(void *vp
, u_int32_t v
)
1686 u_char
*p
= (u_char
*)vp
;
1688 p
[0] = (u_char
)v
& 0xff;
1689 p
[1] = (u_char
)(v
>> 8) & 0xff;
1690 p
[2] = (u_char
)(v
>> 16) & 0xff;
1691 p
[3] = (u_char
)(v
>> 24) & 0xff;
1695 put_u16(void *vp
, u_int16_t v
)
1697 u_char
*p
= (u_char
*)vp
;
1699 p
[0] = (u_char
)(v
>> 8) & 0xff;
1700 p
[1] = (u_char
)v
& 0xff;
1704 ms_subtract_diff(struct timeval
*start
, int *ms
)
1706 struct timeval diff
, finish
;
1708 monotime_tv(&finish
);
1709 timersub(&finish
, start
, &diff
);
1710 *ms
-= (diff
.tv_sec
* 1000) + (diff
.tv_usec
/ 1000);
1714 ms_to_timespec(struct timespec
*ts
, int ms
)
1718 ts
->tv_sec
= ms
/ 1000;
1719 ts
->tv_nsec
= (ms
% 1000) * 1000 * 1000;
1723 monotime_ts(struct timespec
*ts
)
1726 #if defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_BOOTTIME) || \
1727 defined(CLOCK_MONOTONIC) || defined(CLOCK_REALTIME))
1728 static int gettime_failed
= 0;
1730 if (!gettime_failed
) {
1731 # ifdef CLOCK_BOOTTIME
1732 if (clock_gettime(CLOCK_BOOTTIME
, ts
) == 0)
1734 # endif /* CLOCK_BOOTTIME */
1735 # ifdef CLOCK_MONOTONIC
1736 if (clock_gettime(CLOCK_MONOTONIC
, ts
) == 0)
1738 # endif /* CLOCK_MONOTONIC */
1739 # ifdef CLOCK_REALTIME
1740 /* Not monotonic, but we're almost out of options here. */
1741 if (clock_gettime(CLOCK_REALTIME
, ts
) == 0)
1743 # endif /* CLOCK_REALTIME */
1744 debug3("clock_gettime: %s", strerror(errno
));
1747 #endif /* HAVE_CLOCK_GETTIME && (BOOTTIME || MONOTONIC || REALTIME) */
1748 gettimeofday(&tv
, NULL
);
1749 ts
->tv_sec
= tv
.tv_sec
;
1750 ts
->tv_nsec
= (long)tv
.tv_usec
* 1000;
1754 monotime_tv(struct timeval
*tv
)
1759 tv
->tv_sec
= ts
.tv_sec
;
1760 tv
->tv_usec
= ts
.tv_nsec
/ 1000;
1773 monotime_double(void)
1778 return ts
.tv_sec
+ ((double)ts
.tv_nsec
/ 1000000000);
1782 bandwidth_limit_init(struct bwlimit
*bw
, u_int64_t kbps
, size_t buflen
)
1784 bw
->buflen
= buflen
;
1786 bw
->thresh
= buflen
;
1788 timerclear(&bw
->bwstart
);
1789 timerclear(&bw
->bwend
);
1792 /* Callback from read/write loop to insert bandwidth-limiting delays */
1794 bandwidth_limit(struct bwlimit
*bw
, size_t read_len
)
1797 struct timespec ts
, rm
;
1799 bw
->lamt
+= read_len
;
1800 if (!timerisset(&bw
->bwstart
)) {
1801 monotime_tv(&bw
->bwstart
);
1804 if (bw
->lamt
< bw
->thresh
)
1807 monotime_tv(&bw
->bwend
);
1808 timersub(&bw
->bwend
, &bw
->bwstart
, &bw
->bwend
);
1809 if (!timerisset(&bw
->bwend
))
1813 waitlen
= (double)1000000L * bw
->lamt
/ bw
->rate
;
1815 bw
->bwstart
.tv_sec
= waitlen
/ 1000000L;
1816 bw
->bwstart
.tv_usec
= waitlen
% 1000000L;
1818 if (timercmp(&bw
->bwstart
, &bw
->bwend
, >)) {
1819 timersub(&bw
->bwstart
, &bw
->bwend
, &bw
->bwend
);
1821 /* Adjust the wait time */
1822 if (bw
->bwend
.tv_sec
) {
1824 if (bw
->thresh
< bw
->buflen
/ 4)
1825 bw
->thresh
= bw
->buflen
/ 4;
1826 } else if (bw
->bwend
.tv_usec
< 10000) {
1828 if (bw
->thresh
> bw
->buflen
* 8)
1829 bw
->thresh
= bw
->buflen
* 8;
1832 TIMEVAL_TO_TIMESPEC(&bw
->bwend
, &ts
);
1833 while (nanosleep(&ts
, &rm
) == -1) {
1841 monotime_tv(&bw
->bwstart
);
1844 /* Make a template filename for mk[sd]temp() */
1846 mktemp_proto(char *s
, size_t len
)
1851 if ((tmpdir
= getenv("TMPDIR")) != NULL
) {
1852 r
= snprintf(s
, len
, "%s/ssh-XXXXXXXXXXXX", tmpdir
);
1853 if (r
> 0 && (size_t)r
< len
)
1856 r
= snprintf(s
, len
, "/tmp/ssh-XXXXXXXXXXXX");
1857 if (r
< 0 || (size_t)r
>= len
)
1858 fatal_f("template string too short");
1861 static const struct {
1865 { "none", INT_MAX
}, /* can't use 0 here; that's CS0 */
1866 { "af11", IPTOS_DSCP_AF11
},
1867 { "af12", IPTOS_DSCP_AF12
},
1868 { "af13", IPTOS_DSCP_AF13
},
1869 { "af21", IPTOS_DSCP_AF21
},
1870 { "af22", IPTOS_DSCP_AF22
},
1871 { "af23", IPTOS_DSCP_AF23
},
1872 { "af31", IPTOS_DSCP_AF31
},
1873 { "af32", IPTOS_DSCP_AF32
},
1874 { "af33", IPTOS_DSCP_AF33
},
1875 { "af41", IPTOS_DSCP_AF41
},
1876 { "af42", IPTOS_DSCP_AF42
},
1877 { "af43", IPTOS_DSCP_AF43
},
1878 { "cs0", IPTOS_DSCP_CS0
},
1879 { "cs1", IPTOS_DSCP_CS1
},
1880 { "cs2", IPTOS_DSCP_CS2
},
1881 { "cs3", IPTOS_DSCP_CS3
},
1882 { "cs4", IPTOS_DSCP_CS4
},
1883 { "cs5", IPTOS_DSCP_CS5
},
1884 { "cs6", IPTOS_DSCP_CS6
},
1885 { "cs7", IPTOS_DSCP_CS7
},
1886 { "ef", IPTOS_DSCP_EF
},
1887 { "le", IPTOS_DSCP_LE
},
1888 { "lowdelay", IPTOS_LOWDELAY
},
1889 { "throughput", IPTOS_THROUGHPUT
},
1890 { "reliability", IPTOS_RELIABILITY
},
1895 parse_ipqos(const char *cp
)
1903 for (i
= 0; ipqos
[i
].name
!= NULL
; i
++) {
1904 if (strcasecmp(cp
, ipqos
[i
].name
) == 0)
1905 return ipqos
[i
].value
;
1907 /* Try parsing as an integer */
1908 val
= (int)strtonum(cp
, 0, 255, &errstr
);
1915 iptos2str(int iptos
)
1918 static char iptos_str
[sizeof "0xff"];
1920 for (i
= 0; ipqos
[i
].name
!= NULL
; i
++) {
1921 if (ipqos
[i
].value
== iptos
)
1922 return ipqos
[i
].name
;
1924 snprintf(iptos_str
, sizeof iptos_str
, "0x%02x", iptos
);
1932 *s
= tolower((u_char
)*s
);
1936 unix_listener(const char *path
, int backlog
, int unlink_first
)
1938 struct sockaddr_un sunaddr
;
1939 int saved_errno
, sock
;
1941 memset(&sunaddr
, 0, sizeof(sunaddr
));
1942 sunaddr
.sun_family
= AF_UNIX
;
1943 if (strlcpy(sunaddr
.sun_path
, path
,
1944 sizeof(sunaddr
.sun_path
)) >= sizeof(sunaddr
.sun_path
)) {
1945 error_f("path \"%s\" too long for Unix domain socket", path
);
1946 errno
= ENAMETOOLONG
;
1950 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1952 saved_errno
= errno
;
1953 error_f("socket: %.100s", strerror(errno
));
1954 errno
= saved_errno
;
1957 if (unlink_first
== 1) {
1958 if (unlink(path
) != 0 && errno
!= ENOENT
)
1959 error("unlink(%s): %.100s", path
, strerror(errno
));
1961 if (bind(sock
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
)) == -1) {
1962 saved_errno
= errno
;
1963 error_f("cannot bind to path %s: %s", path
, strerror(errno
));
1965 errno
= saved_errno
;
1968 if (listen(sock
, backlog
) == -1) {
1969 saved_errno
= errno
;
1970 error_f("cannot listen on path %s: %s", path
, strerror(errno
));
1973 errno
= saved_errno
;
1980 sock_set_v6only(int s
)
1982 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
1985 debug3("%s: set socket %d IPV6_V6ONLY", __func__
, s
);
1986 if (setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
)) == -1)
1987 error("setsockopt IPV6_V6ONLY: %s", strerror(errno
));
1992 * Compares two strings that maybe be NULL. Returns non-zero if strings
1993 * are both NULL or are identical, returns zero otherwise.
1996 strcmp_maybe_null(const char *a
, const char *b
)
1998 if ((a
== NULL
&& b
!= NULL
) || (a
!= NULL
&& b
== NULL
))
2000 if (a
!= NULL
&& strcmp(a
, b
) != 0)
2006 * Compare two forwards, returning non-zero if they are identical or
2010 forward_equals(const struct Forward
*a
, const struct Forward
*b
)
2012 if (strcmp_maybe_null(a
->listen_host
, b
->listen_host
) == 0)
2014 if (a
->listen_port
!= b
->listen_port
)
2016 if (strcmp_maybe_null(a
->listen_path
, b
->listen_path
) == 0)
2018 if (strcmp_maybe_null(a
->connect_host
, b
->connect_host
) == 0)
2020 if (a
->connect_port
!= b
->connect_port
)
2022 if (strcmp_maybe_null(a
->connect_path
, b
->connect_path
) == 0)
2024 /* allocated_port and handle are not checked */
2028 /* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */
2030 permitopen_port(const char *p
)
2034 if (strcmp(p
, "*") == 0)
2035 return FWD_PERMIT_ANY_PORT
;
2036 if ((port
= a2port(p
)) > 0)
2041 /* returns 1 if process is already daemonized, 0 otherwise */
2047 if ((fd
= open(_PATH_TTY
, O_RDONLY
| O_NOCTTY
)) >= 0) {
2049 return 0; /* have controlling terminal */
2052 return 0; /* parent is not init */
2053 if (getsid(0) != getpid())
2054 return 0; /* not session leader */
2055 debug3("already daemonized");
2060 * Splits 's' into an argument vector. Handles quoted string and basic
2061 * escape characters (\\, \", \'). Caller must free the argument vector
2065 argv_split(const char *s
, int *argcp
, char ***argvp
, int terminate_on_comment
)
2067 int r
= SSH_ERR_INTERNAL_ERROR
;
2068 int argc
= 0, quote
, i
, j
;
2069 char *arg
, **argv
= xcalloc(1, sizeof(*argv
));
2074 for (i
= 0; s
[i
] != '\0'; i
++) {
2075 /* Skip leading whitespace */
2076 if (s
[i
] == ' ' || s
[i
] == '\t')
2078 if (terminate_on_comment
&& s
[i
] == '#')
2080 /* Start of a token */
2083 argv
= xreallocarray(argv
, (argc
+ 2), sizeof(*argv
));
2084 arg
= argv
[argc
++] = xcalloc(1, strlen(s
+ i
) + 1);
2087 /* Copy the token in, removing escapes */
2088 for (j
= 0; s
[i
] != '\0'; i
++) {
2090 if (s
[i
+ 1] == '\'' ||
2093 (quote
== 0 && s
[i
+ 1] == ' ')) {
2097 /* Unrecognised escape */
2100 } else if (quote
== 0 && (s
[i
] == ' ' || s
[i
] == '\t'))
2102 else if (quote
== 0 && (s
[i
] == '\"' || s
[i
] == '\''))
2103 quote
= s
[i
]; /* quote start */
2104 else if (quote
!= 0 && s
[i
] == quote
)
2105 quote
= 0; /* quote end */
2111 /* Ran out of string looking for close quote */
2112 r
= SSH_ERR_INVALID_FORMAT
;
2125 if (argc
!= 0 && argv
!= NULL
) {
2126 for (i
= 0; i
< argc
; i
++)
2134 * Reassemble an argument vector into a string, quoting and escaping as
2135 * necessary. Caller must free returned string.
2138 argv_assemble(int argc
, char **argv
)
2142 struct sshbuf
*buf
, *arg
;
2144 if ((buf
= sshbuf_new()) == NULL
|| (arg
= sshbuf_new()) == NULL
)
2145 fatal_f("sshbuf_new failed");
2147 for (i
= 0; i
< argc
; i
++) {
2150 for (j
= 0; argv
[i
][j
] != '\0'; j
++) {
2157 r
= sshbuf_put_u8(arg
, c
);
2162 if ((r
= sshbuf_put_u8(arg
, '\\')) != 0)
2166 r
= sshbuf_put_u8(arg
, c
);
2170 fatal_fr(r
, "sshbuf_put_u8");
2172 if ((i
!= 0 && (r
= sshbuf_put_u8(buf
, ' ')) != 0) ||
2173 (ws
!= 0 && (r
= sshbuf_put_u8(buf
, '"')) != 0) ||
2174 (r
= sshbuf_putb(buf
, arg
)) != 0 ||
2175 (ws
!= 0 && (r
= sshbuf_put_u8(buf
, '"')) != 0))
2176 fatal_fr(r
, "assemble");
2178 if ((ret
= malloc(sshbuf_len(buf
) + 1)) == NULL
)
2179 fatal_f("malloc failed");
2180 memcpy(ret
, sshbuf_ptr(buf
), sshbuf_len(buf
));
2181 ret
[sshbuf_len(buf
)] = '\0';
2188 argv_next(int *argcp
, char ***argvp
)
2190 char *ret
= (*argvp
)[0];
2192 if (*argcp
> 0 && ret
!= NULL
) {
2200 argv_consume(int *argcp
)
2206 argv_free(char **av
, int ac
)
2212 for (i
= 0; i
< ac
; i
++)
2217 /* Returns 0 if pid exited cleanly, non-zero otherwise */
2219 exited_cleanly(pid_t pid
, const char *tag
, const char *cmd
, int quiet
)
2223 while (waitpid(pid
, &status
, 0) == -1) {
2224 if (errno
!= EINTR
) {
2225 error("%s waitpid: %s", tag
, strerror(errno
));
2229 if (WIFSIGNALED(status
)) {
2230 error("%s %s exited on signal %d", tag
, cmd
, WTERMSIG(status
));
2232 } else if (WEXITSTATUS(status
) != 0) {
2233 do_log2(quiet
? SYSLOG_LEVEL_DEBUG1
: SYSLOG_LEVEL_INFO
,
2234 "%s %s failed, status %d", tag
, cmd
, WEXITSTATUS(status
));
2241 * Check a given path for security. This is defined as all components
2242 * of the path to the file must be owned by either the owner of
2243 * of the file or root and no directories must be group or world writable.
2245 * XXX Should any specific check be done for sym links ?
2247 * Takes a file name, its stat information (preferably from fstat() to
2248 * avoid races), the uid of the expected owner, their home directory and an
2249 * error buffer plus max size as arguments.
2251 * Returns 0 on success and -1 on failure
2254 safe_path(const char *name
, struct stat
*stp
, const char *pw_dir
,
2255 uid_t uid
, char *err
, size_t errlen
)
2257 char buf
[PATH_MAX
], homedir
[PATH_MAX
];
2259 int comparehome
= 0;
2262 if (realpath(name
, buf
) == NULL
) {
2263 snprintf(err
, errlen
, "realpath %s failed: %s", name
,
2267 if (pw_dir
!= NULL
&& realpath(pw_dir
, homedir
) != NULL
)
2270 if (!S_ISREG(stp
->st_mode
)) {
2271 snprintf(err
, errlen
, "%s is not a regular file", buf
);
2274 if ((!platform_sys_dir_uid(stp
->st_uid
) && stp
->st_uid
!= uid
) ||
2275 (stp
->st_mode
& 022) != 0) {
2276 snprintf(err
, errlen
, "bad ownership or modes for file %s",
2281 /* for each component of the canonical path, walking upwards */
2283 if ((cp
= dirname(buf
)) == NULL
) {
2284 snprintf(err
, errlen
, "dirname() failed");
2287 strlcpy(buf
, cp
, sizeof(buf
));
2289 if (stat(buf
, &st
) == -1 ||
2290 (!platform_sys_dir_uid(st
.st_uid
) && st
.st_uid
!= uid
) ||
2291 (st
.st_mode
& 022) != 0) {
2292 snprintf(err
, errlen
,
2293 "bad ownership or modes for directory %s", buf
);
2297 /* If are past the homedir then we can stop */
2298 if (comparehome
&& strcmp(homedir
, buf
) == 0)
2302 * dirname should always complete with a "/" path,
2303 * but we can be paranoid and check for "." too
2305 if ((strcmp("/", buf
) == 0) || (strcmp(".", buf
) == 0))
2312 * Version of safe_path() that accepts an open file descriptor to
2315 * Returns 0 on success and -1 on failure
2318 safe_path_fd(int fd
, const char *file
, struct passwd
*pw
,
2319 char *err
, size_t errlen
)
2323 /* check the open file to avoid races */
2324 if (fstat(fd
, &st
) == -1) {
2325 snprintf(err
, errlen
, "cannot stat file %s: %s",
2326 file
, strerror(errno
));
2329 return safe_path(file
, &st
, pw
->pw_dir
, pw
->pw_uid
, err
, errlen
);
2333 * Sets the value of the given variable in the environment. If the variable
2334 * already exists, its value is overridden.
2337 child_set_env(char ***envp
, u_int
*envsizep
, const char *name
,
2344 if (strchr(name
, '=') != NULL
) {
2345 error("Invalid environment variable \"%.100s\"", name
);
2350 * If we're passed an uninitialized list, allocate a single null
2351 * entry before continuing.
2353 if ((*envp
== NULL
) != (*envsizep
== 0))
2354 fatal_f("environment size mismatch");
2355 if (*envp
== NULL
&& *envsizep
== 0) {
2356 *envp
= xmalloc(sizeof(char *));
2362 * Find the slot where the value should be stored. If the variable
2363 * already exists, we reuse the slot; otherwise we append a new slot
2364 * at the end of the array, expanding if necessary.
2367 namelen
= strlen(name
);
2368 for (i
= 0; env
[i
]; i
++)
2369 if (strncmp(env
[i
], name
, namelen
) == 0 && env
[i
][namelen
] == '=')
2372 /* Reuse the slot. */
2375 /* New variable. Expand if necessary. */
2376 envsize
= *envsizep
;
2377 if (i
>= envsize
- 1) {
2378 if (envsize
>= 1000)
2379 fatal("child_set_env: too many env vars");
2381 env
= (*envp
) = xreallocarray(env
, envsize
, sizeof(char *));
2382 *envsizep
= envsize
;
2384 /* Need to set the NULL pointer at end of array beyond the new slot. */
2388 /* Allocate space and format the variable in the appropriate slot. */
2390 env
[i
] = xmalloc(strlen(name
) + 1 + strlen(value
) + 1);
2391 snprintf(env
[i
], strlen(name
) + 1 + strlen(value
) + 1, "%s=%s", name
, value
);
2395 * Check and optionally lowercase a domain name, also removes trailing '.'
2396 * Returns 1 on success and 0 on failure, storing an error message in errstr.
2399 valid_domain(char *name
, int makelower
, const char **errstr
)
2401 size_t i
, l
= strlen(name
);
2402 u_char c
, last
= '\0';
2403 static char errbuf
[256];
2406 strlcpy(errbuf
, "empty domain name", sizeof(errbuf
));
2409 if (!isalpha((u_char
)name
[0]) && !isdigit((u_char
)name
[0]) &&
2410 name
[0] != '_' /* technically invalid, but common */) {
2411 snprintf(errbuf
, sizeof(errbuf
), "domain name \"%.100s\" "
2412 "starts with invalid character", name
);
2415 for (i
= 0; i
< l
; i
++) {
2416 c
= tolower((u_char
)name
[i
]);
2419 if (last
== '.' && c
== '.') {
2420 snprintf(errbuf
, sizeof(errbuf
), "domain name "
2421 "\"%.100s\" contains consecutive separators", name
);
2424 if (c
!= '.' && c
!= '-' && !isalnum(c
) &&
2425 c
!= '_') /* technically invalid, but common */ {
2426 snprintf(errbuf
, sizeof(errbuf
), "domain name "
2427 "\"%.100s\" contains invalid characters", name
);
2432 if (name
[l
- 1] == '.')
2444 * Verify that a environment variable name (not including initial '$') is
2445 * valid; consisting of one or more alphanumeric or underscore characters only.
2446 * Returns 1 on valid, 0 otherwise.
2449 valid_env_name(const char *name
)
2453 if (name
[0] == '\0')
2455 for (cp
= name
; *cp
!= '\0'; cp
++) {
2456 if (!isalnum((u_char
)*cp
) && *cp
!= '_')
2463 atoi_err(const char *nptr
, int *val
)
2465 const char *errstr
= NULL
;
2467 if (nptr
== NULL
|| *nptr
== '\0')
2469 *val
= strtonum(nptr
, 0, INT_MAX
, &errstr
);
2474 parse_absolute_time(const char *s
, uint64_t *tp
)
2486 if (l
> 1 && strcasecmp(s
+ l
- 1, "Z") == 0) {
2489 } else if (l
> 3 && strcasecmp(s
+ l
- 3, "UTC") == 0) {
2494 * POSIX strptime says "The application shall ensure that there
2495 * is white-space or other non-alphanumeric characters between
2496 * any two conversion specifications" so arrange things this way.
2499 case 8: /* YYYYMMDD */
2501 snprintf(buf
, sizeof(buf
), "%.4s-%.2s-%.2s", s
, s
+ 4, s
+ 6);
2503 case 12: /* YYYYMMDDHHMM */
2504 fmt
= "%Y-%m-%dT%H:%M";
2505 snprintf(buf
, sizeof(buf
), "%.4s-%.2s-%.2sT%.2s:%.2s",
2506 s
, s
+ 4, s
+ 6, s
+ 8, s
+ 10);
2508 case 14: /* YYYYMMDDHHMMSS */
2509 fmt
= "%Y-%m-%dT%H:%M:%S";
2510 snprintf(buf
, sizeof(buf
), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
2511 s
, s
+ 4, s
+ 6, s
+ 8, s
+ 10, s
+ 12);
2514 return SSH_ERR_INVALID_FORMAT
;
2517 memset(&tm
, 0, sizeof(tm
));
2518 if ((cp
= strptime(buf
, fmt
, &tm
)) == NULL
|| *cp
!= '\0')
2519 return SSH_ERR_INVALID_FORMAT
;
2521 if ((tt
= timegm(&tm
)) < 0)
2522 return SSH_ERR_INVALID_FORMAT
;
2524 if ((tt
= mktime(&tm
)) < 0)
2525 return SSH_ERR_INVALID_FORMAT
;
2533 format_absolute_time(uint64_t t
, char *buf
, size_t len
)
2535 time_t tt
= t
> SSH_TIME_T_MAX
? SSH_TIME_T_MAX
: t
;
2538 localtime_r(&tt
, &tm
);
2539 strftime(buf
, len
, "%Y-%m-%dT%H:%M:%S", &tm
);
2543 * Parse a "pattern=interval" clause (e.g. a ChannelTimeout).
2544 * Returns 0 on success or non-zero on failure.
2545 * Caller must free *typep.
2548 parse_pattern_interval(const char *s
, char **typep
, int *secsp
)
2561 if ((cp
= strchr(sdup
, '=')) == NULL
|| cp
== sdup
) {
2566 if ((secs
= convtime(cp
)) < 0) {
2572 *typep
= xstrdup(sdup
);
2579 /* check if path is absolute */
2581 path_absolute(const char *path
)
2583 return (*path
== '/') ? 1 : 0;
2587 skip_space(char **cpp
)
2591 for (cp
= *cpp
; *cp
== ' ' || *cp
== '\t'; cp
++)
2596 /* authorized_key-style options parsing helpers */
2599 * Match flag 'opt' in *optsp, and if allow_negate is set then also match
2600 * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
2601 * if negated option matches.
2602 * If the option or negated option matches, then *optsp is updated to
2603 * point to the first character after the option.
2606 opt_flag(const char *opt
, int allow_negate
, const char **optsp
)
2608 size_t opt_len
= strlen(opt
);
2609 const char *opts
= *optsp
;
2612 if (allow_negate
&& strncasecmp(opts
, "no-", 3) == 0) {
2616 if (strncasecmp(opts
, opt
, opt_len
) == 0) {
2617 *optsp
= opts
+ opt_len
;
2618 return negate
? 0 : 1;
2624 opt_dequote(const char **sp
, const char **errstrp
)
2626 const char *s
= *sp
;
2632 *errstrp
= "missing start quote";
2636 if ((ret
= malloc(strlen((s
)) + 1)) == NULL
) {
2637 *errstrp
= "memory allocation failed";
2640 for (i
= 0; *s
!= '\0' && *s
!= '"';) {
2641 if (s
[0] == '\\' && s
[1] == '"')
2646 *errstrp
= "missing end quote";
2657 opt_match(const char **opts
, const char *term
)
2659 if (strncasecmp((*opts
), term
, strlen(term
)) == 0 &&
2660 (*opts
)[strlen(term
)] == '=') {
2661 *opts
+= strlen(term
) + 1;
2668 opt_array_append2(const char *file
, const int line
, const char *directive
,
2669 char ***array
, int **iarray
, u_int
*lp
, const char *s
, int i
)
2673 fatal("%s line %d: Too many %s entries", file
, line
, directive
);
2675 if (iarray
!= NULL
) {
2676 *iarray
= xrecallocarray(*iarray
, *lp
, *lp
+ 1,
2681 *array
= xrecallocarray(*array
, *lp
, *lp
+ 1, sizeof(**array
));
2682 (*array
)[*lp
] = xstrdup(s
);
2687 opt_array_append(const char *file
, const int line
, const char *directive
,
2688 char ***array
, u_int
*lp
, const char *s
)
2690 opt_array_append2(file
, line
, directive
, array
, NULL
, lp
, s
, 0);
2694 opt_array_free2(char **array
, int **iarray
, u_int l
)
2698 if (array
== NULL
|| l
== 0)
2700 for (i
= 0; i
< l
; i
++)
2707 ssh_signal(int signum
, sshsig_t handler
)
2709 struct sigaction sa
, osa
;
2711 /* mask all other signals while in handler */
2712 memset(&sa
, 0, sizeof(sa
));
2713 sa
.sa_handler
= handler
;
2714 sigfillset(&sa
.sa_mask
);
2715 #if defined(SA_RESTART) && !defined(NO_SA_RESTART)
2716 if (signum
!= SIGALRM
)
2717 sa
.sa_flags
= SA_RESTART
;
2719 if (sigaction(signum
, &sa
, &osa
) == -1) {
2720 debug3("sigaction(%s): %s", strsignal(signum
), strerror(errno
));
2723 return osa
.sa_handler
;
2727 stdfd_devnull(int do_stdin
, int do_stdout
, int do_stderr
)
2729 int devnull
, ret
= 0;
2731 if ((devnull
= open(_PATH_DEVNULL
, O_RDWR
)) == -1) {
2732 error_f("open %s: %s", _PATH_DEVNULL
,
2736 if ((do_stdin
&& dup2(devnull
, STDIN_FILENO
) == -1) ||
2737 (do_stdout
&& dup2(devnull
, STDOUT_FILENO
) == -1) ||
2738 (do_stderr
&& dup2(devnull
, STDERR_FILENO
) == -1)) {
2739 error_f("dup2: %s", strerror(errno
));
2742 if (devnull
> STDERR_FILENO
)
2748 * Runs command in a subprocess with a minimal environment.
2749 * Returns pid on success, 0 on failure.
2750 * The child stdout and stderr maybe captured, left attached or sent to
2751 * /dev/null depending on the contents of flags.
2752 * "tag" is prepended to log messages.
2753 * NB. "command" is only used for logging; the actual command executed is
2757 subprocess(const char *tag
, const char *command
,
2758 int ac
, char **av
, FILE **child
, u_int flags
,
2759 struct passwd
*pw
, privdrop_fn
*drop_privs
, privrestore_fn
*restore_privs
)
2763 int fd
, devnull
, p
[2], i
;
2765 char *cp
, errmsg
[512];
2769 /* If dropping privs, then must specify user and restore function */
2770 if (drop_privs
!= NULL
&& (pw
== NULL
|| restore_privs
== NULL
)) {
2771 error("%s: inconsistent arguments", tag
); /* XXX fatal? */
2774 if (pw
== NULL
&& (pw
= getpwuid(getuid())) == NULL
) {
2775 error("%s: no user for current uid", tag
);
2781 debug3_f("%s command \"%s\" running as %s (flags 0x%x)",
2782 tag
, command
, pw
->pw_name
, flags
);
2784 /* Check consistency */
2785 if ((flags
& SSH_SUBPROCESS_STDOUT_DISCARD
) != 0 &&
2786 (flags
& SSH_SUBPROCESS_STDOUT_CAPTURE
) != 0) {
2787 error_f("inconsistent flags");
2790 if (((flags
& SSH_SUBPROCESS_STDOUT_CAPTURE
) == 0) != (child
== NULL
)) {
2791 error_f("inconsistent flags/output");
2796 * If executing an explicit binary, then verify the it exists
2797 * and appears safe-ish to execute
2799 if (!path_absolute(av
[0])) {
2800 error("%s path is not absolute", tag
);
2803 if (drop_privs
!= NULL
)
2805 if (stat(av
[0], &st
) == -1) {
2806 error("Could not stat %s \"%s\": %s", tag
,
2807 av
[0], strerror(errno
));
2808 goto restore_return
;
2810 if ((flags
& SSH_SUBPROCESS_UNSAFE_PATH
) == 0 &&
2811 safe_path(av
[0], &st
, NULL
, 0, errmsg
, sizeof(errmsg
)) != 0) {
2812 error("Unsafe %s \"%s\": %s", tag
, av
[0], errmsg
);
2813 goto restore_return
;
2815 /* Prepare to keep the child's stdout if requested */
2816 if (pipe(p
) == -1) {
2817 error("%s: pipe: %s", tag
, strerror(errno
));
2819 if (restore_privs
!= NULL
)
2823 if (restore_privs
!= NULL
)
2826 switch ((pid
= fork())) {
2827 case -1: /* error */
2828 error("%s: fork: %s", tag
, strerror(errno
));
2833 /* Prepare a minimal environment for the child. */
2834 if ((flags
& SSH_SUBPROCESS_PRESERVE_ENV
) == 0) {
2836 env
= xcalloc(sizeof(*env
), nenv
);
2837 child_set_env(&env
, &nenv
, "PATH", _PATH_STDPATH
);
2838 child_set_env(&env
, &nenv
, "USER", pw
->pw_name
);
2839 child_set_env(&env
, &nenv
, "LOGNAME", pw
->pw_name
);
2840 child_set_env(&env
, &nenv
, "HOME", pw
->pw_dir
);
2841 if ((cp
= getenv("LANG")) != NULL
)
2842 child_set_env(&env
, &nenv
, "LANG", cp
);
2845 for (i
= 1; i
< NSIG
; i
++)
2846 ssh_signal(i
, SIG_DFL
);
2848 if ((devnull
= open(_PATH_DEVNULL
, O_RDWR
)) == -1) {
2849 error("%s: open %s: %s", tag
, _PATH_DEVNULL
,
2853 if (dup2(devnull
, STDIN_FILENO
) == -1) {
2854 error("%s: dup2: %s", tag
, strerror(errno
));
2858 /* Set up stdout as requested; leave stderr in place for now. */
2860 if ((flags
& SSH_SUBPROCESS_STDOUT_CAPTURE
) != 0)
2862 else if ((flags
& SSH_SUBPROCESS_STDOUT_DISCARD
) != 0)
2864 if (fd
!= -1 && dup2(fd
, STDOUT_FILENO
) == -1) {
2865 error("%s: dup2: %s", tag
, strerror(errno
));
2868 closefrom(STDERR_FILENO
+ 1);
2870 if (geteuid() == 0 &&
2871 initgroups(pw
->pw_name
, pw
->pw_gid
) == -1) {
2872 error("%s: initgroups(%s, %u): %s", tag
,
2873 pw
->pw_name
, (u_int
)pw
->pw_gid
, strerror(errno
));
2876 if (setresgid(pw
->pw_gid
, pw
->pw_gid
, pw
->pw_gid
) == -1) {
2877 error("%s: setresgid %u: %s", tag
, (u_int
)pw
->pw_gid
,
2881 if (setresuid(pw
->pw_uid
, pw
->pw_uid
, pw
->pw_uid
) == -1) {
2882 error("%s: setresuid %u: %s", tag
, (u_int
)pw
->pw_uid
,
2886 /* stdin is pointed to /dev/null at this point */
2887 if ((flags
& SSH_SUBPROCESS_STDOUT_DISCARD
) != 0 &&
2888 dup2(STDIN_FILENO
, STDERR_FILENO
) == -1) {
2889 error("%s: dup2: %s", tag
, strerror(errno
));
2893 execve(av
[0], av
, env
);
2896 error("%s %s \"%s\": %s", tag
, env
== NULL
? "execv" : "execve",
2897 command
, strerror(errno
));
2899 default: /* parent */
2904 if ((flags
& SSH_SUBPROCESS_STDOUT_CAPTURE
) == 0)
2906 else if ((f
= fdopen(p
[0], "r")) == NULL
) {
2907 error("%s: fdopen: %s", tag
, strerror(errno
));
2909 /* Don't leave zombie child */
2911 while (waitpid(pid
, NULL
, 0) == -1 && errno
== EINTR
)
2916 debug3_f("%s pid %ld", tag
, (long)pid
);
2923 lookup_env_in_list(const char *env
, char * const *envs
, size_t nenvs
)
2927 envlen
= strlen(env
);
2928 for (i
= 0; i
< nenvs
; i
++) {
2929 if (strncmp(envs
[i
], env
, envlen
) == 0 &&
2930 envs
[i
][envlen
] == '=') {
2931 return envs
[i
] + envlen
+ 1;
2938 lookup_setenv_in_list(const char *env
, char * const *envs
, size_t nenvs
)
2943 name
= xstrdup(env
);
2944 if ((cp
= strchr(name
, '=')) == NULL
) {
2946 return NULL
; /* not env=val */
2949 ret
= lookup_env_in_list(name
, envs
, nenvs
);
2955 * Helpers for managing poll(2)/ppoll(2) timeouts
2956 * Will remember the earliest deadline and return it for use in poll/ppoll.
2959 /* Initialise a poll/ppoll timeout with an indefinite deadline */
2961 ptimeout_init(struct timespec
*pt
)
2964 * Deliberately invalid for ppoll(2).
2965 * Will be converted to NULL in ptimeout_get_tspec() later.
2971 /* Specify a poll/ppoll deadline of at most 'sec' seconds */
2973 ptimeout_deadline_sec(struct timespec
*pt
, long sec
)
2975 if (pt
->tv_sec
== -1 || pt
->tv_sec
>= sec
) {
2981 /* Specify a poll/ppoll deadline of at most 'p' (timespec) */
2983 ptimeout_deadline_tsp(struct timespec
*pt
, struct timespec
*p
)
2985 if (pt
->tv_sec
== -1 || timespeccmp(pt
, p
, >=))
2989 /* Specify a poll/ppoll deadline of at most 'ms' milliseconds */
2991 ptimeout_deadline_ms(struct timespec
*pt
, long ms
)
2995 p
.tv_sec
= ms
/ 1000;
2996 p
.tv_nsec
= (ms
% 1000) * 1000000;
2997 ptimeout_deadline_tsp(pt
, &p
);
3000 /* Specify a poll/ppoll deadline at wall clock monotime 'when' (timespec) */
3002 ptimeout_deadline_monotime_tsp(struct timespec
*pt
, struct timespec
*when
)
3004 struct timespec now
, t
;
3008 if (timespeccmp(&now
, when
, >=)) {
3009 /* 'when' is now or in the past. Timeout ASAP */
3013 timespecsub(when
, &now
, &t
);
3014 ptimeout_deadline_tsp(pt
, &t
);
3018 /* Specify a poll/ppoll deadline at wall clock monotime 'when' */
3020 ptimeout_deadline_monotime(struct timespec
*pt
, time_t when
)
3026 ptimeout_deadline_monotime_tsp(pt
, &t
);
3029 /* Get a poll(2) timeout value in milliseconds */
3031 ptimeout_get_ms(struct timespec
*pt
)
3033 if (pt
->tv_sec
== -1)
3035 if (pt
->tv_sec
>= (INT_MAX
- (pt
->tv_nsec
/ 1000000)) / 1000)
3037 return (pt
->tv_sec
* 1000) + (pt
->tv_nsec
/ 1000000);
3040 /* Get a ppoll(2) timeout value as a timespec pointer */
3042 ptimeout_get_tsp(struct timespec
*pt
)
3044 return pt
->tv_sec
== -1 ? NULL
: pt
;
3047 /* Returns non-zero if a timeout has been set (i.e. is not indefinite) */
3049 ptimeout_isset(struct timespec
*pt
)
3051 return pt
->tv_sec
!= -1;
3055 * Returns zero if the library at 'path' contains symbol 's', nonzero
3059 lib_contains_symbol(const char *path
, const char *s
)
3065 memset(nl
, 0, sizeof(nl
));
3066 nl
[0].n_name
= xstrdup(s
);
3067 nl
[1].n_name
= NULL
;
3068 if ((r
= nlist(path
, nl
)) == -1) {
3069 error_f("nlist failed for %s", path
);
3072 if (r
!= 0 || nl
[0].n_value
== 0 || nl
[0].n_type
== 0) {
3073 error_f("library %s does not contain symbol %s", path
, s
);
3081 #else /* HAVE_NLIST_H */
3087 memset(&st
, 0, sizeof(st
));
3088 if ((fd
= open(path
, O_RDONLY
)) < 0) {
3089 error_f("open %s: %s", path
, strerror(errno
));
3092 if (fstat(fd
, &st
) != 0) {
3093 error_f("fstat %s: %s", path
, strerror(errno
));
3096 if (!S_ISREG(st
.st_mode
)) {
3097 error_f("%s is not a regular file", path
);
3100 if (st
.st_size
< 0 ||
3101 (size_t)st
.st_size
< strlen(s
) ||
3102 st
.st_size
>= INT_MAX
/2) {
3103 error_f("%s bad size %lld", path
, (long long)st
.st_size
);
3106 sz
= (size_t)st
.st_size
;
3107 if ((m
= mmap(NULL
, sz
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
||
3109 error_f("mmap %s: %s", path
, strerror(errno
));
3112 if (memmem(m
, sz
, s
, strlen(s
)) == NULL
) {
3113 error_f("%s does not contain expected string %s", path
, s
);
3119 if (m
!= NULL
&& m
!= MAP_FAILED
)
3123 #endif /* HAVE_NLIST_H */
3127 signal_is_crash(int sig
)