Print this page
1575 untangle libmlrpc ... pre1:
Move srvsvc_timecheck where it belongs
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
+++ new/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
24 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 /*
28 28 * Client NDR RPC interface.
29 29 */
30 30
31 31 #include <sys/types.h>
32 32 #include <sys/errno.h>
33 33 #include <sys/fcntl.h>
34 -#include <sys/tzfile.h>
35 34 #include <time.h>
36 35 #include <strings.h>
37 36 #include <assert.h>
38 37 #include <errno.h>
39 38 #include <thread.h>
40 -#include <unistd.h>
41 39 #include <syslog.h>
42 40 #include <synch.h>
43 41
44 42 #include <netsmb/smbfs_api.h>
45 43 #include <smbsrv/libsmb.h>
46 44 #include <smbsrv/libsmbns.h>
47 45 #include <smbsrv/libmlrpc.h>
48 46 #include <smbsrv/libmlsvc.h>
49 47 #include <smbsrv/ndl/srvsvc.ndl>
50 48 #include <libsmbrdr.h>
51 49 #include <mlsvc.h>
52 50
53 51 static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
54 52 static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
55 53 static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
56 54 static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
57 55 static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
58 56 static void ndr_xa_release(ndr_client_t *);
59 57
60 58
61 59 /*
62 60 * This call must be made to initialize an RPC client structure and bind
63 61 * to the remote service before any RPCs can be exchanged with that service.
64 62 *
65 63 * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
66 64 * with the client context for an instance of the interface. The handle
67 65 * is zeroed to ensure that it doesn't look like a valid handle -
68 66 * handle content is provided by the remove service.
69 67 *
70 68 * The client points to this top-level handle so that we know when to
71 69 * unbind and teardown the connection. As each handle is initialized it
72 70 * will inherit a reference to the client context.
73 71 *
74 72 * Returns 0 or an NT_STATUS:
75 73 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
76 74 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
77 75 * NT_STATUS_BAD_NETWORK_NAME (tcon, open)
78 76 * NT_STATUS_ACCESS_DENIED (open pipe)
79 77 * NT_STATUS_INVALID_PARAMETER (rpc bind)
80 78 *
81 79 * NT_STATUS_INTERNAL_ERROR (bad args etc)
82 80 * NT_STATUS_NO_MEMORY
83 81 */
84 82 DWORD
85 83 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
86 84 char *username, const char *service)
87 85 {
88 86 struct smb_ctx *ctx = NULL;
89 87 ndr_client_t *clnt = NULL;
90 88 ndr_service_t *svc;
91 89 srvsvc_server_info_t svinfo;
92 90 DWORD status;
93 91 int fd = -1;
94 92 int rc;
95 93
96 94 if (handle == NULL || server == NULL || server[0] == '\0' ||
97 95 domain == NULL || username == NULL)
98 96 return (NT_STATUS_INTERNAL_ERROR);
99 97
100 98 /* In case the service was not registered... */
101 99 if ((svc = ndr_svc_lookup_name(service)) == NULL)
102 100 return (NT_STATUS_INTERNAL_ERROR);
103 101
104 102 /*
105 103 * Set the default based on the assumption that most
106 104 * servers will be Windows 2000 or later. This used to
107 105 * try to get the actual server version, but that RPC
108 106 * is not necessarily allowed anymore, so don't bother.
109 107 */
110 108 bzero(&svinfo, sizeof (srvsvc_server_info_t));
111 109 svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
112 110 svinfo.sv_version_major = 5;
113 111 svinfo.sv_version_minor = 0;
114 112 svinfo.sv_type = SV_TYPE_DEFAULT;
115 113 svinfo.sv_os = NATIVE_OS_WIN2000;
116 114
117 115 /*
118 116 * Some callers pass this when they want a NULL session.
119 117 * Todo: have callers pass an empty string for that.
120 118 */
121 119 if (strcmp(username, MLSVC_ANON_USER) == 0)
122 120 username = "";
123 121
124 122 /*
125 123 * Setup smbfs library handle, authenticate, connect to
126 124 * the IPC$ share. This will reuse an existing connection
127 125 * if the driver already has one for this combination of
128 126 * server, user, domain. It may return any of:
129 127 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
130 128 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
131 129 * NT_STATUS_BAD_NETWORK_NAME (tcon)
132 130 */
133 131 status = smbrdr_ctx_new(&ctx, server, domain, username);
134 132 if (status != NT_STATUS_SUCCESS) {
135 133 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
136 134 "(Srv=%s Dom=%s User=%s), %s (0x%x)",
137 135 server, domain, username,
138 136 xlate_nt_status(status), status);
139 137 /* Tell the DC Locator this DC failed. */
140 138 smb_ddiscover_bad_dc(server);
141 139 goto errout;
142 140 }
143 141
144 142 /*
145 143 * Open the named pipe.
146 144 */
147 145 fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
148 146 if (fd < 0) {
149 147 rc = errno;
150 148 syslog(LOG_DEBUG, "ndr_rpc_bind: "
151 149 "smb_fh_open (%s) err=%d",
152 150 svc->endpoint, rc);
153 151 switch (rc) {
154 152 case EACCES:
155 153 status = NT_STATUS_ACCESS_DENIED;
156 154 break;
157 155 default:
158 156 status = NT_STATUS_BAD_NETWORK_NAME;
159 157 break;
160 158 }
161 159 goto errout;
162 160 }
163 161
164 162 /*
165 163 * Setup the RPC client handle.
166 164 */
167 165 if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) {
168 166 status = NT_STATUS_NO_MEMORY;
169 167 goto errout;
170 168 }
171 169 bzero(clnt, sizeof (ndr_client_t));
172 170
173 171 clnt->handle = &handle->handle;
174 172 clnt->xa_init = ndr_xa_init;
175 173 clnt->xa_exchange = ndr_xa_exchange;
176 174 clnt->xa_read = ndr_xa_read;
177 175 clnt->xa_preserve = ndr_xa_preserve;
178 176 clnt->xa_destruct = ndr_xa_destruct;
179 177 clnt->xa_release = ndr_xa_release;
180 178 clnt->xa_private = ctx;
181 179 clnt->xa_fd = fd;
182 180
183 181 ndr_svc_binding_pool_init(&clnt->binding_list,
184 182 clnt->binding_pool, NDR_N_BINDING_POOL);
185 183
186 184 if ((clnt->heap = ndr_heap_create()) == NULL) {
187 185 status = NT_STATUS_NO_MEMORY;
188 186 goto errout;
189 187 }
190 188
191 189 /*
192 190 * Fill in the caller's handle.
193 191 */
194 192 bzero(&handle->handle, sizeof (ndr_hdid_t));
195 193 handle->clnt = clnt;
196 194 bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
197 195
198 196 /*
199 197 * Do the OtW RPC bind.
200 198 */
201 199 rc = ndr_clnt_bind(clnt, service, &clnt->binding);
202 200 switch (rc) {
203 201 case NDR_DRC_FAULT_OUT_OF_MEMORY:
204 202 status = NT_STATUS_NO_MEMORY;
205 203 break;
206 204 case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */
207 205 status = NT_STATUS_INTERNAL_ERROR;
208 206 break;
209 207 default:
210 208 if (NDR_DRC_IS_FAULT(rc)) {
211 209 status = NT_STATUS_INVALID_PARAMETER;
212 210 break;
213 211 }
214 212 /* FALLTHROUGH */
215 213 case NDR_DRC_OK:
216 214 return (NT_STATUS_SUCCESS);
217 215 }
218 216
219 217 syslog(LOG_DEBUG, "ndr_rpc_bind: "
220 218 "ndr_clnt_bind, %s (0x%x)",
221 219 xlate_nt_status(status), status);
222 220
223 221 errout:
224 222 handle->clnt = NULL;
225 223 if (clnt != NULL) {
226 224 ndr_heap_destroy(clnt->heap);
227 225 free(clnt);
228 226 }
229 227 if (ctx != NULL) {
230 228 if (fd != -1)
231 229 (void) smb_fh_close(fd);
232 230 smbrdr_ctx_free(ctx);
233 231 }
234 232
235 233 return (status);
236 234 }
237 235
238 236 /*
239 237 * Unbind and close the pipe to an RPC service.
240 238 *
241 239 * If the heap has been preserved we need to go through an xa release.
242 240 * The heap is preserved during an RPC call because that's where data
243 241 * returned from the server is stored.
244 242 *
245 243 * Otherwise we destroy the heap directly.
246 244 */
247 245 void
248 246 ndr_rpc_unbind(mlsvc_handle_t *handle)
249 247 {
250 248 ndr_client_t *clnt = handle->clnt;
251 249 struct smb_ctx *ctx = clnt->xa_private;
252 250
253 251 if (clnt->heap_preserved)
254 252 ndr_clnt_free_heap(clnt);
255 253 else
256 254 ndr_heap_destroy(clnt->heap);
257 255
258 256 (void) smb_fh_close(clnt->xa_fd);
259 257 smbrdr_ctx_free(ctx);
260 258 free(clnt);
261 259 bzero(handle, sizeof (mlsvc_handle_t));
262 260 }
263 261
264 262 /*
265 263 * Call the RPC function identified by opnum. The remote service is
266 264 * identified by the handle, which should have been initialized by
267 265 * ndr_rpc_bind.
268 266 *
269 267 * If the RPC call is successful (returns 0), the caller must call
270 268 * ndr_rpc_release to release the heap. Otherwise, we release the
271 269 * heap here.
272 270 */
273 271 int
274 272 ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
275 273 {
276 274 ndr_client_t *clnt = handle->clnt;
277 275 int rc;
278 276
279 277 if (ndr_rpc_get_heap(handle) == NULL)
280 278 return (-1);
281 279
282 280 rc = ndr_clnt_call(clnt->binding, opnum, params);
283 281
284 282 /*
285 283 * Always clear the nonull flag to ensure
286 284 * it is not applied to subsequent calls.
287 285 */
288 286 clnt->nonull = B_FALSE;
289 287
290 288 if (NDR_DRC_IS_FAULT(rc)) {
291 289 ndr_rpc_release(handle);
292 290 return (-1);
293 291 }
294 292
295 293 return (0);
296 294 }
297 295
298 296 /*
299 297 * Outgoing strings should not be null terminated.
300 298 */
301 299 void
302 300 ndr_rpc_set_nonull(mlsvc_handle_t *handle)
303 301 {
304 302 handle->clnt->nonull = B_TRUE;
305 303 }
306 304
307 305 /*
308 306 * Return a reference to the server info.
309 307 */
310 308 const srvsvc_server_info_t *
311 309 ndr_rpc_server_info(mlsvc_handle_t *handle)
312 310 {
313 311 return (&handle->svinfo);
314 312 }
315 313
316 314 /*
317 315 * Return the RPC server OS level.
318 316 */
319 317 uint32_t
320 318 ndr_rpc_server_os(mlsvc_handle_t *handle)
321 319 {
322 320 return (handle->svinfo.sv_os);
323 321 }
324 322
325 323 /*
326 324 * Get the session key from a bound RPC client handle.
327 325 *
328 326 * The key returned is the 16-byte "user session key"
329 327 * established by the underlying authentication protocol
330 328 * (either Kerberos or NTLM). This key is needed for
331 329 * SAM RPC calls such as SamrSetInformationUser, etc.
332 330 * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
333 331 *
334 332 * Returns zero (success) or an errno.
335 333 */
336 334 int
337 335 ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
338 336 unsigned char *ssn_key, size_t len)
339 337 {
340 338 ndr_client_t *clnt = handle->clnt;
341 339 int rc;
342 340
343 341 if (clnt == NULL)
344 342 return (EINVAL);
345 343
346 344 rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len);
347 345 return (rc);
348 346 }
349 347
350 348 void *
351 349 ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
352 350 {
353 351 ndr_heap_t *heap;
354 352
355 353 if ((heap = ndr_rpc_get_heap(handle)) == NULL)
356 354 return (NULL);
357 355
358 356 return (ndr_heap_malloc(heap, size));
359 357 }
360 358
361 359 ndr_heap_t *
362 360 ndr_rpc_get_heap(mlsvc_handle_t *handle)
363 361 {
364 362 ndr_client_t *clnt = handle->clnt;
365 363
366 364 if (clnt->heap == NULL)
367 365 clnt->heap = ndr_heap_create();
368 366
369 367 return (clnt->heap);
370 368 }
371 369
372 370 /*
373 371 * Must be called by RPC clients to free the heap after a successful RPC
374 372 * call, i.e. ndr_rpc_call returned 0. The caller should take a copy
375 373 * of any data returned by the RPC prior to calling this function because
376 374 * returned data is in the heap.
377 375 */
378 376 void
379 377 ndr_rpc_release(mlsvc_handle_t *handle)
380 378 {
381 379 ndr_client_t *clnt = handle->clnt;
382 380
383 381 if (clnt->heap_preserved)
384 382 ndr_clnt_free_heap(clnt);
385 383 else
386 384 ndr_heap_destroy(clnt->heap);
387 385
388 386 clnt->heap = NULL;
389 387 }
390 388
391 389 /*
392 390 * Returns true if the handle is null.
393 391 * Otherwise returns false.
394 392 */
395 393 boolean_t
396 394 ndr_is_null_handle(mlsvc_handle_t *handle)
397 395 {
398 396 static ndr_hdid_t zero_handle;
399 397
400 398 if (handle == NULL || handle->clnt == NULL)
401 399 return (B_TRUE);
402 400
403 401 if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
404 402 return (B_TRUE);
405 403
406 404 return (B_FALSE);
407 405 }
408 406
409 407 /*
410 408 * Returns true if the handle is the top level bind handle.
411 409 * Otherwise returns false.
412 410 */
413 411 boolean_t
414 412 ndr_is_bind_handle(mlsvc_handle_t *handle)
415 413 {
416 414 return (handle->clnt->handle == &handle->handle);
417 415 }
418 416
419 417 /*
420 418 * Pass the client reference from parent to child.
421 419 */
422 420 void
423 421 ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
424 422 {
425 423 child->clnt = parent->clnt;
426 424 bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t));
427 425 }
428 426
429 427 void
430 428 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
431 429 {
432 430 ndr_service_t *svc;
433 431 char *name = "NDR RPC";
434 432 char *s = "unknown";
435 433
436 434 switch (NT_SC_SEVERITY(status)) {
437 435 case NT_STATUS_SEVERITY_SUCCESS:
438 436 s = "success";
439 437 break;
440 438 case NT_STATUS_SEVERITY_INFORMATIONAL:
441 439 s = "info";
442 440 break;
443 441 case NT_STATUS_SEVERITY_WARNING:
444 442 s = "warning";
445 443 break;
446 444 case NT_STATUS_SEVERITY_ERROR:
447 445 s = "error";
448 446 break;
449 447 }
450 448
451 449 if (handle) {
452 450 svc = handle->clnt->binding->service;
453 451 name = svc->name;
454 452 }
455 453
456 454 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
457 455 name, opnum, s, xlate_nt_status(status), status);
458 456 }
459 457
460 458 /*
461 459 * The following functions provide the client callback interface.
462 460 * If the caller hasn't provided a heap, create one here.
463 461 */
464 462 static int
465 463 ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
466 464 {
467 465 ndr_stream_t *recv_nds = &mxa->recv_nds;
468 466 ndr_stream_t *send_nds = &mxa->send_nds;
469 467 ndr_heap_t *heap = clnt->heap;
470 468 int rc;
471 469
472 470 if (heap == NULL) {
473 471 if ((heap = ndr_heap_create()) == NULL)
474 472 return (-1);
475 473
476 474 clnt->heap = heap;
477 475 }
478 476
479 477 mxa->heap = heap;
480 478
481 479 rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
482 480 if (rc == 0)
483 481 rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
484 482 NDR_MODE_RETURN_RECV, heap);
485 483
486 484 if (rc != 0) {
487 485 nds_destruct(&mxa->recv_nds);
488 486 nds_destruct(&mxa->send_nds);
489 487 ndr_heap_destroy(mxa->heap);
490 488 mxa->heap = NULL;
491 489 clnt->heap = NULL;
492 490 return (-1);
493 491 }
494 492
495 493 if (clnt->nonull)
496 494 NDS_SETF(send_nds, NDS_F_NONULL);
497 495
498 496 return (0);
499 497 }
500 498
501 499 /*
502 500 * This is the entry pointy for an RPC client call exchange with
503 501 * a server, which will result in an smbrdr SmbTransact request.
504 502 *
505 503 * SmbTransact should return the number of bytes received, which
506 504 * we record as the PDU size, or a negative error code.
507 505 */
508 506 static int
509 507 ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
510 508 {
511 509 ndr_stream_t *recv_nds = &mxa->recv_nds;
512 510 ndr_stream_t *send_nds = &mxa->send_nds;
513 511 int err, more, nbytes;
514 512
515 513 nbytes = recv_nds->pdu_max_size;
516 514 err = smb_fh_xactnp(clnt->xa_fd,
517 515 send_nds->pdu_size, (char *)send_nds->pdu_base_offset,
518 516 &nbytes, (char *)recv_nds->pdu_base_offset, &more);
519 517 if (err) {
520 518 recv_nds->pdu_size = 0;
521 519 return (-1);
522 520 }
523 521
524 522 recv_nds->pdu_size = nbytes;
525 523 return (0);
526 524 }
527 525
528 526 /*
529 527 * This entry point will be invoked if the xa-exchange response contained
530 528 * only the first fragment of a multi-fragment response. The RPC client
531 529 * code will then make repeated xa-read requests to obtain the remaining
532 530 * fragments, which will result in smbrdr SmbReadX requests.
533 531 *
534 532 * SmbReadX should return the number of bytes received, in which case we
535 533 * expand the PDU size to include the received data, or a negative error
536 534 * code.
537 535 */
538 536 static int
539 537 ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
540 538 {
541 539 ndr_stream_t *nds = &mxa->recv_nds;
542 540 int len;
543 541 int nbytes;
544 542
545 543 if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
546 544 return (-1);
547 545
548 546 nbytes = smb_fh_read(clnt->xa_fd, 0, len,
549 547 (char *)nds->pdu_base_offset + nds->pdu_size);
550 548
551 549 if (nbytes < 0)
552 550 return (-1);
553 551
554 552 nds->pdu_size += nbytes;
555 553
556 554 if (nds->pdu_size > nds->pdu_max_size) {
557 555 nds->pdu_size = nds->pdu_max_size;
558 556 return (-1);
559 557 }
560 558
561 559 return (nbytes);
562 560 }
563 561
564 562 /*
565 563 * Preserve the heap so that the client application has access to data
566 564 * returned from the server after an RPC call.
567 565 */
568 566 static void
569 567 ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
570 568 {
571 569 assert(clnt->heap == mxa->heap);
572 570
573 571 clnt->heap_preserved = B_TRUE;
574 572 mxa->heap = NULL;
575 573 }
576 574
577 575 /*
578 576 * Dispose of the transaction streams. If the heap has not been
579 577 * preserved, we can destroy it here.
580 578 */
581 579 static void
582 580 ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
583 581 {
584 582 nds_destruct(&mxa->recv_nds);
585 583 nds_destruct(&mxa->send_nds);
586 584
587 585 if (!clnt->heap_preserved) {
588 586 ndr_heap_destroy(mxa->heap);
589 587 mxa->heap = NULL;
590 588 clnt->heap = NULL;
591 589 }
592 590 }
593 591
594 592 /*
595 593 * Dispose of a preserved heap.
↓ open down ↓ |
545 lines elided |
↑ open up ↑ |
596 594 */
597 595 static void
598 596 ndr_xa_release(ndr_client_t *clnt)
599 597 {
600 598 if (clnt->heap_preserved) {
601 599 ndr_heap_destroy(clnt->heap);
602 600 clnt->heap = NULL;
603 601 clnt->heap_preserved = B_FALSE;
604 602 }
605 603 }
606 -
607 -
608 -/*
609 - * Compare the time here with the remote time on the server
610 - * and report clock skew.
611 - */
612 -void
613 -ndr_srvsvc_timecheck(char *server, char *domain)
614 -{
615 - char hostname[MAXHOSTNAMELEN];
616 - struct timeval dc_tv;
617 - struct tm dc_tm;
618 - struct tm *tm;
619 - time_t tnow;
620 - time_t tdiff;
621 - int priority;
622 -
623 - if (srvsvc_net_remote_tod(server, domain, &dc_tv, &dc_tm) < 0) {
624 - syslog(LOG_DEBUG, "srvsvc_net_remote_tod failed");
625 - return;
626 - }
627 -
628 - tnow = time(NULL);
629 -
630 - if (tnow > dc_tv.tv_sec)
631 - tdiff = (tnow - dc_tv.tv_sec) / SECSPERMIN;
632 - else
633 - tdiff = (dc_tv.tv_sec - tnow) / SECSPERMIN;
634 -
635 - if (tdiff != 0) {
636 - (void) strlcpy(hostname, "localhost", MAXHOSTNAMELEN);
637 - (void) gethostname(hostname, MAXHOSTNAMELEN);
638 -
639 - priority = (tdiff > 2) ? LOG_NOTICE : LOG_DEBUG;
640 - syslog(priority, "DC [%s] clock skew detected: %u minutes",
641 - server, tdiff);
642 -
643 - tm = gmtime(&dc_tv.tv_sec);
644 - syslog(priority, "%-8s UTC: %s", server, asctime(tm));
645 - tm = gmtime(&tnow);
646 - syslog(priority, "%-8s UTC: %s", hostname, asctime(tm));
647 - }
648 -}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX