summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c187
1 files changed, 149 insertions, 38 deletions
diff --git a/channels.c b/channels.c
index 69c99c9b2..dea60ba24 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.286 2008/07/16 11:52:19 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.295 2009/02/12 03:00:56 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -296,6 +296,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
296 buffer_init(&c->input); 296 buffer_init(&c->input);
297 buffer_init(&c->output); 297 buffer_init(&c->output);
298 buffer_init(&c->extended); 298 buffer_init(&c->extended);
299 c->path = NULL;
299 c->ostate = CHAN_OUTPUT_OPEN; 300 c->ostate = CHAN_OUTPUT_OPEN;
300 c->istate = CHAN_INPUT_OPEN; 301 c->istate = CHAN_INPUT_OPEN;
301 c->flags = 0; 302 c->flags = 0;
@@ -402,6 +403,10 @@ channel_free(Channel *c)
402 xfree(c->remote_name); 403 xfree(c->remote_name);
403 c->remote_name = NULL; 404 c->remote_name = NULL;
404 } 405 }
406 if (c->path) {
407 xfree(c->path);
408 c->path = NULL;
409 }
405 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { 410 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
406 if (cc->abandon_cb != NULL) 411 if (cc->abandon_cb != NULL)
407 cc->abandon_cb(c, cc->ctx); 412 cc->abandon_cb(c, cc->ctx);
@@ -691,7 +696,7 @@ channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx)
691 Channel *c = channel_lookup(id); 696 Channel *c = channel_lookup(id);
692 697
693 if (c == NULL) { 698 if (c == NULL) {
694 logit("channel_register_open_comfirm: %d: bad id", id); 699 logit("channel_register_open_confirm: %d: bad id", id);
695 return; 700 return;
696 } 701 }
697 c->open_confirm = fn; 702 c->open_confirm = fn;
@@ -980,7 +985,7 @@ static int
980channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) 985channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
981{ 986{
982 char *p, *host; 987 char *p, *host;
983 u_int len, have, i, found; 988 u_int len, have, i, found, need;
984 char username[256]; 989 char username[256];
985 struct { 990 struct {
986 u_int8_t version; 991 u_int8_t version;
@@ -996,10 +1001,20 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
996 if (have < len) 1001 if (have < len)
997 return 0; 1002 return 0;
998 p = buffer_ptr(&c->input); 1003 p = buffer_ptr(&c->input);
1004
1005 need = 1;
1006 /* SOCKS4A uses an invalid IP address 0.0.0.x */
1007 if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) {
1008 debug2("channel %d: socks4a request", c->self);
1009 /* ... and needs an extra string (the hostname) */
1010 need = 2;
1011 }
1012 /* Check for terminating NUL on the string(s) */
999 for (found = 0, i = len; i < have; i++) { 1013 for (found = 0, i = len; i < have; i++) {
1000 if (p[i] == '\0') { 1014 if (p[i] == '\0') {
1001 found = 1; 1015 found++;
1002 break; 1016 if (found == need)
1017 break;
1003 } 1018 }
1004 if (i > 1024) { 1019 if (i > 1024) {
1005 /* the peer is probably sending garbage */ 1020 /* the peer is probably sending garbage */
@@ -1008,7 +1023,7 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
1008 return -1; 1023 return -1;
1009 } 1024 }
1010 } 1025 }
1011 if (!found) 1026 if (found < need)
1012 return 0; 1027 return 0;
1013 buffer_get(&c->input, (char *)&s4_req.version, 1); 1028 buffer_get(&c->input, (char *)&s4_req.version, 1);
1014 buffer_get(&c->input, (char *)&s4_req.command, 1); 1029 buffer_get(&c->input, (char *)&s4_req.command, 1);
@@ -1018,23 +1033,46 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
1018 p = buffer_ptr(&c->input); 1033 p = buffer_ptr(&c->input);
1019 len = strlen(p); 1034 len = strlen(p);
1020 debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); 1035 debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
1036 len++; /* trailing '\0' */
1021 if (len > have) 1037 if (len > have)
1022 fatal("channel %d: decode socks4: len %d > have %d", 1038 fatal("channel %d: decode socks4: len %d > have %d",
1023 c->self, len, have); 1039 c->self, len, have);
1024 strlcpy(username, p, sizeof(username)); 1040 strlcpy(username, p, sizeof(username));
1025 buffer_consume(&c->input, len); 1041 buffer_consume(&c->input, len);
1026 buffer_consume(&c->input, 1); /* trailing '\0' */
1027 1042
1028 host = inet_ntoa(s4_req.dest_addr); 1043 if (c->path != NULL) {
1029 strlcpy(c->path, host, sizeof(c->path)); 1044 xfree(c->path);
1045 c->path = NULL;
1046 }
1047 if (need == 1) { /* SOCKS4: one string */
1048 host = inet_ntoa(s4_req.dest_addr);
1049 c->path = xstrdup(host);
1050 } else { /* SOCKS4A: two strings */
1051 have = buffer_len(&c->input);
1052 p = buffer_ptr(&c->input);
1053 len = strlen(p);
1054 debug2("channel %d: decode socks4a: host %s/%d",
1055 c->self, p, len);
1056 len++; /* trailing '\0' */
1057 if (len > have)
1058 fatal("channel %d: decode socks4a: len %d > have %d",
1059 c->self, len, have);
1060 if (len > NI_MAXHOST) {
1061 error("channel %d: hostname \"%.100s\" too long",
1062 c->self, p);
1063 return -1;
1064 }
1065 c->path = xstrdup(p);
1066 buffer_consume(&c->input, len);
1067 }
1030 c->host_port = ntohs(s4_req.dest_port); 1068 c->host_port = ntohs(s4_req.dest_port);
1031 1069
1032 debug2("channel %d: dynamic request: socks4 host %s port %u command %u", 1070 debug2("channel %d: dynamic request: socks4 host %s port %u command %u",
1033 c->self, host, c->host_port, s4_req.command); 1071 c->self, c->path, c->host_port, s4_req.command);
1034 1072
1035 if (s4_req.command != 1) { 1073 if (s4_req.command != 1) {
1036 debug("channel %d: cannot handle: socks4 cn %d", 1074 debug("channel %d: cannot handle: %s cn %d",
1037 c->self, s4_req.command); 1075 c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command);
1038 return -1; 1076 return -1;
1039 } 1077 }
1040 s4_rsp.version = 0; /* vn: 0 for reply */ 1078 s4_rsp.version = 0; /* vn: 0 for reply */
@@ -1065,7 +1103,7 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
1065 u_int8_t atyp; 1103 u_int8_t atyp;
1066 } s5_req, s5_rsp; 1104 } s5_req, s5_rsp;
1067 u_int16_t dest_port; 1105 u_int16_t dest_port;
1068 u_char *p, dest_addr[255+1]; 1106 u_char *p, dest_addr[255+1], ntop[INET6_ADDRSTRLEN];
1069 u_int have, need, i, found, nmethods, addrlen, af; 1107 u_int have, need, i, found, nmethods, addrlen, af;
1070 1108
1071 debug2("channel %d: decode socks5", c->self); 1109 debug2("channel %d: decode socks5", c->self);
@@ -1138,10 +1176,22 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
1138 buffer_get(&c->input, (char *)&dest_addr, addrlen); 1176 buffer_get(&c->input, (char *)&dest_addr, addrlen);
1139 buffer_get(&c->input, (char *)&dest_port, 2); 1177 buffer_get(&c->input, (char *)&dest_port, 2);
1140 dest_addr[addrlen] = '\0'; 1178 dest_addr[addrlen] = '\0';
1141 if (s5_req.atyp == SSH_SOCKS5_DOMAIN) 1179 if (c->path != NULL) {
1142 strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); 1180 xfree(c->path);
1143 else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) 1181 c->path = NULL;
1144 return -1; 1182 }
1183 if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
1184 if (addrlen >= NI_MAXHOST) {
1185 error("channel %d: dynamic request: socks5 hostname "
1186 "\"%.100s\" too long", c->self, dest_addr);
1187 return -1;
1188 }
1189 c->path = xstrdup(dest_addr);
1190 } else {
1191 if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL)
1192 return -1;
1193 c->path = xstrdup(ntop);
1194 }
1145 c->host_port = ntohs(dest_port); 1195 c->host_port = ntohs(dest_port);
1146 1196
1147 debug2("channel %d: dynamic request: socks5 host %s port %u command %u", 1197 debug2("channel %d: dynamic request: socks5 host %s port %u command %u",
@@ -1370,7 +1420,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1370 c->local_window_max, c->local_maxpacket, 0, rtype, 1); 1420 c->local_window_max, c->local_maxpacket, 0, rtype, 1);
1371 nc->listening_port = c->listening_port; 1421 nc->listening_port = c->listening_port;
1372 nc->host_port = c->host_port; 1422 nc->host_port = c->host_port;
1373 strlcpy(nc->path, c->path, sizeof(nc->path)); 1423 if (c->path != NULL)
1424 nc->path = xstrdup(c->path);
1374 1425
1375 if (nextstate == SSH_CHANNEL_DYNAMIC) { 1426 if (nextstate == SSH_CHANNEL_DYNAMIC) {
1376 /* 1427 /*
@@ -2311,8 +2362,8 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
2311 xfree(lang); 2362 xfree(lang);
2312 } 2363 }
2313 packet_check_eom(); 2364 packet_check_eom();
2314 /* Free the channel. This will also close the socket. */ 2365 /* Schedule the channel for cleanup/deletion. */
2315 channel_free(c); 2366 chan_mark_dead(c);
2316} 2367}
2317 2368
2318/* ARGSUSED */ 2369/* ARGSUSED */
@@ -2377,18 +2428,18 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
2377{ 2428{
2378 Channel *c; 2429 Channel *c;
2379 struct channel_confirm *cc; 2430 struct channel_confirm *cc;
2380 int remote_id; 2431 int id;
2381 2432
2382 /* Reset keepalive timeout */ 2433 /* Reset keepalive timeout */
2383 keep_alive_timeouts = 0; 2434 keep_alive_timeouts = 0;
2384 2435
2385 remote_id = packet_get_int(); 2436 id = packet_get_int();
2386 packet_check_eom(); 2437 packet_check_eom();
2387 2438
2388 debug2("channel_input_confirm: type %d id %d", type, remote_id); 2439 debug2("channel_input_status_confirm: type %d id %d", type, id);
2389 2440
2390 if ((c = channel_lookup(remote_id)) == NULL) { 2441 if ((c = channel_lookup(id)) == NULL) {
2391 logit("channel_input_success_failure: %d: unknown", remote_id); 2442 logit("channel_input_status_confirm: %d: unknown", id);
2392 return; 2443 return;
2393 } 2444 }
2394 ; 2445 ;
@@ -2409,7 +2460,8 @@ channel_set_af(int af)
2409} 2460}
2410 2461
2411static int 2462static int
2412channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, 2463channel_setup_fwd_listener(int type, const char *listen_addr,
2464 u_short listen_port, int *allocated_listen_port,
2413 const char *host_to_connect, u_short port_to_connect, int gateway_ports) 2465 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2414{ 2466{
2415 Channel *c; 2467 Channel *c;
@@ -2417,6 +2469,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2417 struct addrinfo hints, *ai, *aitop; 2469 struct addrinfo hints, *ai, *aitop;
2418 const char *host, *addr; 2470 const char *host, *addr;
2419 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 2471 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
2472 in_port_t *lport_p;
2420 2473
2421 host = (type == SSH_CHANNEL_RPORT_LISTENER) ? 2474 host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
2422 listen_addr : host_to_connect; 2475 listen_addr : host_to_connect;
@@ -2426,7 +2479,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2426 error("No forward host name."); 2479 error("No forward host name.");
2427 return 0; 2480 return 0;
2428 } 2481 }
2429 if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { 2482 if (strlen(host) >= NI_MAXHOST) {
2430 error("Forward host name too long."); 2483 error("Forward host name too long.");
2431 return 0; 2484 return 0;
2432 } 2485 }
@@ -2485,10 +2538,29 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2485 } 2538 }
2486 return 0; 2539 return 0;
2487 } 2540 }
2488 2541 if (allocated_listen_port != NULL)
2542 *allocated_listen_port = 0;
2489 for (ai = aitop; ai; ai = ai->ai_next) { 2543 for (ai = aitop; ai; ai = ai->ai_next) {
2490 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 2544 switch (ai->ai_family) {
2545 case AF_INET:
2546 lport_p = &((struct sockaddr_in *)ai->ai_addr)->
2547 sin_port;
2548 break;
2549 case AF_INET6:
2550 lport_p = &((struct sockaddr_in6 *)ai->ai_addr)->
2551 sin6_port;
2552 break;
2553 default:
2491 continue; 2554 continue;
2555 }
2556 /*
2557 * If allocating a port for -R forwards, then use the
2558 * same port for all address families.
2559 */
2560 if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
2561 allocated_listen_port != NULL && *allocated_listen_port > 0)
2562 *lport_p = htons(*allocated_listen_port);
2563
2492 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2564 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
2493 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2565 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2494 error("channel_setup_fwd_listener: getnameinfo failed"); 2566 error("channel_setup_fwd_listener: getnameinfo failed");
@@ -2504,7 +2576,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2504 2576
2505 channel_set_reuseaddr(sock); 2577 channel_set_reuseaddr(sock);
2506 2578
2507 debug("Local forwarding listening on %s port %s.", ntop, strport); 2579 debug("Local forwarding listening on %s port %s.",
2580 ntop, strport);
2508 2581
2509 /* Bind the socket to the address. */ 2582 /* Bind the socket to the address. */
2510 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 2583 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
@@ -2523,11 +2596,24 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2523 close(sock); 2596 close(sock);
2524 continue; 2597 continue;
2525 } 2598 }
2599
2600 /*
2601 * listen_port == 0 requests a dynamically allocated port -
2602 * record what we got.
2603 */
2604 if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
2605 allocated_listen_port != NULL &&
2606 *allocated_listen_port == 0) {
2607 *allocated_listen_port = get_sock_port(sock, 1);
2608 debug("Allocated listen port %d",
2609 *allocated_listen_port);
2610 }
2611
2526 /* Allocate a channel number for the socket. */ 2612 /* Allocate a channel number for the socket. */
2527 c = channel_new("port listener", type, sock, sock, -1, 2613 c = channel_new("port listener", type, sock, sock, -1,
2528 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 2614 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2529 0, "port listener", 1); 2615 0, "port listener", 1);
2530 strlcpy(c->path, host, sizeof(c->path)); 2616 c->path = xstrdup(host);
2531 c->host_port = port_to_connect; 2617 c->host_port = port_to_connect;
2532 c->listening_port = listen_port; 2618 c->listening_port = listen_port;
2533 success = 1; 2619 success = 1;
@@ -2549,8 +2635,7 @@ channel_cancel_rport_listener(const char *host, u_short port)
2549 Channel *c = channels[i]; 2635 Channel *c = channels[i];
2550 2636
2551 if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && 2637 if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER &&
2552 strncmp(c->path, host, sizeof(c->path)) == 0 && 2638 strcmp(c->path, host) == 0 && c->listening_port == port) {
2553 c->listening_port == port) {
2554 debug2("%s: close channel %d", __func__, i); 2639 debug2("%s: close channel %d", __func__, i);
2555 channel_free(c); 2640 channel_free(c);
2556 found = 1; 2641 found = 1;
@@ -2566,17 +2651,18 @@ channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
2566 const char *host_to_connect, u_short port_to_connect, int gateway_ports) 2651 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2567{ 2652{
2568 return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, 2653 return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
2569 listen_host, listen_port, host_to_connect, port_to_connect, 2654 listen_host, listen_port, NULL, host_to_connect, port_to_connect,
2570 gateway_ports); 2655 gateway_ports);
2571} 2656}
2572 2657
2573/* protocol v2 remote port fwd, used by sshd */ 2658/* protocol v2 remote port fwd, used by sshd */
2574int 2659int
2575channel_setup_remote_fwd_listener(const char *listen_address, 2660channel_setup_remote_fwd_listener(const char *listen_address,
2576 u_short listen_port, int gateway_ports) 2661 u_short listen_port, int *allocated_listen_port, int gateway_ports)
2577{ 2662{
2578 return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, 2663 return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
2579 listen_address, listen_port, NULL, 0, gateway_ports); 2664 listen_address, listen_port, allocated_listen_port,
2665 NULL, 0, gateway_ports);
2580} 2666}
2581 2667
2582/* 2668/*
@@ -2791,10 +2877,16 @@ channel_print_adm_permitted_opens(void)
2791{ 2877{
2792 int i; 2878 int i;
2793 2879
2880 printf("permitopen");
2881 if (num_adm_permitted_opens == 0) {
2882 printf(" any\n");
2883 return;
2884 }
2794 for (i = 0; i < num_adm_permitted_opens; i++) 2885 for (i = 0; i < num_adm_permitted_opens; i++)
2795 if (permitted_adm_opens[i].host_to_connect != NULL) 2886 if (permitted_adm_opens[i].host_to_connect != NULL)
2796 printf(" %s:%d", permitted_adm_opens[i].host_to_connect, 2887 printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
2797 permitted_adm_opens[i].port_to_connect); 2888 permitted_adm_opens[i].port_to_connect);
2889 printf("\n");
2798} 2890}
2799 2891
2800/* Try to start non-blocking connect to next host in cctx list */ 2892/* Try to start non-blocking connect to next host in cctx list */
@@ -3074,7 +3166,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
3074} 3166}
3075 3167
3076static int 3168static int
3077connect_local_xsocket(u_int dnr) 3169connect_local_xsocket_path(const char *pathname)
3078{ 3170{
3079 int sock; 3171 int sock;
3080 struct sockaddr_un addr; 3172 struct sockaddr_un addr;
@@ -3084,7 +3176,7 @@ connect_local_xsocket(u_int dnr)
3084 error("socket: %.100s", strerror(errno)); 3176 error("socket: %.100s", strerror(errno));
3085 memset(&addr, 0, sizeof(addr)); 3177 memset(&addr, 0, sizeof(addr));
3086 addr.sun_family = AF_UNIX; 3178 addr.sun_family = AF_UNIX;
3087 snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); 3179 strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
3088 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) 3180 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
3089 return sock; 3181 return sock;
3090 close(sock); 3182 close(sock);
@@ -3092,6 +3184,14 @@ connect_local_xsocket(u_int dnr)
3092 return -1; 3184 return -1;
3093} 3185}
3094 3186
3187static int
3188connect_local_xsocket(u_int dnr)
3189{
3190 char buf[1024];
3191 snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
3192 return connect_local_xsocket_path(buf);
3193}
3194
3095int 3195int
3096x11_connect_display(void) 3196x11_connect_display(void)
3097{ 3197{
@@ -3113,6 +3213,17 @@ x11_connect_display(void)
3113 * connection to the real X server. 3213 * connection to the real X server.
3114 */ 3214 */
3115 3215
3216 /* Check if the display is from launchd. */
3217#ifdef __APPLE__
3218 if (strncmp(display, "/tmp/launch", 11) == 0) {
3219 sock = connect_local_xsocket_path(display);
3220 if (sock < 0)
3221 return -1;
3222
3223 /* OK, we now have a connection to the display. */
3224 return sock;
3225 }
3226#endif
3116 /* 3227 /*
3117 * Check if it is a unix domain socket. Unix domain displays are in 3228 * Check if it is a unix domain socket. Unix domain displays are in
3118 * one of the following formats: unix:d[.s], :d[.s], ::d[.s] 3229 * one of the following formats: unix:d[.s], :d[.s], ::d[.s]