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(stdout, sattrs->vc_misc_flags,
122                  SMBV_NEG_SMB3_ONLY, "SMB_NEGOTIATE",
123                  "SMBV_NEG_SMB3_ONLY", &ret);
124    print_if_attr_chk_ret(stdout, 0,
125                  0, "SMB_NEGOTIATE",
126                  "AUTO_NEGOTIATE", &ret);
127
128    /* smb version */
129    print_if_attr(stdout, sattrs->vc_flags,
130                  SMBV_SMB302, "SMB_VERSION",
131                  "SMB_3.02", &ret);
132    print_if_attr(stdout, sattrs->vc_flags,
133                  SMBV_SMB30, "SMB_VERSION",
134                  "SMB_3.0", &ret);
135    print_if_attr(stdout, sattrs->vc_flags,
136                  SMBV_SMB2002, "SMB_VERSION",
137                  "SMB_2.002", &ret);
138    print_if_attr(stdout, sattrs->vc_flags,
139                  SMBV_SMB21, "SMB_VERSION",
140                  "SMB_2.1", &ret);
141    print_if_attr_chk_ret(stdout, 0,
142                  0, "SMB_VERSION",
143                  "SMB_1", &ret);
144
145    /*
146     * Note: No way to get file system type since the type is determined at
147     * mount time and not just by a Tree Connect.  If we ever wanted to display
148     * the file system type, we would probably need an IOCTL to the mount
149     * point to get the information.
150     */
151
152    /* Share type */
153    switch (sattrs->ss_type) {
154        case SMB2_SHARE_TYPE_DISK:
155            print_if_attr(stdout, 1, 1, "SMB_SHARE_TYPE", "DISK", &ret);
156            break;
157
158        case SMB2_SHARE_TYPE_PIPE:
159            print_if_attr(stdout, 1, 1, "SMB_SHARE_TYPE", "PIPE", &ret);
160            break;
161
162        case SMB2_SHARE_TYPE_PRINT:
163            print_if_attr(stdout, 1, 1, "SMB_SHARE_TYPE", "PRINT", &ret);
164            break;
165
166        default:
167            print_if_attr_chk_ret(stdout, 0, 0, "SMB_SHARE_TYPE", "UNKNOWN",
168                                  &ret);
169            break;
170    }
171
172    /* smb server capabilities */
173    print_if_attr(stdout, sattrs->vc_flags,
174                  SMBV_SIGNING, "SIGNING_SUPPORTED",
175                  "TRUE", &ret);
176    print_if_attr(stdout, sattrs->vc_flags,
177                  SMBV_SIGNING_REQUIRED, "SIGNING_REQUIRED",
178                  "TRUE", &ret);
179    print_if_attr(stdout, sattrs->vc_smb1_caps,
180                  SMB_CAP_EXT_SECURITY, "EXTENDED_SECURITY_SUPPORTED",
181                  "TRUE", &ret);
182    print_if_attr(stdout, sattrs->vc_smb1_caps,
183                  SMB_CAP_UNIX, "UNIX_SUPPORT",
184                  "TRUE", &ret);
185    print_if_attr(stdout, sattrs->vc_smb1_caps,
186                  SMB_CAP_LARGE_FILES, "LARGE_FILE_SUPPORTED",
187                  "TRUE", &ret);
188
189    /* SMB 2/3 capabilities */
190    print_if_attr(stdout, sattrs->vc_misc_flags,
191                  SMBV_OSX_SERVER, "OS_X_SERVER",
192                  "TRUE", &ret);
193    print_if_attr(stdout, sattrs->vc_misc_flags,
194                  SMBV_CLIENT_SIGNING_REQUIRED, "CLIENT_REQUIRES_SIGNING",
195                  "TRUE", &ret);
196    print_if_attr(stdout, sattrs->vc_misc_flags,
197                  SMBV_HAS_FILEIDS, "FILE_IDS_SUPPORTED",
198                  "TRUE", &ret);
199    print_if_attr(stdout, sattrs->vc_misc_flags,
200                  SMBV_NO_QUERYINFO, "QUERYINFO_NOT_SUPPORTED",
201                  "TRUE", &ret);
202
203    print_if_attr(stdout, sattrs->vc_smb2_caps,
204                  SMB2_GLOBAL_CAP_DFS, "DFS_SUPPORTED",
205                  "TRUE", &ret);
206    print_if_attr(stdout, sattrs->vc_smb2_caps,
207                  SMB2_GLOBAL_CAP_LEASING, "FILE_LEASING_SUPPORTED",
208                  "TRUE", &ret);
209    print_if_attr(stdout, sattrs->vc_smb2_caps,
210                  SMB2_GLOBAL_CAP_LARGE_MTU, "MULTI_CREDIT_SUPPORTED",
211                  "TRUE", &ret);
212    print_if_attr(stdout, sattrs->vc_smb2_caps,
213                  SMB2_GLOBAL_CAP_MULTI_CHANNEL, "MULTI_CHANNEL_SUPPORTED",
214                  "TRUE", &ret);
215    print_if_attr(stdout, sattrs->vc_smb2_caps,
216                  SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, "PERSISTENT_HANDLES_SUPPORTED",
217                  "TRUE", &ret);
218    print_if_attr(stdout, sattrs->vc_smb2_caps,
219                  SMB2_GLOBAL_CAP_DIRECTORY_LEASING, "DIR_LEASING_SUPPORTED",
220                  "TRUE", &ret);
221    print_if_attr(stdout, sattrs->vc_smb2_caps,
222                  SMB2_GLOBAL_CAP_ENCRYPTION, "ENCRYPTION_SUPPORTED",
223                  "TRUE", &ret);
224
225    print_if_attr_chk_ret(stdout, 0,
226                          0, "SERVER_CAPS",
227                          "UNKNOWN", &ret);
228
229    /* other share attributes */
230    print_if_attr(stdout, sattrs->ss_attrs,
231                  FILE_READ_ONLY_VOLUME, "VOLUME_RDONLY",
232                  "TRUE", &ret);
233    print_if_attr(stdout, sattrs->ss_caps,
234                  SMB2_SHARE_CAP_DFS, "DFS_SHARE",
235                  "TRUE", &ret);
236    /* Sealing current status */
237    print_if_attr(stdout, sattrs->ss_flags,
238                  SMB2_SHAREFLAG_ENCRYPT_DATA, "ENCRYPTION_REQUIRED",
239                  "TRUE", &ret);
240
241    /* Signing current status */
242    print_if_attr(stdout, sattrs->vc_hflags2,
243                  SMB_FLAGS2_SECURITY_SIGNATURE, "SIGNING_ON",
244                  "TRUE", &ret);
245
246	if (verbose) {
247        fprintf(stdout, "vc_flags: 0x%x\n", sattrs->vc_flags);
248        fprintf(stdout, "vc_hflags: 0x%x\n", sattrs->vc_hflags);
249        fprintf(stdout, "vc_hflags2: 0x%x\n", sattrs->vc_hflags2);
250        fprintf(stdout, "vc_misc_flags: 0x%llx\n", sattrs->vc_misc_flags);
251        fprintf(stdout, "vc_smb1_caps: 0x%x\n", sattrs->vc_smb1_caps);
252        fprintf(stdout, "vc_smb2_caps: 0x%x\n", sattrs->vc_smb2_caps);
253        fprintf(stdout, "vc_uid: 0x%x\n", sattrs->vc_uid);
254
255        fprintf(stdout, "ss_attrs: 0x%x\n", sattrs->ss_attrs);
256        fprintf(stdout, "ss_caps: 0x%x\n", sattrs->ss_caps);
257        fprintf(stdout, "ss_flags: 0x%x\n", sattrs->ss_flags);
258        fprintf(stdout, "ss_fstype: 0x%x\n", sattrs->ss_fstype);
259        fprintf(stdout, "ss_type: 0x%x\n", sattrs->ss_type);
260    }
261}
262
263static NTSTATUS
264stat_share(char *share_mp, bool disablePrintingHeader)
265{
266    SMBHANDLE inConnection = NULL;
267    NTSTATUS status = STATUS_SUCCESS;
268    struct statfs statbuf;
269    char tmp_name[MNAMELEN];
270    char *share_name = NULL, *end = NULL;
271
272    if ((statfs((const char*)share_mp, &statbuf) == -1) || (strncmp(statbuf.f_fstypename, "smbfs", 5) != 0)) {
273        status = STATUS_INVALID_PARAMETER;
274        errno = EINVAL;
275        return  status;
276	}
277
278    /*
279     * Need to specify a share name, else you get IPC$
280     * Use the f_mntfromname so we dont have to worry about -1, -2 on the
281     * mountpath and skip the initial "//"
282     */
283    strlcpy(tmp_name, &statbuf.f_mntfromname[2], sizeof(tmp_name));
284    share_name = strchr(tmp_name, '/');
285    if (share_name != NULL) {
286        /* skip over the / to point at share name */
287        share_name += 1;
288
289        /* Check for submount and if found, strip it off */
290        end = strchr(share_name, '/');
291        if (end != NULL) {
292            /* Found submount, just null it out as we only want sharepoint */
293            *end = 0x00;
294        }
295    }
296    else {
297        fprintf(stderr, "%s : Failed to find share name in %s\n",
298                __FUNCTION__, statbuf.f_mntfromname);
299        status = STATUS_INVALID_PARAMETER;
300        errno = EINVAL;
301        return  status;
302    }
303
304    status = SMBOpenServerWithMountPoint(share_mp,
305                                         share_name,
306                                         &inConnection,
307                                         0);
308    if (!NT_SUCCESS(status)) {
309        fprintf(stderr, "%s : SMBOpenServerWithMountPoint() failed for %s <%s>\n",
310                __FUNCTION__, share_mp, share_name);
311    }
312    else {
313        SMBShareAttributes sattrs;
314
315        status = SMBGetShareAttributes(inConnection, &sattrs);
316        if (!NT_SUCCESS(status)) {
317            fprintf(stderr, "%s : SMBGetShareAttributes() failed for %s <%s>\n",
318                    __FUNCTION__, share_mp, share_name);
319        }
320        else {
321            if (!disablePrintingHeader)
322                print_header(stdout);
323
324            interpret_and_display(share_name, &sattrs);
325            print_delimeter(stdout);
326        }
327        SMBReleaseServer(inConnection);
328    }
329
330    return status;
331}
332
333static NTSTATUS
334stat_all_shares()
335{
336    NTSTATUS error = STATUS_SUCCESS;
337    struct statfs *fs = NULL;
338    int fs_cnt = 0;
339    int i = 0;
340    int disablePrintingHeader = 1;
341
342    fs = smb_getfsstat(&fs_cnt);
343    if (!fs || fs_cnt < 0)
344        return ENOENT;
345    print_header(stdout);
346    for (i = 0; i < fs_cnt; i++, fs++) {
347        NTSTATUS status;
348
349        if (strncmp(fs->f_fstypename, "smbfs", 5) != 0)
350			continue;
351		if (fs->f_flags & MNT_AUTOMOUNTED)
352            continue;
353
354        status = stat_share(fs->f_mntonname, disablePrintingHeader) ;
355        if (!NT_SUCCESS(status)) {
356            fprintf(stderr, "%s : stat_share() failed for %s\n",
357                    __FUNCTION__, fs->f_mntonname);
358            print_delimeter(stderr);
359            error = status;
360        }
361    }
362
363    return error;
364}
365
366int
367cmd_statshares(int argc, char *argv[])
368{
369    NTSTATUS status = STATUS_SUCCESS;
370    int opt;
371    bool disablePrintingHeader = 0;
372
373    if ((opt = getopt(argc, argv, "am:")) != EOF) {
374		switch(opt) {
375			case 'a':
376                if (argc != 2)
377                    statshares_usage();
378                status = stat_all_shares();
379                break;
380            case 'm':
381                if (argc != 3)
382                    statshares_usage();
383                status = stat_share(optarg, disablePrintingHeader);
384                break;
385            default:
386                break;
387        }
388    }
389    else
390        statshares_usage();
391
392    if (!NT_SUCCESS(status))
393        ntstatus_to_err(status);
394
395    return 0;
396}
397
398void
399statshares_usage(void)
400{
401	fprintf(stderr, "usage : smbutil statshares [-m <mount_path>] | [-a]\n");
402    fprintf(stderr, "\
403            [\n \
404            description :\n \
405            -a : attributes of all mounted shares\n \
406            -m <mount_path> : attributes of share mounted at mount_path\n \
407            ]\n");
408    exit(1);
409}
410