1/* 2 * Copyright (c) 2012 - 2013 Apple Inc. All rights reserved 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Apple Inc. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34#include <sys/param.h> 35#include <sys/ucred.h> 36#include <sys/mount.h> 37#include <sys/errno.h> 38#include <sys/stat.h> 39#include <err.h> 40#include <stdio.h> 41#include <unistd.h> 42#include <strings.h> 43#include <stdlib.h> 44#include <sysexits.h> 45 46#include <smbclient/smbclient.h> 47#include <smbclient/smbclient_internal.h> 48#include <smbclient/smbclient_private.h> 49#include <smbclient/smbclient_netfs.h> 50#include <smbclient/ntstatus.h> 51 52#include <netsmb/smb_lib.h> 53#include <netsmb/smb_dev.h> 54#include <netsmb/smbio.h> 55#include <netsmb/smbio_2.h> 56#include <netsmb/smb_2.h> 57#include <netsmb/smb_conn.h> 58 59#include "common.h" 60#include "netshareenum.h" 61 62static void 63print_header(FILE *fp) 64{ 65 fprintf(fp, "\n================================================"); 66 fprintf(fp, "==================================================\n"); 67 fprintf(fp, "%-30s%-30s%s\n", "SHARE", "ATTRIBUTE TYPE", "VALUE"); 68 fprintf(fp, "=================================================="); 69 fprintf(fp, "================================================\n"); 70} 71 72static void 73print_if_attr(FILE *fp, uint64_t flag, uint64_t of_type, 74 const char *attr, const char *attr_val, int *isattr) 75{ 76 if (*isattr == -1) 77 fprintf(fp, "%-30s%-30s%s\n", "", attr, attr_val); 78 else if (flag & of_type) { 79 fprintf(fp, "%-30s%-30s%s\n", "", attr, attr_val); 80 *isattr = 1; 81 } 82} 83 84static void 85print_if_attr_chk_ret(FILE *fp, uint64_t flag, uint64_t of_type, 86 const char *attr, const char *attr_val, int *ret) 87{ 88 if (!(*ret)) { 89 *ret = -1; 90 print_if_attr(fp, flag, of_type, attr, attr_val, ret); 91 } 92 *ret = 0; 93} 94 95static void 96print_delimeter(FILE *fp) 97{ 98 fprintf(fp, "\n------------------------------------------------"); 99 fprintf(fp, "--------------------------------------------------\n"); \ 100} 101 102static void 103interpret_and_display(char *share, SMBShareAttributes *sattrs) 104{ 105 int ret = 0; 106 107 /* share name and server */ 108 fprintf(stdout, "%-30s\n", share); 109 fprintf(stdout, "%-30s%-30s%s\n", "", "SERVER_NAME", sattrs->server_name); 110 111 /* user who mounted this share */ 112 fprintf(stdout, "%-30s%-30s%d\n", "","USER_ID", sattrs->vc_uid); 113 114 /* smb negotiate */ 115 print_if_attr(stdout, sattrs->vc_misc_flags, 116 SMBV_NEG_SMB1_ONLY, "SMB_NEGOTIATE", 117 "SMBV_NEG_SMB1_ONLY", &ret); 118 print_if_attr(stdout, sattrs->vc_misc_flags, 119 SMBV_NEG_SMB2_ONLY, "SMB_NEGOTIATE", 120 "SMBV_NEG_SMB2_ONLY", &ret); 121 print_if_attr_chk_ret(stdout, 0, 122 0, "SMB_NEGOTIATE", 123 "AUTO_NEGOTIATE", &ret); 124 125 /* smb version */ 126 print_if_attr(stdout, sattrs->vc_flags, 127 SMBV_SMB2002, "SMB_VERSION", 128 "SMB_2.002", &ret); 129 print_if_attr(stdout, sattrs->vc_flags, 130 SMBV_SMB21, "SMB_VERSION", 131 "SMB_2.1", &ret); 132 print_if_attr_chk_ret(stdout, 0, 133 0, "SMB_VERSION", 134 "SMB_1", &ret); 135 136 /* 137 * Note: No way to get file system type since the type is determined at 138 * mount time and not just by a Tree Connect. If we ever wanted to display 139 * the file system type, we would probably need an IOCTL to the mount 140 * point to get the information. 141 */ 142 143 /* Share type */ 144 switch (sattrs->ss_type) { 145 case SMB2_SHARE_TYPE_DISK: 146 print_if_attr(stdout, 1, 1, "SMB_SHARE_TYPE", "DISK", &ret); 147 break; 148 149 case SMB2_SHARE_TYPE_PIPE: 150 print_if_attr(stdout, 1, 1, "SMB_SHARE_TYPE", "PIPE", &ret); 151 break; 152 153 case SMB2_SHARE_TYPE_PRINT: 154 print_if_attr(stdout, 1, 1, "SMB_SHARE_TYPE", "PRINT", &ret); 155 break; 156 157 default: 158 print_if_attr_chk_ret(stdout, 0, 0, "SMB_SHARE_TYPE", "UNKNOWN", 159 &ret); 160 break; 161 } 162 163 /* smb server capabilities */ 164 print_if_attr(stdout, sattrs->vc_flags, 165 SMBV_SIGNING, "SIGNING_SUPPORTED", 166 "TRUE", &ret); 167 print_if_attr(stdout, sattrs->vc_flags, 168 SMBV_SIGNING_REQUIRED, "SIGNING_REQUIRED", 169 "TRUE", &ret); 170 print_if_attr(stdout, sattrs->vc_smb1_caps, 171 SMB_CAP_EXT_SECURITY, "EXTENDED_SECURITY_SUPPORTED", 172 "TRUE", &ret); 173 print_if_attr(stdout, sattrs->vc_smb1_caps, 174 SMB_CAP_UNIX, "UNIX_SUPPORT", 175 "TRUE", &ret); 176 print_if_attr(stdout, sattrs->vc_smb1_caps, 177 SMB_CAP_LARGE_FILES, "LARGE_FILE_SUPPORTED", 178 "TRUE", &ret); 179 180 /* SMB 2.x capabilities */ 181 print_if_attr(stdout, sattrs->vc_misc_flags, 182 SMBV_OSX_SERVER, "OS_X_SERVER", 183 "TRUE", &ret); 184 print_if_attr(stdout, sattrs->vc_misc_flags, 185 SMBV_CLIENT_SIGNING_REQUIRED, "CLIENT_REQUIRES_SIGNING", 186 "TRUE", &ret); 187 print_if_attr(stdout, sattrs->vc_misc_flags, 188 SMBV_HAS_FILEIDS, "FILE_IDS_SUPPORTED", 189 "TRUE", &ret); 190 print_if_attr(stdout, sattrs->vc_misc_flags, 191 SMBV_NO_QUERYINFO, "QUERYINFO_NOT_SUPPORTED", 192 "TRUE", &ret); 193 194 print_if_attr(stdout, sattrs->vc_smb2_caps, 195 SMB2_GLOBAL_CAP_DFS, "DFS_SUPPORTED", 196 "TRUE", &ret); 197 print_if_attr(stdout, sattrs->vc_smb2_caps, 198 SMB2_GLOBAL_CAP_LEASING, "FILE_LEASING_SUPPORTED", 199 "TRUE", &ret); 200 print_if_attr(stdout, sattrs->vc_smb2_caps, 201 SMB2_GLOBAL_CAP_LARGE_MTU, "MULTI_CREDIT_SUPPORTED", 202 "TRUE", &ret); 203 print_if_attr(stdout, sattrs->vc_smb2_caps, 204 SMB2_GLOBAL_CAP_MULTI_CHANNEL, "MULTI_CHANNEL_SUPPORTED", 205 "TRUE", &ret); 206 print_if_attr(stdout, sattrs->vc_smb2_caps, 207 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, "PERSISTENT_HANDLES_SUPPORTED", 208 "TRUE", &ret); 209 print_if_attr(stdout, sattrs->vc_smb2_caps, 210 SMB2_GLOBAL_CAP_DIRECTORY_LEASING, "DIR_LEASING_SUPPORTED", 211 "TRUE", &ret); 212 print_if_attr(stdout, sattrs->vc_smb2_caps, 213 SMB2_GLOBAL_CAP_ENCRYPTION, "ENCRYPTION_SUPPORTED", 214 "TRUE", &ret); 215 216 print_if_attr_chk_ret(stdout, 0, 217 0, "SERVER_CAPS", 218 "UNKNOWN", &ret); 219 220 /* other share attributes */ 221 print_if_attr(stdout, sattrs->ss_attrs, 222 FILE_READ_ONLY_VOLUME, "VOLUME_RDONLY", 223 "TRUE", &ret); 224 print_if_attr(stdout, sattrs->ss_caps, 225 SMB2_SHARE_CAP_DFS, "DFS_SHARE", 226 "TRUE", &ret); 227 228 if (verbose) { 229 fprintf(stdout, "vc_flags: 0x%x\n", sattrs->vc_flags); 230 fprintf(stdout, "vc_hflags: 0x%x\n", sattrs->vc_hflags); 231 fprintf(stdout, "vc_hflags2: 0x%x\n", sattrs->vc_hflags2); 232 fprintf(stdout, "vc_misc_flags: 0x%llx\n", sattrs->vc_misc_flags); 233 fprintf(stdout, "vc_smb1_caps: 0x%x\n", sattrs->vc_smb1_caps); 234 fprintf(stdout, "vc_smb2_caps: 0x%x\n", sattrs->vc_smb2_caps); 235 fprintf(stdout, "vc_uid: 0x%x\n", sattrs->vc_uid); 236 237 fprintf(stdout, "ss_attrs: 0x%x\n", sattrs->ss_attrs); 238 fprintf(stdout, "ss_caps: 0x%x\n", sattrs->ss_caps); 239 fprintf(stdout, "ss_flags: 0x%x\n", sattrs->ss_flags); 240 fprintf(stdout, "ss_fstype: 0x%x\n", sattrs->ss_fstype); 241 fprintf(stdout, "ss_type: 0x%x\n", sattrs->ss_type); 242 } 243} 244 245static NTSTATUS 246stat_share(char *share_mp, bool disablePrintingHeader) 247{ 248 SMBHANDLE inConnection = NULL; 249 NTSTATUS status = STATUS_SUCCESS; 250 struct statfs statbuf; 251 char tmp_name[MNAMELEN]; 252 char *share_name = NULL, *end = NULL; 253 254 if ((statfs((const char*)share_mp, &statbuf) == -1) || (strncmp(statbuf.f_fstypename, "smbfs", 5) != 0)) { 255 status = STATUS_INVALID_PARAMETER; 256 errno = EINVAL; 257 return status; 258 } 259 260 /* 261 * Need to specify a share name, else you get IPC$ 262 * Use the f_mntfromname so we dont have to worry about -1, -2 on the 263 * mountpath and skip the initial "//" 264 */ 265 strlcpy(tmp_name, &statbuf.f_mntfromname[2], sizeof(tmp_name)); 266 share_name = strchr(tmp_name, '/'); 267 if (share_name != NULL) { 268 /* skip over the / to point at share name */ 269 share_name += 1; 270 271 /* Check for submount and if found, strip it off */ 272 end = strchr(share_name, '/'); 273 if (end != NULL) { 274 /* Found submount, just null it out as we only want sharepoint */ 275 *end = 0x00; 276 } 277 } 278 else { 279 fprintf(stderr, "%s : Failed to find share name in %s\n", 280 __FUNCTION__, statbuf.f_mntfromname); 281 status = STATUS_INVALID_PARAMETER; 282 errno = EINVAL; 283 return status; 284 } 285 286 status = SMBOpenServerWithMountPoint(share_mp, 287 share_name, 288 &inConnection, 289 0); 290 if (!NT_SUCCESS(status)) { 291 fprintf(stderr, "%s : SMBOpenServerWithMountPoint() failed for %s <%s>\n", 292 __FUNCTION__, share_mp, share_name); 293 } 294 else { 295 SMBShareAttributes sattrs; 296 297 status = SMBGetShareAttributes(inConnection, &sattrs); 298 if (!NT_SUCCESS(status)) { 299 fprintf(stderr, "%s : SMBGetShareAttributes() failed for %s <%s>\n", 300 __FUNCTION__, share_mp, share_name); 301 } 302 else { 303 if (!disablePrintingHeader) 304 print_header(stdout); 305 306 interpret_and_display(share_name, &sattrs); 307 print_delimeter(stdout); 308 } 309 SMBReleaseServer(inConnection); 310 } 311 312 return status; 313} 314 315static NTSTATUS 316stat_all_shares() 317{ 318 NTSTATUS error = STATUS_SUCCESS; 319 struct statfs *fs = NULL; 320 int fs_cnt = 0; 321 int i = 0; 322 int disablePrintingHeader = 1; 323 324 fs = smb_getfsstat(&fs_cnt); 325 if (!fs || fs_cnt < 0) 326 return ENOENT; 327 print_header(stdout); 328 for (i = 0; i < fs_cnt; i++, fs++) { 329 NTSTATUS status; 330 331 if (strncmp(fs->f_fstypename, "smbfs", 5) != 0) 332 continue; 333 if (fs->f_flags & MNT_AUTOMOUNTED) 334 continue; 335 336 status = stat_share(fs->f_mntonname, disablePrintingHeader) ; 337 if (!NT_SUCCESS(status)) { 338 fprintf(stderr, "%s : stat_share() failed for %s\n", 339 __FUNCTION__, fs->f_mntonname); 340 print_delimeter(stderr); 341 error = status; 342 } 343 } 344 345 return error; 346} 347 348int 349cmd_statshares(int argc, char *argv[]) 350{ 351 NTSTATUS status = STATUS_SUCCESS; 352 int opt; 353 bool disablePrintingHeader = 0; 354 355 if ((opt = getopt(argc, argv, "am:")) != EOF) { 356 switch(opt) { 357 case 'a': 358 if (argc != 2) 359 statshares_usage(); 360 status = stat_all_shares(); 361 break; 362 case 'm': 363 if (argc != 3) 364 statshares_usage(); 365 status = stat_share(optarg, disablePrintingHeader); 366 break; 367 default: 368 break; 369 } 370 } 371 else 372 statshares_usage(); 373 374 if (!NT_SUCCESS(status)) 375 ntstatus_to_err(status); 376 377 return 0; 378} 379 380void 381statshares_usage(void) 382{ 383 fprintf(stderr, "usage : smbutil statshare [-m <mount_path>] | [-a]\n"); 384 fprintf(stderr, "\ 385 [\n \ 386 description :\n \ 387 -a : attributes of all mounted shares\n \ 388 -m <mount_path> : attributes of share mounted at mount_path\n \ 389 ]\n"); 390 exit(1); 391} 392