1430b4c46SGordon Ross /*
2430b4c46SGordon Ross  * CDDL HEADER START
3430b4c46SGordon Ross  *
4430b4c46SGordon Ross  * The contents of this file are subject to the terms of the
5430b4c46SGordon Ross  * Common Development and Distribution License (the "License").
6430b4c46SGordon Ross  * You may not use this file except in compliance with the License.
7430b4c46SGordon Ross  *
8430b4c46SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9430b4c46SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10430b4c46SGordon Ross  * See the License for the specific language governing permissions
11430b4c46SGordon Ross  * and limitations under the License.
12430b4c46SGordon Ross  *
13430b4c46SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14430b4c46SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15430b4c46SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16430b4c46SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17430b4c46SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18430b4c46SGordon Ross  *
19430b4c46SGordon Ross  * CDDL HEADER END
20430b4c46SGordon Ross  */
21430b4c46SGordon Ross 
22430b4c46SGordon Ross /*
23430b4c46SGordon Ross  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*8329232eSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
25430b4c46SGordon Ross  */
26430b4c46SGordon Ross 
27430b4c46SGordon Ross /*
28430b4c46SGordon Ross  * Test program for the smbfs named pipe API.
29430b4c46SGordon Ross  */
30430b4c46SGordon Ross 
31430b4c46SGordon Ross #include <sys/types.h>
32430b4c46SGordon Ross #include <errno.h>
33430b4c46SGordon Ross #include <fcntl.h>
34430b4c46SGordon Ross #include <stdio.h>
35430b4c46SGordon Ross #include <stdlib.h>
36430b4c46SGordon Ross #include <string.h>
37430b4c46SGordon Ross #include <unistd.h>
38430b4c46SGordon Ross #include <libintl.h>
39*8329232eSGordon Ross #include <ctype.h>
40430b4c46SGordon Ross 
41*8329232eSGordon Ross #include <netsmb/smb_lib.h>
42430b4c46SGordon Ross 
43430b4c46SGordon Ross /*
44430b4c46SGordon Ross  * This is a quick hack for testing client-side named pipes.
45*8329232eSGordon Ross  * Its purpose is to test SMB named-pipe interface separately
46*8329232eSGordon Ross  * from the RPC implementation.  It's a "hack" because it uses
47*8329232eSGordon Ross  * hand-crafted RPC messages (extracted from network traffic).
48430b4c46SGordon Ross  */
49430b4c46SGordon Ross 
50430b4c46SGordon Ross /* This is a DCE/RPC bind call for "srvsvc". */
51430b4c46SGordon Ross static const uchar_t
52430b4c46SGordon Ross srvsvc_bind[] = {
53430b4c46SGordon Ross 	0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
54430b4c46SGordon Ross 	0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
55430b4c46SGordon Ross 	0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
56430b4c46SGordon Ross 	0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
57430b4c46SGordon Ross 	0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01,
58430b4c46SGordon Ross 	0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88,
59430b4c46SGordon Ross 	0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
60430b4c46SGordon Ross 	0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
61430b4c46SGordon Ross 	0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 };
62430b4c46SGordon Ross 
6385e6b674SGordon Ross /* This is a srvsvc "enum servers" call, in two parts */
64430b4c46SGordon Ross static const uchar_t
6585e6b674SGordon Ross srvsvc_enum1[] = {
66430b4c46SGordon Ross 	0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00,
6785e6b674SGordon Ross #define	ENUM_RPCLEN_OFF	8
68430b4c46SGordon Ross 	/* V - RPC frag length */
69430b4c46SGordon Ross 	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70430b4c46SGordon Ross 	/* ... and the operation number is: VVVV */
7185e6b674SGordon Ross 	0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00,
7285e6b674SGordon Ross #define	ENUM_SLEN1_OFF	28
7385e6b674SGordon Ross #define	ENUM_SLEN2_OFF	36
74430b4c46SGordon Ross 	/* server name, length 14 vv ... */
75430b4c46SGordon Ross 	0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
76430b4c46SGordon Ross 	0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00 };
77430b4c46SGordon Ross 	/* UNC server here, i.e.: "\\192.168.1.6" */
78430b4c46SGordon Ross 
7985e6b674SGordon Ross static const uchar_t
8085e6b674SGordon Ross srvsvc_enum2[] = {
8185e6b674SGordon Ross 	0x01, 0x00, 0x00, 0x00,
8285e6b674SGordon Ross 	0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
8385e6b674SGordon Ross 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8485e6b674SGordon Ross 	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
8585e6b674SGordon Ross 
86430b4c46SGordon Ross static uchar_t sendbuf[1024];
8785e6b674SGordon Ross static uchar_t recvbuf[4096];
88430b4c46SGordon Ross 
89*8329232eSGordon Ross /*
90*8329232eSGordon Ross  * Print strings found in the buffer.
91*8329232eSGordon Ross  */
92430b4c46SGordon Ross static void
pstrings(const uchar_t * buf,int len)93*8329232eSGordon Ross pstrings(const uchar_t *buf, int len)
94430b4c46SGordon Ross {
95*8329232eSGordon Ross 	const uchar_t *p = buf;
96*8329232eSGordon Ross 	uint16_t u2;
97*8329232eSGordon Ross 	boolean_t instr = B_FALSE;
98*8329232eSGordon Ross 
99*8329232eSGordon Ross 	while (len > 2) {
100*8329232eSGordon Ross 		u2 = *p++;
101*8329232eSGordon Ross 		u2 |= (*p++) << 8;
102*8329232eSGordon Ross 		len -= 2;
103*8329232eSGordon Ross 
104*8329232eSGordon Ross 		if ((u2 & 0xFF80) == 0 && isprint(u2)) {
105*8329232eSGordon Ross 			/* printable */
106*8329232eSGordon Ross 			instr = B_TRUE;
107*8329232eSGordon Ross 			putchar(u2);
108*8329232eSGordon Ross 		} else {
109*8329232eSGordon Ross 			/* not printalbe */
110*8329232eSGordon Ross 			if (instr)
111*8329232eSGordon Ross 				putchar('\n');
112*8329232eSGordon Ross 			instr = B_FALSE;
113430b4c46SGordon Ross 		}
114430b4c46SGordon Ross 	}
115*8329232eSGordon Ross 	if (instr)
116*8329232eSGordon Ross 		putchar('\n');
117430b4c46SGordon Ross }
118430b4c46SGordon Ross 
119430b4c46SGordon Ross /*
120430b4c46SGordon Ross  * Put a unicode UNC server name, including the null.
121430b4c46SGordon Ross  * Quick-n-dirty, just for this test...
122430b4c46SGordon Ross  */
123430b4c46SGordon Ross static int
put_uncserver(const char * s,uchar_t * buf)124430b4c46SGordon Ross put_uncserver(const char *s, uchar_t *buf)
125430b4c46SGordon Ross {
126430b4c46SGordon Ross 	uchar_t *p = buf;
127430b4c46SGordon Ross 	char c;
128430b4c46SGordon Ross 
129430b4c46SGordon Ross 	*p++ = '\\'; *p++ = '\0';
130430b4c46SGordon Ross 	*p++ = '\\'; *p++ = '\0';
131430b4c46SGordon Ross 
132430b4c46SGordon Ross 	do {
133430b4c46SGordon Ross 		c = *s++;
134430b4c46SGordon Ross 		if (c == '/')
135430b4c46SGordon Ross 			c = '\\';
136430b4c46SGordon Ross 		*p++ = c;
137430b4c46SGordon Ross 		*p++ = '\0';
138430b4c46SGordon Ross 
139430b4c46SGordon Ross 	} while (c != 0);
140430b4c46SGordon Ross 
141430b4c46SGordon Ross 	return (p - buf);
142430b4c46SGordon Ross }
143430b4c46SGordon Ross 
144430b4c46SGordon Ross /*
145430b4c46SGordon Ross  * Send the bind and read the ack.
146430b4c46SGordon Ross  * This tests smb_fh_xactnp.
147430b4c46SGordon Ross  */
148430b4c46SGordon Ross static int
do_bind(int fid)149430b4c46SGordon Ross do_bind(int fid)
150430b4c46SGordon Ross {
151430b4c46SGordon Ross 	int err, len, more;
152430b4c46SGordon Ross 
153430b4c46SGordon Ross 	more = 0;
154430b4c46SGordon Ross 	len = sizeof (recvbuf);
155430b4c46SGordon Ross 	err = smb_fh_xactnp(fid,
156430b4c46SGordon Ross 	    sizeof (srvsvc_bind), (char *)srvsvc_bind,
157430b4c46SGordon Ross 	    &len, (char *)recvbuf, &more);
158430b4c46SGordon Ross 	if (err) {
159430b4c46SGordon Ross 		printf("xact bind, err=%d\n", err);
160430b4c46SGordon Ross 		return (err);
161430b4c46SGordon Ross 	}
162430b4c46SGordon Ross 	if (more > 0) {
163430b4c46SGordon Ross 		if (more > sizeof (recvbuf)) {
164430b4c46SGordon Ross 			printf("bogus more=%d\n", more);
165430b4c46SGordon Ross 			more = sizeof (recvbuf);
166430b4c46SGordon Ross 		}
167430b4c46SGordon Ross 		len = smb_fh_read(fid, 0,
168430b4c46SGordon Ross 		    more, (char *)recvbuf);
169430b4c46SGordon Ross 		if (len == -1) {
170430b4c46SGordon Ross 			err = EIO;
17185e6b674SGordon Ross 			printf("read enum resp, err=%d\n", err);
172430b4c46SGordon Ross 			return (err);
173430b4c46SGordon Ross 		}
174430b4c46SGordon Ross 	}
175430b4c46SGordon Ross 
176430b4c46SGordon Ross 	return (0);
177430b4c46SGordon Ross }
178430b4c46SGordon Ross 
179430b4c46SGordon Ross static int
do_enum(char * server,int fid)180*8329232eSGordon Ross do_enum(char *server, int fid)
181430b4c46SGordon Ross {
18285e6b674SGordon Ross 	int err, len, rlen, wlen;
183430b4c46SGordon Ross 	uchar_t *p;
184430b4c46SGordon Ross 
185430b4c46SGordon Ross 	/*
18685e6b674SGordon Ross 	 * Build the enum request - three parts.
18785e6b674SGordon Ross 	 * See above: srvsvc_enum1, srvsvc_enum2
188430b4c46SGordon Ross 	 *
189430b4c46SGordon Ross 	 * First part: RPC header, etc.
190430b4c46SGordon Ross 	 */
191430b4c46SGordon Ross 	p = sendbuf;
19285e6b674SGordon Ross 	len = sizeof (srvsvc_enum1); /* 40 */
19385e6b674SGordon Ross 	memcpy(p, srvsvc_enum1, len);
194430b4c46SGordon Ross 	p += len;
195430b4c46SGordon Ross 
196430b4c46SGordon Ross 	/* Second part: UNC server name */
197430b4c46SGordon Ross 	len = put_uncserver(server, p);
198430b4c46SGordon Ross 	p += len;
19985e6b674SGordon Ross 	sendbuf[ENUM_SLEN1_OFF] = len / 2;
20085e6b674SGordon Ross 	sendbuf[ENUM_SLEN2_OFF] = len / 2;
201430b4c46SGordon Ross 
202430b4c46SGordon Ross 	/* Third part: level, etc. (align4) */
203430b4c46SGordon Ross 	for (len = (p - sendbuf) & 3; len; len--)
204430b4c46SGordon Ross 		*p++ = '\0';
20585e6b674SGordon Ross 	len = sizeof (srvsvc_enum2); /* 28 */
20685e6b674SGordon Ross 	memcpy(p, srvsvc_enum2, len);
20785e6b674SGordon Ross 	p += len;
208430b4c46SGordon Ross 
209430b4c46SGordon Ross 	/*
210430b4c46SGordon Ross 	 * Compute total length, and fixup RPC header.
211430b4c46SGordon Ross 	 */
212430b4c46SGordon Ross 	len = p - sendbuf;
21385e6b674SGordon Ross 	sendbuf[ENUM_RPCLEN_OFF] = len;
214430b4c46SGordon Ross 
215430b4c46SGordon Ross 	/*
21685e6b674SGordon Ross 	 * Send the enum request, read the response.
217430b4c46SGordon Ross 	 * This tests smb_fh_write, smb_fh_read.
218430b4c46SGordon Ross 	 */
219430b4c46SGordon Ross 	wlen = smb_fh_write(fid, 0, len, (char *)sendbuf);
220430b4c46SGordon Ross 	if (wlen == -1) {
221430b4c46SGordon Ross 		err = errno;
22285e6b674SGordon Ross 		printf("write enum req, err=%d\n", err);
223430b4c46SGordon Ross 		return (err);
224430b4c46SGordon Ross 	}
225430b4c46SGordon Ross 	if (wlen != len) {
22685e6b674SGordon Ross 		printf("write enum req, short write %d\n", wlen);
227430b4c46SGordon Ross 		return (EIO);
228430b4c46SGordon Ross 	}
229430b4c46SGordon Ross 
230430b4c46SGordon Ross 	rlen = smb_fh_read(fid, 0,
231430b4c46SGordon Ross 	    sizeof (recvbuf), (char *)recvbuf);
232430b4c46SGordon Ross 	if (rlen == -1) {
233430b4c46SGordon Ross 		err = errno;
23485e6b674SGordon Ross 		printf("read enum resp, err=%d\n", err);
235430b4c46SGordon Ross 		return (err);
236430b4c46SGordon Ross 	}
237430b4c46SGordon Ross 
238*8329232eSGordon Ross 	/*
239*8329232eSGordon Ross 	 * Just dump strings found in the response data.
240*8329232eSGordon Ross 	 * Skip the first 0x90 (RPC wrappers).
241*8329232eSGordon Ross 	 */
242*8329232eSGordon Ross 	printf("enum strings\n");
243*8329232eSGordon Ross 	pstrings(recvbuf + 0x90, rlen - 0x90);
244430b4c46SGordon Ross 
245430b4c46SGordon Ross 	return (0);
246430b4c46SGordon Ross }
247430b4c46SGordon Ross 
248*8329232eSGordon Ross int
list_shares(struct smb_ctx * ctx)249*8329232eSGordon Ross list_shares(struct smb_ctx *ctx)
250430b4c46SGordon Ross {
251430b4c46SGordon Ross 	static char path[] = "/srvsvc";
252430b4c46SGordon Ross 	static uchar_t key[16];
253*8329232eSGordon Ross 	char *server = ctx->ct_srvname;
254430b4c46SGordon Ross 	int err, fd;
255430b4c46SGordon Ross 
256430b4c46SGordon Ross 	printf("open pipe: %s\n", path);
257430b4c46SGordon Ross 	fd = smb_fh_open(ctx, path, O_RDWR);
258430b4c46SGordon Ross 	if (fd < 0) {
259430b4c46SGordon Ross 		perror(path);
260430b4c46SGordon Ross 		return (errno);
261430b4c46SGordon Ross 	}
262430b4c46SGordon Ross 
263430b4c46SGordon Ross 	/* Test this too. */
264430b4c46SGordon Ross 	err = smb_fh_getssnkey(fd, key, sizeof (key));
265430b4c46SGordon Ross 	if (err) {
266430b4c46SGordon Ross 		printf("getssnkey: %d\n", err);
267430b4c46SGordon Ross 		goto out;
268430b4c46SGordon Ross 	}
269430b4c46SGordon Ross 
270430b4c46SGordon Ross 	err = do_bind(fd);
271430b4c46SGordon Ross 	if (err) {
272430b4c46SGordon Ross 		printf("do_bind: %d\n", err);
273430b4c46SGordon Ross 		goto out;
274430b4c46SGordon Ross 	}
275*8329232eSGordon Ross 	err = do_enum(server, fd);
276430b4c46SGordon Ross 	if (err)
27785e6b674SGordon Ross 		printf("do_enum: %d\n", err);
278430b4c46SGordon Ross 
279430b4c46SGordon Ross out:
280430b4c46SGordon Ross 	smb_fh_close(fd);
28185e6b674SGordon Ross 	return (0);
282430b4c46SGordon Ross }
283