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 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 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 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 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 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