--- samba-4.21.1/source3/utils/net_time.c 2024-07-29 11:03:15.522632000 +0200 +++ samba-4.21.1-liu/source3/utils/net_time.c 2024-12-09 15:45:41.263028000 +0100 @@ -77,6 +77,57 @@ return ret; } +static struct timespec cli_server_timespec(const char *host, + const struct sockaddr_storage *dest_ss, + int *zone) +{ + struct timespec ret; + struct cli_state *cli = NULL; + NTSTATUS status; + + status = cli_connect_nb(talloc_tos(), + host, + dest_ss, + 0, + 0x20, + lp_netbios_name(), + SMB_SIGNING_DEFAULT, + 0, + &cli); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { + fprintf(stderr, "Can't contact server %s. NetBIOS support disabled," + " Error %s\n", host, nt_errstr(status)); + } else { + fprintf(stderr, "Can't contact server %s. Error %s\n", + host, nt_errstr(status)); + } + goto done; + } + + status = smbXcli_negprot(cli->conn, + cli->timeout, + lp_client_min_protocol(), + lp_client_max_protocol(), + NULL, + NULL, + NULL); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, _("Protocol negotiation failed: %s\n"), + nt_errstr(status)); + goto done; + } + + ret = cli_state_server_timespec(cli); + if (zone) *zone = smb1cli_conn_server_time_zone(cli->conn); + +done: + if (cli) { + cli_shutdown(cli); + } + return ret; +} + /* find the servers time on the opt_host host */ static time_t nettime(struct net_context *c, int *zone) { @@ -84,6 +135,13 @@ c->opt_have_ip? &c->opt_dest_ip : NULL, zone); } +/* find the servers time on the opt_host host */ +static struct timespec nettimespec(struct net_context *c, int *zone) +{ + return cli_server_timespec(c->opt_host, + c->opt_have_ip? &c->opt_dest_ip : NULL, zone); +} + /* return a time as a string ready to be passed to /bin/date */ static const char *systime(time_t t) { @@ -99,6 +157,21 @@ tm->tm_min, tm->tm_year + 1900, tm->tm_sec); } + +static const char *sysisotime(time_t t) +{ + struct tm *tm; + + tm = localtime(&t); + if (!tm) { + return "unknown"; + } + + return talloc_asprintf(talloc_tos(), "%d-%02d-%02d %02d:%02d:%02d", + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +} + int net_time_usage(struct net_context *c, int argc, const char **argv) { d_printf(_( @@ -146,6 +219,7 @@ { time_t t; + if (c->display_usage || c->opt_host == NULL) { d_printf( "%s\n" "net time system\n" @@ -160,10 +234,76 @@ if (t == 0) return -1; printf("%s\n", systime(t)); + return 0; +} + +static int timespec_diff(const struct timespec *ap, + const struct timespec *bp, + struct timespec *rp) { + struct timespec r; + int rc; + + + if (!rp) + rp = &r; + + if (ap->tv_sec == bp->tv_sec && ap->tv_nsec == bp->tv_nsec) { + rp->tv_sec = 0; + rp->tv_nsec = 0; return 0; + } + + if (ap->tv_sec < bp->tv_sec || + (ap->tv_sec == bp->tv_sec && ap->tv_nsec < bp->tv_nsec)) { + rc = -1; + rp->tv_sec = bp->tv_sec - ap->tv_sec; + rp->tv_nsec = bp->tv_nsec - ap->tv_nsec; + } else { + rc = 1; + rp->tv_sec = ap->tv_sec - bp->tv_sec; + rp->tv_nsec = ap->tv_nsec - bp->tv_nsec; + } + + if (rp->tv_nsec < 0) { + --rp->tv_sec; + rp->tv_nsec += 1000000000L; + } + + return rc; } +/* display the offset between local and remote time */ +static int net_time_offset(struct net_context *c, int argc, const char **argv) +{ + struct timespec ts, tn, td; + int d; + + + if (c->display_usage || c->opt_host == NULL) { + d_printf( "%s\n" + "net time offset\n" + " %s\n", + _("Usage:"), + _("Output local vs remote time server (-S server) " + "offset (seconds.nanoseconds)")); + return 0; + } + ts = nettimespec(c, NULL); + + clock_gettime(CLOCK_REALTIME, &tn); + + printf("Local: %s.%09d\n", sysisotime(tn.tv_sec), tn.tv_nsec); + printf("Remote: %s.%09d\n", sysisotime(ts.tv_sec), ts.tv_nsec); + + d = timespec_diff(&ts, &tn, &td); + printf("Offset: %s%d.%09d\n", + (d > 0 ? "+" : (d < 0 ? "-" : "")), + td.tv_sec, td.tv_nsec); + + return 0; +} + /* display the remote time server's offset to UTC */ static int net_time_zone(struct net_context *c, int argc, const char **argv) { @@ -210,6 +350,14 @@ N_("Display time ready for /bin/date"), N_("net time system\n" " Display time ready for /bin/date") + }, + { + "offset", + net_time_offset, + NET_TRANSPORT_LOCAL, + N_("Display difference between remote and local time"), + N_("net time offset\n" + " Display difference between remote and local time") }, { "set", --- samba-4.21.1/source3/libsmb/clientgen.c 2024-07-29 11:03:15.354630500 +0200 +++ samba-4.21.1-liu/source3/libsmb/clientgen.c 2024-12-09 10:34:17.261313000 +0100 @@ -503,6 +503,14 @@ return t; } +struct timespec cli_state_server_timespec(struct cli_state *cli) +{ + NTTIME nt; + + nt = smbXcli_conn_server_system_time(cli->conn); + return nt_time_to_full_timespec(nt); +} + struct cli_echo_state { uint8_t dummy; }; --- samba-4.21.1/source3/libsmb/proto.h 2024-07-29 11:03:15.362630600 +0200 +++ samba-4.21.1-liu/source3/libsmb/proto.h 2024-12-09 13:27:18.026438000 +0100 @@ -208,6 +208,7 @@ bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive); uint32_t cli_state_available_size(struct cli_state *cli, uint32_t ofs); time_t cli_state_server_time(struct cli_state *cli); +struct timespec cli_state_server_timespec(struct cli_state *cli); struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, uint16_t num_echos, DATA_BLOB data);