NET TIME /SET utility I've written - 8K source
Krehbiel, Richard
rich at kastle.com
Mon Apr 10 19:05:26 GMT 2000
There are a few Linux application servers around our company that need to be
time-synchronized with the corporate network. For company inter/intranet
policy reasons I can't use a superior NTP solution, so I've taken the Samba
smbclient source (client.c) and hatcheted it down into a smallish utility that
connects with an SMB server, accquires the date and time, and sets the local
system time to match.
So - I'd like to get some feedback. Did I waste my time because a better
solution exists? (Remember, I can't use NTP.) Am I unaware of some
fundamental problem that makes the concept unworkable? I'm not a Samba
insider, this is my first experience.
Source is presented below; place it in "source/clients/nettime.c". I've only
tested this with Red Hat 6.x clients against a Windows NT 4.0 AS server, so
it's likely missing some platform details. If this passes muster I plan to
daemon-ify it.
/*
Unix SMB/Netbios implementation.
Version 1.9.
SMB "NET TIME /SET" utility
Copyright (C) Andrew Tridgell 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define NO_SYSLOG
#include "includes.h"
#ifndef REGISTER
#define REGISTER 0
#endif
struct cli_state *cli;
extern BOOL in_client;
static int port = SMB_PORT;
static pstring service;
extern pstring global_myname;
static pstring username;
static pstring workgroup;
extern struct in_addr ipzero;
extern pstring scope;
static int name_type = 0x20;
extern pstring user_socket_options;
extern pstring debugf;
extern int DEBUGLEVEL;
BOOL translation = False;
static BOOL have_ip;
struct in_addr dest_ip;
/****************************************************************************
usage on the program
****************************************************************************/
static void usage(char *pname)
{
DEBUG(0,("Usage: %s server [options]", pname));
DEBUG(0,("\nVersion %s\n",VERSION));
DEBUG(0,("\t-s smb.conf pathname to smb.conf file\n"));
DEBUG(0,("\t-O socket_options socket options to use\n"));
DEBUG(0,("\t-R name resolve order use these name resolution services
only\n"));
DEBUG(0,("\t-i scope use this NetBIOS scope\n"));
DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n"));
DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
DEBUG(0,("\t-p port connect to the specified port\n"));
DEBUG(0,("\t-l log basename. Basename for log/debug files\n"));
DEBUG(0,("\t-h Print this help message.\n"));
DEBUG(0,("\t-I dest IP use this IP to connect to\n"));
DEBUG(0,("\t-E write messages to stderr instead of
stdout\n"));
DEBUG(0,("\t-m max protocol set the max protocol level\n"));
DEBUG(0,("\t-W workgroup set the workgroup name\n"));
DEBUG(0,("\n"));
}
/*
normalize_tv places tv_usec in the range 0 ... 999999
when it is in the range -999999 ... 1999999 i.e. after an addition
or subtraction of normalized values.
*/
static void normalize_tv(struct timeval *tv)
{
if(tv->tv_usec < 0)
tv->tv_sec--, tv->tv_usec += 1000000;
else if(tv->tv_usec >= 1000000)
tv->tv_sec++, tv->tv_usec -= 1000000;
}
/* Perform tv1 -= tv2 */
void subtract_tv(struct timeval *tv1,
struct timeval *tv2)
{
tv1->tv_sec -= tv2->tv_sec;
tv1->tv_usec -= tv2->tv_usec;
normalize_tv(tv1);
}
/*****************************************************
get the server's time and set ourselves to match.
*******************************************************/
int do_nettime(char *a_server)
{
struct cli_state *c;
struct nmb_name called, calling;
struct in_addr ip;
extern struct in_addr ipzero;
struct timeval start, end;
int ok;
char *server = strdup(a_server + 2); /* server name without
leading double \'es */
/* Chop off share name from a_server */
{
char *sp = strchr(server, '\\');
if(sp)
*sp = 0;
}
ip = ipzero;
make_nmb_name(&calling, global_myname, 0x0, "");
make_nmb_name(&called , server, name_type, "");
again:
ip = ipzero;
if (have_ip) ip = dest_ip;
/* have to open a new connection */
if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) == 0) ||
!cli_connect(c, server, &ip)) {
DEBUG(0,("Connection to %s failed\n", server));
if(c)
cli_shutdown(c);
free(server);
return 0; /* Failed to set time.
*/
}
if (!cli_session_request(c, &calling, &called)) {
char *p;
DEBUG(0,("session request to %s failed (%s)\n",
called.name, cli_errstr(c)));
cli_shutdown(c);
if ((p=strchr(called.name, '.'))) {
*p = 0;
goto again;
}
if (strcmp(called.name, "*SMBSERVER")) {
make_nmb_name(&called , "*SMBSERVER", 0x20, "");
goto again;
}
free(server);
return 0; /* Failed to set time.
*/
}
gettimeofday(&start, NULL); /* Get a precise start time */
/* measure the time it takes to negotiate - during which time the
server returns it's time */
if (!cli_negprot(c)) {
DEBUG(0,("protocol negotiation failed\n"));
cli_shutdown(c);
free(server);
return 0;
}
gettimeofday(&end, NULL); /* Get a precise end time */
ok = 0; /* assume the time
can't be set */
subtract_tv(&end, &start); /* Compute duration in end */
if(end.tv_sec == 0 &&
end.tv_usec <= 500000) /* Under half a second? */
{
end.tv_usec = 0;
end.tv_sec = c->servertime;
if(settimeofday(&end, NULL))
perror("settimeofday");
else
{
time_t servertime = c->servertime;
struct tm *tm = localtime(&servertime);
/* Got it! Set the system time. */
printf("Current system time set to %s", asctime(tm));
ok = 1; /* Okay, system
time is set. */
}
}
cli_shutdown(c);
free(server);
return ok;
}
/****************************************************************************
main program
****************************************************************************/
int main(int argc,char *argv[])
{
char *pname = argv[0];
int opt;
extern FILE *dbf;
extern char *optarg;
extern int optind;
static pstring servicesf = CONFIGFILE;
pstring new_name_resolve_order;
*new_name_resolve_order = 0;
DEBUGLEVEL = 2;
setup_logging(pname,True);
TimeInit();
charset_initialise();
in_client = True; /* Make sure that we tell lp_load we are */
if (!lp_load(servicesf,True,False,False)) {
fprintf(stderr, "Can't load %s - run testparm to debug it\n",
servicesf);
}
#ifdef WITH_SSL
sslutil_init(0);
#endif
pstrcpy(workgroup,lp_workgroup());
load_interfaces();
pstrcpy(username,"GUEST");
if (argc < 2) {
usage(pname);
exit(1);
}
pstrcpy(service,argv[1]);
/* Convert any '/' characters in the service name to '\' characters */
string_replace( service, '/','\\');
argc--;
argv++;
if (service[0] != '\\' ||
service[1] != '\\' ||
count_chars(service,'\\') != 2)
{
usage(pname);
printf("\n%s: improper server name %s\n", argv[0], service);
exit(1);
}
while ((opt =
getopt(argc, argv,"s:O:R:M:i:Nn:d:Pp:l:hI:EU:t:m:W:T:D:c:b:"))
!= EOF) {
switch (opt) {
case 's':
pstrcpy(servicesf, optarg);
break;
case 'O':
pstrcpy(user_socket_options,optarg);
break;
case 'R':
pstrcpy(new_name_resolve_order, optarg);
break;
case 'i':
pstrcpy(scope,optarg);
break;
case 'n':
pstrcpy(global_myname,optarg);
break;
case 'd':
if (*optarg == 'A')
DEBUGLEVEL = 10000;
else
DEBUGLEVEL = atoi(optarg);
break;
case 'p':
port = atoi(optarg);
break;
case 'l':
slprintf(debugf,sizeof(debugf)-1, "%s.client",optarg);
break;
case 'h':
usage(pname);
exit(0);
break;
case 'I':
{
dest_ip = *interpret_addr2(optarg);
if (zero_ip(dest_ip))
exit(1);
have_ip = True;
}
break;
case 'E':
dbf = stderr;
break;
case 'W':
pstrcpy(workgroup,optarg);
break;
default:
usage(pname);
exit(1);
}
}
get_myname((*global_myname)?NULL:global_myname);
if(*new_name_resolve_order)
lp_set_name_resolve_order(new_name_resolve_order);
DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
do_nettime(service);
return 0;
}
==== patch for Makefile.in
*** samba/samba-2.0.6/source/Makefile.in Wed Nov 10 21:35:55 1999
--- samba-2.0.6/source/Makefile.in Mon Apr 10 14:57:09 2000
*************** FLAGS = $(ISA) $(FLAGS5) $(PASSWD_FLAGS
*** 77,83 ****
FLAGS32 = $(ISA32) $(FLAGS5) $(PASSWD_FLAGS)
SPROGS = bin/smbd bin/nmbd bin/swat
! PROGS1 = bin/smbclient bin/smbspool bin/testparm bin/testprns bin/smbstatus
@RUNPROG@
PROGS2 = bin/rpcclient bin/smbpasswd bin/make_smbcodepage @WRAP@ @WRAP32@
MPROGS = @MPROGS@
PROGS = $(PROGS1) $(PROGS2) $(MPROGS) bin/nmblookup bin/make_printerdef
--- 77,83 ----
FLAGS32 = $(ISA32) $(FLAGS5) $(PASSWD_FLAGS)
SPROGS = bin/smbd bin/nmbd bin/swat
! PROGS1 = bin/smbclient bin/nettime bin/smbspool bin/testparm bin/testprns
bin/smbstatus @RUNPROG@
PROGS2 = bin/rpcclient bin/smbpasswd bin/make_smbcodepage @WRAP@ @WRAP32@
MPROGS = @MPROGS@
PROGS = $(PROGS1) $(PROGS2) $(MPROGS) bin/nmblookup bin/make_printerdef
*************** SMBWRAPPER_OBJ = smbwrapper/smbw.o smbwr
*** 220,225 ****
--- 220,228 ----
CLIENT_OBJ = client/client.o client/clitar.o \
$(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+ NETTIME_OBJ = client/nettime.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ)
$(LIB_OBJ)
MOUNT_OBJ = client/smbmount.o \
*************** SMBFILTER_OBJ = utils/smbfilter.o $(LIBS
*** 256,261 ****
--- 259,265 ----
$(UBIQX_OBJ) $(LIB_OBJ)
PROTO_OBJ = $(SMBD_OBJ) $(NMBD_OBJ) $(SWAT_OBJ) $(CLIENT_OBJ) \
+ $(NETTIME_OBJ) \
$(RPCCLIENT_OBJ) $(SMBWRAPPER_OBJ) $(SMBTORTURE_OBJ)
PICOBJS = $(SMBWRAPPER_OBJ:.o=.po)
*************** bin/rpcclient: $(RPCCLIENT_OBJ) bin/.dum
*** 371,376 ****
--- 375,384 ----
bin/smbclient: $(CLIENT_OBJ) bin/.dummy
@echo Linking $@
@$(CC) $(FLAGS) -o $@ $(CLIENT_OBJ) $(LDFLAGS) $(LIBS)
+
+ bin/nettime: $(NETTIME_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NETTIME_OBJ) $(LDFLAGS) $(LIBS)
bin/smbspool: $(CUPS_OBJ) bin/.dummy
@echo Linking $@
More information about the samba-technical
mailing list