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