1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21*148c5f43SAlan Wright 
22da6c28aaSamw /*
23*148c5f43SAlan Wright  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * Server Service (srvsvc) client side RPC library interface. The
28da6c28aaSamw  * srvsvc interface allows a client to query a server for information
29da6c28aaSamw  * on shares, sessions, connections and files on the server. Some
30da6c28aaSamw  * functions are available via anonymous IPC while others require
31da6c28aaSamw  * administrator privilege. Also, some functions return NT status
32da6c28aaSamw  * values while others return Win32 errors codes.
33da6c28aaSamw  */
34da6c28aaSamw 
35da6c28aaSamw #include <sys/errno.h>
36da6c28aaSamw #include <stdio.h>
37da6c28aaSamw #include <time.h>
38da6c28aaSamw #include <strings.h>
39da6c28aaSamw 
40da6c28aaSamw #include <smbsrv/libsmb.h>
418d7e4166Sjose borrego #include <smbsrv/libmlsvc.h>
42da6c28aaSamw #include <smbsrv/smbinfo.h>
43da6c28aaSamw #include <smbsrv/ndl/srvsvc.ndl>
44da6c28aaSamw 
45da6c28aaSamw /*
46da6c28aaSamw  * Information level for NetShareGetInfo.
47da6c28aaSamw  */
48da6c28aaSamw DWORD srvsvc_info_level = 1;
49da6c28aaSamw 
50da6c28aaSamw /*
518d7e4166Sjose borrego  * Bind to the the SRVSVC.
52da6c28aaSamw  *
5355bf511dSas  * If username argument is NULL, an anonymous connection will be established.
5455bf511dSas  * Otherwise, an authenticated connection will be established.
55da6c28aaSamw  */
5655bf511dSas static int
578d7e4166Sjose borrego srvsvc_open(char *server, char *domain, char *username, mlsvc_handle_t *handle)
58da6c28aaSamw {
59a0aa776eSAlan Wright 	smb_domainex_t di;
60da6c28aaSamw 
61da6c28aaSamw 	if (server == NULL || domain == NULL) {
628d7e4166Sjose borrego 		if (!smb_domain_getinfo(&di))
6355bf511dSas 			return (-1);
64da6c28aaSamw 
658d7e4166Sjose borrego 		server = di.d_dc;
66a0aa776eSAlan Wright 		domain = di.d_primary.di_nbname;
6755bf511dSas 	}
68da6c28aaSamw 
6955bf511dSas 	if (username == NULL)
7055bf511dSas 		username = MLSVC_ANON_USER;
71da6c28aaSamw 
728d7e4166Sjose borrego 	if (ndr_rpc_bind(handle, server, domain, username, "SRVSVC") < 0)
73da6c28aaSamw 		return (-1);
74da6c28aaSamw 
758d7e4166Sjose borrego 	return (0);
76da6c28aaSamw }
77da6c28aaSamw 
78da6c28aaSamw /*
798d7e4166Sjose borrego  * Unbind the SRVSVC connection.
80da6c28aaSamw  */
818d7e4166Sjose borrego static void
828d7e4166Sjose borrego srvsvc_close(mlsvc_handle_t *handle)
83da6c28aaSamw {
848d7e4166Sjose borrego 	ndr_rpc_unbind(handle);
85da6c28aaSamw }
86da6c28aaSamw 
87da6c28aaSamw /*
88da6c28aaSamw  * This is a client side routine for NetShareGetInfo.
89da6c28aaSamw  * Levels 0 and 1 work with an anonymous connection but
90da6c28aaSamw  * level 2 requires administrator access.
91da6c28aaSamw  */
92da6c28aaSamw int
93da6c28aaSamw srvsvc_net_share_get_info(char *server, char *domain, char *netname)
94da6c28aaSamw {
95da6c28aaSamw 	struct mlsm_NetShareGetInfo arg;
96da6c28aaSamw 	mlsvc_handle_t handle;
97da6c28aaSamw 	int rc;
98da6c28aaSamw 	int opnum;
99eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	struct mslm_NetShareInfo_0 *info0;
100eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	struct mslm_NetShareInfo_1 *info1;
101eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	struct mslm_NetShareInfo_2 *info2;
102da6c28aaSamw 	int len;
103a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
104da6c28aaSamw 
105da6c28aaSamw 	if (netname == NULL)
106da6c28aaSamw 		return (-1);
107da6c28aaSamw 
108da6c28aaSamw 	if (srvsvc_info_level == 2)
109a0aa776eSAlan Wright 		smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
110da6c28aaSamw 
1118d7e4166Sjose borrego 	if (srvsvc_open(server, domain, user, &handle) != 0)
112da6c28aaSamw 		return (-1);
113da6c28aaSamw 
114da6c28aaSamw 	opnum = SRVSVC_OPNUM_NetShareGetInfo;
115da6c28aaSamw 	bzero(&arg, sizeof (struct mlsm_NetShareGetInfo));
116da6c28aaSamw 
117da6c28aaSamw 	len = strlen(server) + 4;
1188d7e4166Sjose borrego 	arg.servername = ndr_rpc_malloc(&handle, len);
119da6c28aaSamw 	if (arg.servername == NULL) {
1208d7e4166Sjose borrego 		srvsvc_close(&handle);
121da6c28aaSamw 		return (-1);
122da6c28aaSamw 	}
123da6c28aaSamw 
124da6c28aaSamw 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
125da6c28aaSamw 	arg.netname = (LPTSTR)netname;
126da6c28aaSamw 	arg.level = srvsvc_info_level; /* share information level */
127da6c28aaSamw 
1288d7e4166Sjose borrego 	rc = ndr_rpc_call(&handle, opnum, &arg);
129da6c28aaSamw 	if ((rc != 0) || (arg.status != 0)) {
1308d7e4166Sjose borrego 		srvsvc_close(&handle);
131da6c28aaSamw 		return (-1);
132da6c28aaSamw 	}
133da6c28aaSamw 
134da6c28aaSamw 	switch (arg.result.switch_value) {
135da6c28aaSamw 	case 0:
136da6c28aaSamw 		info0 = arg.result.ru.info0;
137da6c28aaSamw 		smb_tracef("srvsvc shi0_netname=%s", info0->shi0_netname);
138da6c28aaSamw 		break;
139da6c28aaSamw 
140da6c28aaSamw 	case 1:
141da6c28aaSamw 		info1 = arg.result.ru.info1;
142da6c28aaSamw 		smb_tracef("srvsvc shi1_netname=%s", info1->shi1_netname);
143da6c28aaSamw 		smb_tracef("srvsvc shi1_type=%u", info1->shi1_type);
144da6c28aaSamw 
145da6c28aaSamw 		if (info1->shi1_comment)
146da6c28aaSamw 			smb_tracef("srvsvc shi1_comment=%s",
147da6c28aaSamw 			    info1->shi1_comment);
148da6c28aaSamw 		break;
149da6c28aaSamw 
150da6c28aaSamw 	case 2:
151da6c28aaSamw 		info2 = arg.result.ru.info2;
152da6c28aaSamw 		smb_tracef("srvsvc shi2_netname=%s", info2->shi2_netname);
153da6c28aaSamw 		smb_tracef("srvsvc shi2_type=%u", info2->shi2_type);
154da6c28aaSamw 
155da6c28aaSamw 		if (info2->shi2_comment)
156da6c28aaSamw 			smb_tracef("srvsvc shi2_comment=%s",
157da6c28aaSamw 			    info2->shi2_comment);
158da6c28aaSamw 
159da6c28aaSamw 		smb_tracef("srvsvc shi2_perms=%d", info2->shi2_permissions);
160da6c28aaSamw 		smb_tracef("srvsvc shi2_max_use=%d", info2->shi2_max_uses);
161da6c28aaSamw 		smb_tracef("srvsvc shi2_cur_use=%d", info2->shi2_current_uses);
162da6c28aaSamw 
163da6c28aaSamw 		if (info2->shi2_path)
164da6c28aaSamw 			smb_tracef("srvsvc shi2_path=%s", info2->shi2_path);
165da6c28aaSamw 
166da6c28aaSamw 		if (info2->shi2_passwd)
167da6c28aaSamw 			smb_tracef("srvsvc shi2_passwd=%s", info2->shi2_passwd);
168da6c28aaSamw 		break;
169da6c28aaSamw 
170da6c28aaSamw 	default:
171da6c28aaSamw 		smb_tracef("srvsvc: unknown level");
172da6c28aaSamw 		break;
173da6c28aaSamw 	}
174da6c28aaSamw 
1758d7e4166Sjose borrego 	srvsvc_close(&handle);
176da6c28aaSamw 	return (0);
177da6c28aaSamw }
178da6c28aaSamw 
179da6c28aaSamw /*
180da6c28aaSamw  * This is a client side routine for NetSessionEnum.
181da6c28aaSamw  * NetSessionEnum requires administrator rights.
182da6c28aaSamw  */
183da6c28aaSamw int
184da6c28aaSamw srvsvc_net_session_enum(char *server, char *domain, char *netname)
185da6c28aaSamw {
186da6c28aaSamw 	struct mslm_NetSessionEnum arg;
187da6c28aaSamw 	mlsvc_handle_t handle;
188da6c28aaSamw 	int rc;
189da6c28aaSamw 	int opnum;
190da6c28aaSamw 	struct mslm_infonres infonres;
191da6c28aaSamw 	struct mslm_SESSION_INFO_1 *nsi1;
192da6c28aaSamw 	int len;
193a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
194da6c28aaSamw 
195da6c28aaSamw 	if (netname == NULL)
196da6c28aaSamw 		return (-1);
197da6c28aaSamw 
198a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
199a0aa776eSAlan Wright 
2008d7e4166Sjose borrego 	rc = srvsvc_open(server, domain, user, &handle);
201da6c28aaSamw 	if (rc != 0)
202da6c28aaSamw 		return (-1);
203da6c28aaSamw 
204da6c28aaSamw 	opnum = SRVSVC_OPNUM_NetSessionEnum;
205da6c28aaSamw 	bzero(&arg, sizeof (struct mslm_NetSessionEnum));
206da6c28aaSamw 
207da6c28aaSamw 	len = strlen(server) + 4;
2088d7e4166Sjose borrego 	arg.servername = ndr_rpc_malloc(&handle, len);
209da6c28aaSamw 	if (arg.servername == NULL) {
2108d7e4166Sjose borrego 		srvsvc_close(&handle);
211da6c28aaSamw 		return (-1);
212da6c28aaSamw 	}
213da6c28aaSamw 
214da6c28aaSamw 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
215da6c28aaSamw 	infonres.entriesread = 0;
216da6c28aaSamw 	infonres.entries = 0;
217da6c28aaSamw 	arg.level = 1;
218da6c28aaSamw 	arg.result.level = 1;
219da6c28aaSamw 	arg.result.bufptr.p = &infonres;
220da6c28aaSamw 	arg.resume_handle = 0;
221da6c28aaSamw 	arg.pref_max_len = 0xFFFFFFFF;
222da6c28aaSamw 
2238d7e4166Sjose borrego 	rc = ndr_rpc_call(&handle, opnum, &arg);
224da6c28aaSamw 	if ((rc != 0) || (arg.status != 0)) {
2258d7e4166Sjose borrego 		srvsvc_close(&handle);
226da6c28aaSamw 		return (-1);
227da6c28aaSamw 	}
228da6c28aaSamw 
229da6c28aaSamw 	/* Only the first session info is dereferenced. */
230da6c28aaSamw 	nsi1 = ((struct mslm_infonres *)arg.result.bufptr.p)->entries;
231da6c28aaSamw 
232da6c28aaSamw 	smb_tracef("srvsvc switch_value=%d", arg.level);
233da6c28aaSamw 	smb_tracef("srvsvc sesi1_cname=%s", nsi1->sesi1_cname);
234da6c28aaSamw 	smb_tracef("srvsvc sesi1_uname=%s", nsi1->sesi1_uname);
235da6c28aaSamw 	smb_tracef("srvsvc sesi1_nopens=%u", nsi1->sesi1_nopens);
236da6c28aaSamw 	smb_tracef("srvsvc sesi1_time=%u", nsi1->sesi1_time);
237da6c28aaSamw 	smb_tracef("srvsvc sesi1_itime=%u", nsi1->sesi1_itime);
238da6c28aaSamw 	smb_tracef("srvsvc sesi1_uflags=%u", nsi1->sesi1_uflags);
239da6c28aaSamw 
2408d7e4166Sjose borrego 	srvsvc_close(&handle);
241da6c28aaSamw 	return (0);
242da6c28aaSamw }
243da6c28aaSamw 
244da6c28aaSamw /*
245da6c28aaSamw  * This is a client side routine for NetConnectEnum.
246da6c28aaSamw  * NetConnectEnum requires administrator rights.
247da6c28aaSamw  * Level 0 and level 1 requests are supported.
248da6c28aaSamw  */
249da6c28aaSamw int
250da6c28aaSamw srvsvc_net_connect_enum(char *server, char *domain, char *netname, int level)
251da6c28aaSamw {
252da6c28aaSamw 	struct mslm_NetConnectEnum arg;
253da6c28aaSamw 	mlsvc_handle_t handle;
254da6c28aaSamw 	int rc;
255da6c28aaSamw 	int opnum;
256da6c28aaSamw 	struct mslm_NetConnectInfo1 info1;
257da6c28aaSamw 	struct mslm_NetConnectInfo0 info0;
258da6c28aaSamw 	struct mslm_NetConnectInfoBuf1 *cib1;
259da6c28aaSamw 	int len;
260a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
261da6c28aaSamw 
262da6c28aaSamw 	if (netname == NULL)
263da6c28aaSamw 		return (-1);
264da6c28aaSamw 
265a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
266a0aa776eSAlan Wright 
2678d7e4166Sjose borrego 	rc = srvsvc_open(server, domain, user, &handle);
268da6c28aaSamw 	if (rc != 0)
269da6c28aaSamw 		return (-1);
270da6c28aaSamw 
271da6c28aaSamw 	opnum = SRVSVC_OPNUM_NetConnectEnum;
272da6c28aaSamw 	bzero(&arg, sizeof (struct mslm_NetConnectEnum));
273da6c28aaSamw 
274da6c28aaSamw 	len = strlen(server) + 4;
2758d7e4166Sjose borrego 	arg.servername = ndr_rpc_malloc(&handle, len);
276da6c28aaSamw 	if (arg.servername == NULL) {
2778d7e4166Sjose borrego 		srvsvc_close(&handle);
278da6c28aaSamw 		return (-1);
279da6c28aaSamw 	}
280da6c28aaSamw 
281da6c28aaSamw 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
282da6c28aaSamw 	arg.qualifier = (LPTSTR)netname;
283da6c28aaSamw 
284da6c28aaSamw 	switch (level) {
285da6c28aaSamw 	case 0:
286da6c28aaSamw 		arg.info.level = 0;
287da6c28aaSamw 		arg.info.switch_value = 0;
288da6c28aaSamw 		arg.info.ru.info0 = &info0;
289da6c28aaSamw 		info0.entries_read = 0;
290da6c28aaSamw 		info0.ci0 = 0;
291da6c28aaSamw 		break;
292da6c28aaSamw 	case 1:
293da6c28aaSamw 		arg.info.level = 1;
294da6c28aaSamw 		arg.info.switch_value = 1;
295da6c28aaSamw 		arg.info.ru.info1 = &info1;
296da6c28aaSamw 		info1.entries_read = 0;
297da6c28aaSamw 		info1.ci1 = 0;
298da6c28aaSamw 		break;
299da6c28aaSamw 	default:
3008d7e4166Sjose borrego 		srvsvc_close(&handle);
301da6c28aaSamw 		return (-1);
302da6c28aaSamw 	}
303da6c28aaSamw 
304da6c28aaSamw 	arg.resume_handle = 0;
305da6c28aaSamw 	arg.pref_max_len = 0xFFFFFFFF;
306da6c28aaSamw 
3078d7e4166Sjose borrego 	rc = ndr_rpc_call(&handle, opnum, &arg);
308da6c28aaSamw 	if ((rc != 0) || (arg.status != 0)) {
3098d7e4166Sjose borrego 		srvsvc_close(&handle);
310da6c28aaSamw 		return (-1);
311da6c28aaSamw 	}
312da6c28aaSamw 
313da6c28aaSamw 	smb_tracef("srvsvc switch_value=%d", arg.info.switch_value);
314da6c28aaSamw 
315da6c28aaSamw 	switch (level) {
316da6c28aaSamw 	case 0:
317da6c28aaSamw 		if (arg.info.ru.info0 && arg.info.ru.info0->ci0) {
318da6c28aaSamw 			smb_tracef("srvsvc coni0_id=%x",
319da6c28aaSamw 			    arg.info.ru.info0->ci0->coni0_id);
320da6c28aaSamw 		}
321da6c28aaSamw 		break;
322da6c28aaSamw 	case 1:
323da6c28aaSamw 		if (arg.info.ru.info1 && arg.info.ru.info1->ci1) {
324da6c28aaSamw 			cib1 = arg.info.ru.info1->ci1;
325da6c28aaSamw 
326da6c28aaSamw 			smb_tracef("srvsvc coni_uname=%s",
327da6c28aaSamw 			    cib1->coni1_username ?
328da6c28aaSamw 			    (char *)cib1->coni1_username : "(null)");
329da6c28aaSamw 			smb_tracef("srvsvc coni1_netname=%s",
330da6c28aaSamw 			    cib1->coni1_netname ?
331da6c28aaSamw 			    (char *)cib1->coni1_netname : "(null)");
332da6c28aaSamw 			smb_tracef("srvsvc coni1_nopens=%u",
333da6c28aaSamw 			    cib1->coni1_num_opens);
334da6c28aaSamw 			smb_tracef("srvsvc coni1_time=%u", cib1->coni1_time);
335da6c28aaSamw 			smb_tracef("srvsvc coni1_num_users=%u",
336da6c28aaSamw 			    cib1->coni1_num_users);
337da6c28aaSamw 		}
338da6c28aaSamw 		break;
339da6c28aaSamw 
340da6c28aaSamw 	default:
341da6c28aaSamw 		smb_tracef("srvsvc: unknown level");
342da6c28aaSamw 		break;
343da6c28aaSamw 	}
344da6c28aaSamw 
3458d7e4166Sjose borrego 	srvsvc_close(&handle);
346da6c28aaSamw 	return (0);
347da6c28aaSamw }
348da6c28aaSamw 
349a0aa776eSAlan Wright /*
350a0aa776eSAlan Wright  * Windows 95+ and Windows NT4.0 both report the version as 4.0.
351a0aa776eSAlan Wright  * Windows 2000+ reports the version as 5.x.
352a0aa776eSAlan Wright  */
3531fcced4cSJordan Brown int
3541fcced4cSJordan Brown srvsvc_net_server_getinfo(char *server, char *domain,
3551fcced4cSJordan Brown     srvsvc_server_info_t *svinfo)
3561fcced4cSJordan Brown {
3571fcced4cSJordan Brown 	mlsvc_handle_t handle;
3581fcced4cSJordan Brown 	struct mslm_NetServerGetInfo arg;
3591fcced4cSJordan Brown 	struct mslm_SERVER_INFO_101 *sv101;
3601fcced4cSJordan Brown 	int len, opnum, rc;
361a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
362a0aa776eSAlan Wright 
363a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
3641fcced4cSJordan Brown 
3651fcced4cSJordan Brown 	if (srvsvc_open(server, domain, user, &handle) != 0)
3661fcced4cSJordan Brown 		return (-1);
3671fcced4cSJordan Brown 
3681fcced4cSJordan Brown 	opnum = SRVSVC_OPNUM_NetServerGetInfo;
3691fcced4cSJordan Brown 	bzero(&arg, sizeof (arg));
3701fcced4cSJordan Brown 
3711fcced4cSJordan Brown 	len = strlen(server) + 4;
3721fcced4cSJordan Brown 	arg.servername = ndr_rpc_malloc(&handle, len);
3731fcced4cSJordan Brown 	if (arg.servername == NULL)
3741fcced4cSJordan Brown 		return (-1);
3751fcced4cSJordan Brown 
3761fcced4cSJordan Brown 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
3771fcced4cSJordan Brown 	arg.level = 101;
3781fcced4cSJordan Brown 
3791fcced4cSJordan Brown 	rc = ndr_rpc_call(&handle, opnum, &arg);
3801fcced4cSJordan Brown 	if ((rc != 0) || (arg.status != 0)) {
3811fcced4cSJordan Brown 		srvsvc_close(&handle);
3821fcced4cSJordan Brown 		return (-1);
3831fcced4cSJordan Brown 	}
3841fcced4cSJordan Brown 
3851fcced4cSJordan Brown 	sv101 = arg.result.bufptr.bufptr101;
3861fcced4cSJordan Brown 
3871fcced4cSJordan Brown 	bzero(svinfo, sizeof (srvsvc_server_info_t));
3881fcced4cSJordan Brown 	svinfo->sv_platform_id = sv101->sv101_platform_id;
3891fcced4cSJordan Brown 	svinfo->sv_version_major = sv101->sv101_version_major;
3901fcced4cSJordan Brown 	svinfo->sv_version_minor = sv101->sv101_version_minor;
3911fcced4cSJordan Brown 	svinfo->sv_type = sv101->sv101_type;
3921fcced4cSJordan Brown 	if (sv101->sv101_name)
3931fcced4cSJordan Brown 		svinfo->sv_name = strdup((char *)sv101->sv101_name);
3941fcced4cSJordan Brown 	if (sv101->sv101_comment)
3951fcced4cSJordan Brown 		svinfo->sv_comment = strdup((char *)sv101->sv101_comment);
3961fcced4cSJordan Brown 
397a0aa776eSAlan Wright 	if (svinfo->sv_type & SV_TYPE_WFW)
398a0aa776eSAlan Wright 		svinfo->sv_os = NATIVE_OS_WIN95;
399a0aa776eSAlan Wright 	if (svinfo->sv_type & SV_TYPE_WINDOWS)
400a0aa776eSAlan Wright 		svinfo->sv_os = NATIVE_OS_WIN95;
401a0aa776eSAlan Wright 	if ((svinfo->sv_type & SV_TYPE_NT) ||
402a0aa776eSAlan Wright 	    (svinfo->sv_type & SV_TYPE_SERVER_NT))
403a0aa776eSAlan Wright 		svinfo->sv_os = NATIVE_OS_WINNT;
404a0aa776eSAlan Wright 	if (svinfo->sv_version_major > 4)
405a0aa776eSAlan Wright 		svinfo->sv_os = NATIVE_OS_WIN2000;
406a0aa776eSAlan Wright 
4071fcced4cSJordan Brown 	srvsvc_close(&handle);
4081fcced4cSJordan Brown 	return (0);
4091fcced4cSJordan Brown }
4101fcced4cSJordan Brown 
411da6c28aaSamw /*
412da6c28aaSamw  * Synchronize the local system clock with the domain controller.
413da6c28aaSamw  */
414da6c28aaSamw void
415da6c28aaSamw srvsvc_timesync(void)
416da6c28aaSamw {
417a0aa776eSAlan Wright 	smb_domainex_t di;
418da6c28aaSamw 	struct timeval tv;
419da6c28aaSamw 	struct tm tm;
420da6c28aaSamw 	time_t tsecs;
421da6c28aaSamw 
4228d7e4166Sjose borrego 	if (!smb_domain_getinfo(&di))
423da6c28aaSamw 		return;
424da6c28aaSamw 
425a0aa776eSAlan Wright 	if (srvsvc_net_remote_tod(di.d_dc, di.d_primary.di_nbname, &tv, &tm)
426a0aa776eSAlan Wright 	    != 0)
427da6c28aaSamw 		return;
428da6c28aaSamw 
429da6c28aaSamw 	if (settimeofday(&tv, 0))
430da6c28aaSamw 		smb_tracef("unable to set system time");
431da6c28aaSamw 
432da6c28aaSamw 	tsecs = time(0);
433da6c28aaSamw 	(void) localtime_r(&tsecs, &tm);
434da6c28aaSamw 	smb_tracef("SrvsvcTimeSync %s", ctime((time_t *)&tv.tv_sec));
435da6c28aaSamw }
436da6c28aaSamw 
437da6c28aaSamw /*
438da6c28aaSamw  * NetRemoteTOD to get the current GMT time from a Windows NT server.
439da6c28aaSamw  */
440da6c28aaSamw int
441da6c28aaSamw srvsvc_gettime(unsigned long *t)
442da6c28aaSamw {
443a0aa776eSAlan Wright 	smb_domainex_t di;
444da6c28aaSamw 	struct timeval tv;
445da6c28aaSamw 	struct tm tm;
446da6c28aaSamw 
4478d7e4166Sjose borrego 	if (!smb_domain_getinfo(&di))
448da6c28aaSamw 		return (-1);
449da6c28aaSamw 
450a0aa776eSAlan Wright 	if (srvsvc_net_remote_tod(di.d_dc, di.d_primary.di_nbname, &tv, &tm)
451a0aa776eSAlan Wright 	    != 0)
452da6c28aaSamw 		return (-1);
453da6c28aaSamw 
454da6c28aaSamw 	*t = tv.tv_sec;
455da6c28aaSamw 	return (0);
456da6c28aaSamw }
457da6c28aaSamw 
458da6c28aaSamw /*
459da6c28aaSamw  * This is a client side routine for NetRemoteTOD, which gets the time
460da6c28aaSamw  * and date from a remote system. The time information is returned in
461da6c28aaSamw  * the timeval and tm.
462da6c28aaSamw  *
463da6c28aaSamw  * typedef struct _TIME_OF_DAY_INFO {
464da6c28aaSamw  *	DWORD tod_elapsedt;  // seconds since 00:00:00 January 1 1970 GMT
465da6c28aaSamw  *	DWORD tod_msecs;     // arbitrary milliseconds (since reset)
466da6c28aaSamw  *	DWORD tod_hours;     // current hour [0-23]
467da6c28aaSamw  *	DWORD tod_mins;      // current minute [0-59]
468da6c28aaSamw  *	DWORD tod_secs;      // current second [0-59]
469da6c28aaSamw  *	DWORD tod_hunds;     // current hundredth (0.01) second [0-99]
470da6c28aaSamw  *	LONG tod_timezone;   // time zone of the server
471da6c28aaSamw  *	DWORD tod_tinterval; // clock tick time interval
472da6c28aaSamw  *	DWORD tod_day;       // day of the month [1-31]
473da6c28aaSamw  *	DWORD tod_month;     // month of the year [1-12]
474da6c28aaSamw  *	DWORD tod_year;      // current year
475da6c28aaSamw  *	DWORD tod_weekday;   // day of the week since sunday [0-6]
476da6c28aaSamw  * } TIME_OF_DAY_INFO;
477da6c28aaSamw  *
478da6c28aaSamw  * The time zone of the server is calculated in minutes from Greenwich
479da6c28aaSamw  * Mean Time (GMT). For time zones west of Greenwich, the value is
480da6c28aaSamw  * positive; for time zones east of Greenwich, the value is negative.
481da6c28aaSamw  * A value of -1 indicates that the time zone is undefined.
482da6c28aaSamw  *
483da6c28aaSamw  * The clock tick value represents a resolution of one ten-thousandth
484da6c28aaSamw  * (0.0001) second.
485da6c28aaSamw  */
486da6c28aaSamw int
487da6c28aaSamw srvsvc_net_remote_tod(char *server, char *domain, struct timeval *tv,
488da6c28aaSamw     struct tm *tm)
489da6c28aaSamw {
4909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	struct mslm_NetRemoteTOD	arg;
4919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	struct mslm_TIME_OF_DAY_INFO	*tod;
4929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mlsvc_handle_t			handle;
4939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int				rc;
4949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int				opnum;
4959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int				len;
4969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	char				user[SMB_USERNAME_MAXLEN];
497a0aa776eSAlan Wright 
498a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
499da6c28aaSamw 
5008d7e4166Sjose borrego 	rc = srvsvc_open(server, domain, user, &handle);
501da6c28aaSamw 	if (rc != 0)
502da6c28aaSamw 		return (-1);
503da6c28aaSamw 
504da6c28aaSamw 	opnum = SRVSVC_OPNUM_NetRemoteTOD;
505da6c28aaSamw 	bzero(&arg, sizeof (struct mslm_NetRemoteTOD));
506da6c28aaSamw 
507da6c28aaSamw 	len = strlen(server) + 4;
5088d7e4166Sjose borrego 	arg.servername = ndr_rpc_malloc(&handle, len);
509da6c28aaSamw 	if (arg.servername == NULL) {
5108d7e4166Sjose borrego 		srvsvc_close(&handle);
511da6c28aaSamw 		return (-1);
512da6c28aaSamw 	}
513da6c28aaSamw 
514da6c28aaSamw 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
515da6c28aaSamw 
5168d7e4166Sjose borrego 	rc = ndr_rpc_call(&handle, opnum, &arg);
517da6c28aaSamw 	if ((rc != 0) || (arg.status != 0)) {
5188d7e4166Sjose borrego 		srvsvc_close(&handle);
519da6c28aaSamw 		return (-1);
520da6c28aaSamw 	}
521da6c28aaSamw 
522da6c28aaSamw 	/*
523da6c28aaSamw 	 * We're assigning milliseconds to microseconds
524da6c28aaSamw 	 * here but the value's not really relevant.
525da6c28aaSamw 	 */
526da6c28aaSamw 	tod = arg.bufptr;
527da6c28aaSamw 
528da6c28aaSamw 	if (tv) {
529da6c28aaSamw 		tv->tv_sec = tod->tod_elapsedt;
530da6c28aaSamw 		tv->tv_usec = tod->tod_msecs;
531da6c28aaSamw 	}
532da6c28aaSamw 
533da6c28aaSamw 	if (tm) {
534da6c28aaSamw 		tm->tm_sec = tod->tod_secs;
535da6c28aaSamw 		tm->tm_min = tod->tod_mins;
536da6c28aaSamw 		tm->tm_hour = tod->tod_hours;
537da6c28aaSamw 		tm->tm_mday = tod->tod_day;
538da6c28aaSamw 		tm->tm_mon = tod->tod_month - 1;
539da6c28aaSamw 		tm->tm_year = tod->tod_year - 1900;
540da6c28aaSamw 		tm->tm_wday = tod->tod_weekday;
541da6c28aaSamw 	}
542da6c28aaSamw 
5438d7e4166Sjose borrego 	srvsvc_close(&handle);
544da6c28aaSamw 	return (0);
545da6c28aaSamw }
546da6c28aaSamw 
547da6c28aaSamw void
548da6c28aaSamw srvsvc_net_test(char *server, char *domain, char *netname)
549da6c28aaSamw {
550a0aa776eSAlan Wright 	smb_domainex_t di;
5511fcced4cSJordan Brown 	srvsvc_server_info_t svinfo;
552da6c28aaSamw 
553da6c28aaSamw 	(void) smb_tracef("%s %s %s", server, domain, netname);
554da6c28aaSamw 
5558d7e4166Sjose borrego 	if (smb_domain_getinfo(&di)) {
5568d7e4166Sjose borrego 		server = di.d_dc;
557a0aa776eSAlan Wright 		domain = di.d_primary.di_nbname;
558da6c28aaSamw 	}
559da6c28aaSamw 
5601fcced4cSJordan Brown 	if (srvsvc_net_server_getinfo(server, domain, &svinfo) == 0) {
5611fcced4cSJordan Brown 		smb_tracef("NetServerGetInfo: %s %s (%d.%d) id=%d type=0x%08x",
5621fcced4cSJordan Brown 		    svinfo.sv_name ? svinfo.sv_name : "NULL",
5631fcced4cSJordan Brown 		    svinfo.sv_comment ? svinfo.sv_comment : "NULL",
5641fcced4cSJordan Brown 		    svinfo.sv_version_major, svinfo.sv_version_minor,
5651fcced4cSJordan Brown 		    svinfo.sv_platform_id, svinfo.sv_type);
5661fcced4cSJordan Brown 
5671fcced4cSJordan Brown 		free(svinfo.sv_name);
5681fcced4cSJordan Brown 		free(svinfo.sv_comment);
5691fcced4cSJordan Brown 	}
5701fcced4cSJordan Brown 
571da6c28aaSamw 	(void) srvsvc_net_share_get_info(server, domain, netname);
572da6c28aaSamw #if 0
573da6c28aaSamw 	/*
574da6c28aaSamw 	 * The NetSessionEnum server-side definition was updated.
575da6c28aaSamw 	 * Disabled until the client-side has been updated.
576da6c28aaSamw 	 */
577da6c28aaSamw 	(void) srvsvc_net_session_enum(server, domain, netname);
578da6c28aaSamw #endif
579da6c28aaSamw 	(void) srvsvc_net_connect_enum(server, domain, netname, 0);
580da6c28aaSamw 	(void) srvsvc_net_connect_enum(server, domain, netname, 1);
581da6c28aaSamw }
582