1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Server Service (srvsvc) client side RPC library interface. The 30 * srvsvc interface allows a client to query a server for information 31 * on shares, sessions, connections and files on the server. Some 32 * functions are available via anonymous IPC while others require 33 * administrator privilege. Also, some functions return NT status 34 * values while others return Win32 errors codes. 35 */ 36 37 #include <sys/errno.h> 38 #include <stdio.h> 39 #include <time.h> 40 #include <strings.h> 41 #include <time.h> 42 43 #include <smbsrv/libsmb.h> 44 #include <smbsrv/libsmbrdr.h> 45 #include <smbsrv/smbinfo.h> 46 #include <smbsrv/ntstatus.h> 47 #include <smbsrv/ndl/srvsvc.ndl> 48 #include <smbsrv/mlsvc_util.h> 49 50 /* 51 * Information level for NetShareGetInfo. 52 */ 53 DWORD srvsvc_info_level = 1; 54 55 static int srvsvc_net_remote_tod(char *, char *, struct timeval *, struct tm *); 56 57 /* 58 * Ensure that an appropriate session and logon exists for the srvsvc 59 * client calls. Open and bind the RPC interface. 60 * 61 * On success 0 is returned. Otherwise a -ve error code. 62 */ 63 int 64 srvsvc_open(int ipc_mode, char *server, char *domain, char *username, 65 char *password, mlsvc_handle_t *handle, mlrpc_heapref_t *heapref) 66 { 67 smb_ntdomain_t *di; 68 int fid; 69 int rc; 70 71 if ((di = smb_getdomaininfo(0)) == NULL) 72 return (-1); 73 74 if (server == NULL || domain == NULL) { 75 server = di->server; 76 domain = di->domain; 77 } 78 79 switch (ipc_mode) { 80 case MLSVC_IPC_USER: 81 /* 82 * Use the supplied credentials. 83 */ 84 rc = mlsvc_user_logon(server, domain, username, password); 85 break; 86 87 case MLSVC_IPC_ADMIN: 88 /* 89 * Use the resource domain administrator credentials. 90 */ 91 server = di->server; 92 domain = di->domain; 93 username = smbrdr_ipc_get_user(); 94 95 rc = mlsvc_admin_logon(server, domain); 96 break; 97 98 case MLSVC_IPC_ANON: 99 default: 100 rc = mlsvc_anonymous_logon(server, domain, &username); 101 break; 102 } 103 104 if (rc != 0) 105 return (-1); 106 107 fid = mlsvc_open_pipe(server, domain, username, "\\srvsvc"); 108 if (fid < 0) 109 return (-1); 110 111 if ((rc = mlsvc_rpc_bind(handle, fid, "SRVSVC")) < 0) { 112 (void) mlsvc_close_pipe(fid); 113 return (rc); 114 } 115 116 rc = mlsvc_rpc_init(heapref); 117 return (rc); 118 } 119 120 /* 121 * Close the srvsvc pipe and free the associated context. This function 122 * should only be called if the open was successful. 123 */ 124 void 125 srvsvc_close(mlsvc_handle_t *handle, mlrpc_heapref_t *heapref) 126 { 127 mlsvc_rpc_free(handle->context, heapref); 128 (void) mlsvc_close_pipe(handle->context->fid); 129 free(handle->context); 130 } 131 132 /* 133 * This is a client side routine for NetShareGetInfo. 134 * Levels 0 and 1 work with an anonymous connection but 135 * level 2 requires administrator access. 136 */ 137 int 138 srvsvc_net_share_get_info(char *server, char *domain, char *netname) 139 { 140 struct mlsm_NetShareGetInfo arg; 141 mlsvc_handle_t handle; 142 mlrpc_heapref_t heap; 143 int rc; 144 int opnum; 145 struct mslm_NetShareGetInfo0 *info0; 146 struct mslm_NetShareGetInfo1 *info1; 147 struct mslm_NetShareGetInfo2 *info2; 148 int ipc_mode; 149 int len; 150 151 if (netname == NULL) 152 return (-1); 153 154 if (srvsvc_info_level == 2) 155 ipc_mode = MLSVC_IPC_ADMIN; 156 else 157 ipc_mode = MLSVC_IPC_ANON; 158 159 rc = srvsvc_open(ipc_mode, server, domain, 0, 0, &handle, &heap); 160 if (rc != 0) 161 return (-1); 162 163 opnum = SRVSVC_OPNUM_NetShareGetInfo; 164 bzero(&arg, sizeof (struct mlsm_NetShareGetInfo)); 165 166 len = strlen(server) + 4; 167 arg.servername = mlrpc_heap_malloc(heap.heap, len); 168 if (arg.servername == NULL) { 169 srvsvc_close(&handle, &heap); 170 return (-1); 171 } 172 173 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 174 arg.netname = (LPTSTR)netname; 175 arg.level = srvsvc_info_level; /* share information level */ 176 177 rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap); 178 if ((rc != 0) || (arg.status != 0)) { 179 srvsvc_close(&handle, &heap); 180 return (-1); 181 } 182 183 switch (arg.result.switch_value) { 184 case 0: 185 info0 = arg.result.ru.info0; 186 smb_tracef("srvsvc shi0_netname=%s", info0->shi0_netname); 187 break; 188 189 case 1: 190 info1 = arg.result.ru.info1; 191 smb_tracef("srvsvc shi1_netname=%s", info1->shi1_netname); 192 smb_tracef("srvsvc shi1_type=%u", info1->shi1_type); 193 194 if (info1->shi1_comment) 195 smb_tracef("srvsvc shi1_comment=%s", 196 info1->shi1_comment); 197 break; 198 199 case 2: 200 info2 = arg.result.ru.info2; 201 smb_tracef("srvsvc shi2_netname=%s", info2->shi2_netname); 202 smb_tracef("srvsvc shi2_type=%u", info2->shi2_type); 203 204 if (info2->shi2_comment) 205 smb_tracef("srvsvc shi2_comment=%s", 206 info2->shi2_comment); 207 208 smb_tracef("srvsvc shi2_perms=%d", info2->shi2_permissions); 209 smb_tracef("srvsvc shi2_max_use=%d", info2->shi2_max_uses); 210 smb_tracef("srvsvc shi2_cur_use=%d", info2->shi2_current_uses); 211 212 if (info2->shi2_path) 213 smb_tracef("srvsvc shi2_path=%s", info2->shi2_path); 214 215 if (info2->shi2_passwd) 216 smb_tracef("srvsvc shi2_passwd=%s", info2->shi2_passwd); 217 break; 218 219 default: 220 smb_tracef("srvsvc: unknown level"); 221 break; 222 } 223 224 srvsvc_close(&handle, &heap); 225 return (0); 226 } 227 228 /* 229 * This is a client side routine for NetSessionEnum. 230 * NetSessionEnum requires administrator rights. 231 */ 232 int 233 srvsvc_net_session_enum(char *server, char *domain, char *netname) 234 { 235 struct mslm_NetSessionEnum arg; 236 mlsvc_handle_t handle; 237 mlrpc_heapref_t heap; 238 int rc; 239 int opnum; 240 struct mslm_infonres infonres; 241 struct mslm_SESSION_INFO_1 *nsi1; 242 int len; 243 244 if (netname == NULL) 245 return (-1); 246 247 rc = srvsvc_open(MLSVC_IPC_ADMIN, server, domain, 0, 0, &handle, &heap); 248 if (rc != 0) 249 return (-1); 250 251 opnum = SRVSVC_OPNUM_NetSessionEnum; 252 bzero(&arg, sizeof (struct mslm_NetSessionEnum)); 253 254 len = strlen(server) + 4; 255 arg.servername = mlrpc_heap_malloc(heap.heap, len); 256 if (arg.servername == NULL) { 257 srvsvc_close(&handle, &heap); 258 return (-1); 259 } 260 261 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 262 infonres.entriesread = 0; 263 infonres.entries = 0; 264 arg.level = 1; 265 arg.result.level = 1; 266 arg.result.bufptr.p = &infonres; 267 arg.resume_handle = 0; 268 arg.pref_max_len = 0xFFFFFFFF; 269 270 rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap); 271 if ((rc != 0) || (arg.status != 0)) { 272 srvsvc_close(&handle, &heap); 273 return (-1); 274 } 275 276 /* Only the first session info is dereferenced. */ 277 nsi1 = ((struct mslm_infonres *)arg.result.bufptr.p)->entries; 278 279 smb_tracef("srvsvc switch_value=%d", arg.level); 280 smb_tracef("srvsvc sesi1_cname=%s", nsi1->sesi1_cname); 281 smb_tracef("srvsvc sesi1_uname=%s", nsi1->sesi1_uname); 282 smb_tracef("srvsvc sesi1_nopens=%u", nsi1->sesi1_nopens); 283 smb_tracef("srvsvc sesi1_time=%u", nsi1->sesi1_time); 284 smb_tracef("srvsvc sesi1_itime=%u", nsi1->sesi1_itime); 285 smb_tracef("srvsvc sesi1_uflags=%u", nsi1->sesi1_uflags); 286 287 srvsvc_close(&handle, &heap); 288 return (0); 289 } 290 291 /* 292 * This is a client side routine for NetConnectEnum. 293 * NetConnectEnum requires administrator rights. 294 * Level 0 and level 1 requests are supported. 295 */ 296 int 297 srvsvc_net_connect_enum(char *server, char *domain, char *netname, int level) 298 { 299 struct mslm_NetConnectEnum arg; 300 mlsvc_handle_t handle; 301 mlrpc_heapref_t heap; 302 int rc; 303 int opnum; 304 struct mslm_NetConnectInfo1 info1; 305 struct mslm_NetConnectInfo0 info0; 306 struct mslm_NetConnectInfoBuf1 *cib1; 307 int len; 308 309 if (netname == NULL) 310 return (-1); 311 312 rc = srvsvc_open(MLSVC_IPC_ADMIN, server, domain, 0, 0, &handle, &heap); 313 if (rc != 0) 314 return (-1); 315 316 opnum = SRVSVC_OPNUM_NetConnectEnum; 317 bzero(&arg, sizeof (struct mslm_NetConnectEnum)); 318 319 len = strlen(server) + 4; 320 arg.servername = mlrpc_heap_malloc(heap.heap, len); 321 if (arg.servername == NULL) { 322 srvsvc_close(&handle, &heap); 323 return (-1); 324 } 325 326 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 327 arg.qualifier = (LPTSTR)netname; 328 329 switch (level) { 330 case 0: 331 arg.info.level = 0; 332 arg.info.switch_value = 0; 333 arg.info.ru.info0 = &info0; 334 info0.entries_read = 0; 335 info0.ci0 = 0; 336 break; 337 case 1: 338 arg.info.level = 1; 339 arg.info.switch_value = 1; 340 arg.info.ru.info1 = &info1; 341 info1.entries_read = 0; 342 info1.ci1 = 0; 343 break; 344 default: 345 srvsvc_close(&handle, &heap); 346 return (-1); 347 } 348 349 arg.resume_handle = 0; 350 arg.pref_max_len = 0xFFFFFFFF; 351 352 rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap); 353 if ((rc != 0) || (arg.status != 0)) { 354 srvsvc_close(&handle, &heap); 355 return (-1); 356 } 357 358 smb_tracef("srvsvc switch_value=%d", arg.info.switch_value); 359 360 switch (level) { 361 case 0: 362 if (arg.info.ru.info0 && arg.info.ru.info0->ci0) { 363 smb_tracef("srvsvc coni0_id=%x", 364 arg.info.ru.info0->ci0->coni0_id); 365 } 366 break; 367 case 1: 368 if (arg.info.ru.info1 && arg.info.ru.info1->ci1) { 369 cib1 = arg.info.ru.info1->ci1; 370 371 smb_tracef("srvsvc coni_uname=%s", 372 cib1->coni1_username ? 373 (char *)cib1->coni1_username : "(null)"); 374 smb_tracef("srvsvc coni1_netname=%s", 375 cib1->coni1_netname ? 376 (char *)cib1->coni1_netname : "(null)"); 377 smb_tracef("srvsvc coni1_nopens=%u", 378 cib1->coni1_num_opens); 379 smb_tracef("srvsvc coni1_time=%u", cib1->coni1_time); 380 smb_tracef("srvsvc coni1_num_users=%u", 381 cib1->coni1_num_users); 382 } 383 break; 384 385 default: 386 smb_tracef("srvsvc: unknown level"); 387 break; 388 } 389 390 srvsvc_close(&handle, &heap); 391 return (0); 392 } 393 394 /* 395 * Synchronize the local system clock with the domain controller. 396 */ 397 void 398 srvsvc_timesync(void) 399 { 400 smb_ntdomain_t *di; 401 struct timeval tv; 402 struct tm tm; 403 time_t tsecs; 404 405 if ((di = smb_getdomaininfo(0)) == NULL) 406 return; 407 408 if (srvsvc_net_remote_tod(di->server, di->domain, &tv, &tm) != 0) 409 return; 410 411 if (settimeofday(&tv, 0)) 412 smb_tracef("unable to set system time"); 413 414 tsecs = time(0); 415 (void) localtime_r(&tsecs, &tm); 416 smb_tracef("SrvsvcTimeSync %s", ctime((time_t *)&tv.tv_sec)); 417 } 418 419 /* 420 * NetRemoteTOD to get the current GMT time from a Windows NT server. 421 */ 422 int 423 srvsvc_gettime(unsigned long *t) 424 { 425 smb_ntdomain_t *di; 426 struct timeval tv; 427 struct tm tm; 428 429 if ((di = smb_getdomaininfo(0)) == NULL) 430 return (-1); 431 432 if (srvsvc_net_remote_tod(di->server, di->domain, &tv, &tm) != 0) 433 return (-1); 434 435 *t = tv.tv_sec; 436 return (0); 437 } 438 439 /* 440 * This is a client side routine for NetRemoteTOD, which gets the time 441 * and date from a remote system. The time information is returned in 442 * the timeval and tm. 443 * 444 * typedef struct _TIME_OF_DAY_INFO { 445 * DWORD tod_elapsedt; // seconds since 00:00:00 January 1 1970 GMT 446 * DWORD tod_msecs; // arbitrary milliseconds (since reset) 447 * DWORD tod_hours; // current hour [0-23] 448 * DWORD tod_mins; // current minute [0-59] 449 * DWORD tod_secs; // current second [0-59] 450 * DWORD tod_hunds; // current hundredth (0.01) second [0-99] 451 * LONG tod_timezone; // time zone of the server 452 * DWORD tod_tinterval; // clock tick time interval 453 * DWORD tod_day; // day of the month [1-31] 454 * DWORD tod_month; // month of the year [1-12] 455 * DWORD tod_year; // current year 456 * DWORD tod_weekday; // day of the week since sunday [0-6] 457 * } TIME_OF_DAY_INFO; 458 * 459 * The time zone of the server is calculated in minutes from Greenwich 460 * Mean Time (GMT). For time zones west of Greenwich, the value is 461 * positive; for time zones east of Greenwich, the value is negative. 462 * A value of -1 indicates that the time zone is undefined. 463 * 464 * The clock tick value represents a resolution of one ten-thousandth 465 * (0.0001) second. 466 */ 467 int 468 srvsvc_net_remote_tod(char *server, char *domain, struct timeval *tv, 469 struct tm *tm) 470 { 471 char timebuf[64]; 472 struct mslm_NetRemoteTOD arg; 473 struct mslm_TIME_OF_DAY_INFO *tod; 474 mlsvc_handle_t handle; 475 mlrpc_heapref_t heap; 476 int rc; 477 int opnum; 478 int len; 479 480 rc = srvsvc_open(MLSVC_IPC_ANON, server, domain, 0, 0, &handle, &heap); 481 if (rc != 0) 482 return (-1); 483 484 opnum = SRVSVC_OPNUM_NetRemoteTOD; 485 bzero(&arg, sizeof (struct mslm_NetRemoteTOD)); 486 487 len = strlen(server) + 4; 488 arg.servername = mlrpc_heap_malloc(heap.heap, len); 489 if (arg.servername == NULL) { 490 srvsvc_close(&handle, &heap); 491 return (-1); 492 } 493 494 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 495 496 rc = mlsvc_rpc_call(handle.context, opnum, &arg, &heap); 497 if ((rc != 0) || (arg.status != 0)) { 498 srvsvc_close(&handle, &heap); 499 return (-1); 500 } 501 502 /* 503 * We're assigning milliseconds to microseconds 504 * here but the value's not really relevant. 505 */ 506 tod = arg.bufptr; 507 508 if (tv) { 509 tv->tv_sec = tod->tod_elapsedt; 510 tv->tv_usec = tod->tod_msecs; 511 smb_tracef("RemoteTime: %s", ctime(&tv->tv_sec)); 512 } 513 514 if (tm) { 515 tm->tm_sec = tod->tod_secs; 516 tm->tm_min = tod->tod_mins; 517 tm->tm_hour = tod->tod_hours; 518 tm->tm_mday = tod->tod_day; 519 tm->tm_mon = tod->tod_month - 1; 520 tm->tm_year = tod->tod_year - 1900; 521 tm->tm_wday = tod->tod_weekday; 522 523 (void) strftime(timebuf, sizeof (timebuf), 524 "NetRemoteTOD: %D %T", tm); 525 smb_tracef("NetRemoteTOD: %s", timebuf); 526 } 527 528 srvsvc_close(&handle, &heap); 529 return (0); 530 } 531 532 void 533 srvsvc_net_test(char *server, char *domain, char *netname) 534 { 535 smb_ntdomain_t *di; 536 537 (void) smb_tracef("%s %s %s", server, domain, netname); 538 539 if ((di = smb_getdomaininfo(0)) != NULL) { 540 server = di->server; 541 domain = di->domain; 542 } 543 544 (void) srvsvc_net_share_get_info(server, domain, netname); 545 #if 0 546 /* 547 * The NetSessionEnum server-side definition was updated. 548 * Disabled until the client-side has been updated. 549 */ 550 (void) srvsvc_net_session_enum(server, domain, netname); 551 #endif 552 (void) srvsvc_net_connect_enum(server, domain, netname, 0); 553 (void) srvsvc_net_connect_enum(server, domain, netname, 1); 554 } 555