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