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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * Test program for the smbfs named pipe API.
29 */
30
31 #include <sys/types.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <libintl.h>
39 #include <ctype.h>
40
41 #include <netsmb/smb_lib.h>
42
43 /*
44 * This is a quick hack for testing client-side named pipes.
45 * Its purpose is to test SMB named-pipe interface separately
46 * from the RPC implementation. It's a "hack" because it uses
47 * hand-crafted RPC messages (extracted from network traffic).
48 */
49
50 /* This is a DCE/RPC bind call for "srvsvc". */
51 static const uchar_t
52 srvsvc_bind[] = {
53 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
54 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
55 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
56 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
57 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01,
58 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88,
59 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
60 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
61 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 };
62
63 /* This is a srvsvc "enum servers" call, in two parts */
64 static const uchar_t
65 srvsvc_enum1[] = {
66 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00,
67 #define ENUM_RPCLEN_OFF 8
68 /* V - RPC frag length */
69 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 /* ... and the operation number is: VVVV */
71 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00,
72 #define ENUM_SLEN1_OFF 28
73 #define ENUM_SLEN2_OFF 36
74 /* server name, length 14 vv ... */
75 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00 };
77 /* UNC server here, i.e.: "\\192.168.1.6" */
78
79 static const uchar_t
80 srvsvc_enum2[] = {
81 0x01, 0x00, 0x00, 0x00,
82 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
85
86 static uchar_t sendbuf[1024];
87 static uchar_t recvbuf[4096];
88
89 /*
90 * Print strings found in the buffer.
91 */
92 static void
pstrings(const uchar_t * buf,int len)93 pstrings(const uchar_t *buf, int len)
94 {
95 const uchar_t *p = buf;
96 uint16_t u2;
97 boolean_t instr = B_FALSE;
98
99 while (len > 2) {
100 u2 = *p++;
101 u2 |= (*p++) << 8;
102 len -= 2;
103
104 if ((u2 & 0xFF80) == 0 && isprint(u2)) {
105 /* printable */
106 instr = B_TRUE;
107 putchar(u2);
108 } else {
109 /* not printalbe */
110 if (instr)
111 putchar('\n');
112 instr = B_FALSE;
113 }
114 }
115 if (instr)
116 putchar('\n');
117 }
118
119 /*
120 * Put a unicode UNC server name, including the null.
121 * Quick-n-dirty, just for this test...
122 */
123 static int
put_uncserver(const char * s,uchar_t * buf)124 put_uncserver(const char *s, uchar_t *buf)
125 {
126 uchar_t *p = buf;
127 char c;
128
129 *p++ = '\\'; *p++ = '\0';
130 *p++ = '\\'; *p++ = '\0';
131
132 do {
133 c = *s++;
134 if (c == '/')
135 c = '\\';
136 *p++ = c;
137 *p++ = '\0';
138
139 } while (c != 0);
140
141 return (p - buf);
142 }
143
144 /*
145 * Send the bind and read the ack.
146 * This tests smb_fh_xactnp.
147 */
148 static int
do_bind(int fid)149 do_bind(int fid)
150 {
151 int err, len, more;
152
153 more = 0;
154 len = sizeof (recvbuf);
155 err = smb_fh_xactnp(fid,
156 sizeof (srvsvc_bind), (char *)srvsvc_bind,
157 &len, (char *)recvbuf, &more);
158 if (err) {
159 printf("xact bind, err=%d\n", err);
160 return (err);
161 }
162 if (more > 0) {
163 if (more > sizeof (recvbuf)) {
164 printf("bogus more=%d\n", more);
165 more = sizeof (recvbuf);
166 }
167 len = smb_fh_read(fid, 0,
168 more, (char *)recvbuf);
169 if (len == -1) {
170 err = EIO;
171 printf("read enum resp, err=%d\n", err);
172 return (err);
173 }
174 }
175
176 return (0);
177 }
178
179 static int
do_enum(char * server,int fid)180 do_enum(char *server, int fid)
181 {
182 int err, len, rlen, wlen;
183 uchar_t *p;
184
185 /*
186 * Build the enum request - three parts.
187 * See above: srvsvc_enum1, srvsvc_enum2
188 *
189 * First part: RPC header, etc.
190 */
191 p = sendbuf;
192 len = sizeof (srvsvc_enum1); /* 40 */
193 memcpy(p, srvsvc_enum1, len);
194 p += len;
195
196 /* Second part: UNC server name */
197 len = put_uncserver(server, p);
198 p += len;
199 sendbuf[ENUM_SLEN1_OFF] = len / 2;
200 sendbuf[ENUM_SLEN2_OFF] = len / 2;
201
202 /* Third part: level, etc. (align4) */
203 for (len = (p - sendbuf) & 3; len; len--)
204 *p++ = '\0';
205 len = sizeof (srvsvc_enum2); /* 28 */
206 memcpy(p, srvsvc_enum2, len);
207 p += len;
208
209 /*
210 * Compute total length, and fixup RPC header.
211 */
212 len = p - sendbuf;
213 sendbuf[ENUM_RPCLEN_OFF] = len;
214
215 /*
216 * Send the enum request, read the response.
217 * This tests smb_fh_write, smb_fh_read.
218 */
219 wlen = smb_fh_write(fid, 0, len, (char *)sendbuf);
220 if (wlen == -1) {
221 err = errno;
222 printf("write enum req, err=%d\n", err);
223 return (err);
224 }
225 if (wlen != len) {
226 printf("write enum req, short write %d\n", wlen);
227 return (EIO);
228 }
229
230 rlen = smb_fh_read(fid, 0,
231 sizeof (recvbuf), (char *)recvbuf);
232 if (rlen == -1) {
233 err = errno;
234 printf("read enum resp, err=%d\n", err);
235 return (err);
236 }
237
238 /*
239 * Just dump strings found in the response data.
240 * Skip the first 0x90 (RPC wrappers).
241 */
242 printf("enum strings\n");
243 pstrings(recvbuf + 0x90, rlen - 0x90);
244
245 return (0);
246 }
247
248 int
list_shares(struct smb_ctx * ctx)249 list_shares(struct smb_ctx *ctx)
250 {
251 static char path[] = "/srvsvc";
252 static uchar_t key[16];
253 char *server = ctx->ct_srvname;
254 int err, fd;
255
256 printf("open pipe: %s\n", path);
257 fd = smb_fh_open(ctx, path, O_RDWR);
258 if (fd < 0) {
259 perror(path);
260 return (errno);
261 }
262
263 /* Test this too. */
264 err = smb_fh_getssnkey(fd, key, sizeof (key));
265 if (err) {
266 printf("getssnkey: %d\n", err);
267 goto out;
268 }
269
270 err = do_bind(fd);
271 if (err) {
272 printf("do_bind: %d\n", err);
273 goto out;
274 }
275 err = do_enum(server, fd);
276 if (err)
277 printf("do_enum: %d\n", err);
278
279 out:
280 smb_fh_close(fd);
281 return (0);
282 }
283