~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/utils/net_usershare.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Samba Unix/Linux SMB client library
 
3
   Distributed SMB/CIFS Server Management Utility
 
4
 
 
5
   Copyright (C) Jeremy Allison (jra@samba.org) 2005
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
20
 
 
21
#include "includes.h"
 
22
#include "utils/net.h"
 
23
 
 
24
struct {
 
25
        const char *us_errstr;
 
26
        enum usershare_err us_err;
 
27
} us_errs [] = {
 
28
        {"",USERSHARE_OK},
 
29
        {"Malformed usershare file", USERSHARE_MALFORMED_FILE},
 
30
        {"Bad version number", USERSHARE_BAD_VERSION},
 
31
        {"Malformed path entry", USERSHARE_MALFORMED_PATH},
 
32
        {"Malformed comment entryfile", USERSHARE_MALFORMED_COMMENT_DEF},
 
33
        {"Malformed acl definition", USERSHARE_MALFORMED_ACL_DEF},
 
34
        {"Acl parse error", USERSHARE_ACL_ERR},
 
35
        {"Path not absolute", USERSHARE_PATH_NOT_ABSOLUTE},
 
36
        {"Path is denied", USERSHARE_PATH_IS_DENIED},
 
37
        {"Path not allowed", USERSHARE_PATH_NOT_ALLOWED},
 
38
        {"Path is not a directory", USERSHARE_PATH_NOT_DIRECTORY},
 
39
        {"System error", USERSHARE_POSIX_ERR},
 
40
        {NULL,(enum usershare_err)-1}
 
41
};
 
42
 
 
43
static const char *get_us_error_code(enum usershare_err us_err)
 
44
{
 
45
        char *result;
 
46
        int idx = 0;
 
47
 
 
48
        while (us_errs[idx].us_errstr != NULL) {
 
49
                if (us_errs[idx].us_err == us_err) {
 
50
                        return us_errs[idx].us_errstr;
 
51
                }
 
52
                idx++;
 
53
        }
 
54
 
 
55
        result = talloc_asprintf(talloc_tos(), "Usershare error code (0x%x)",
 
56
                                 (unsigned int)us_err);
 
57
        SMB_ASSERT(result != NULL);
 
58
        return result;
 
59
}
 
60
 
 
61
/* The help subsystem for the USERSHARE subcommand */
 
62
 
 
63
static int net_usershare_add_usage(struct net_context *c, int argc, const char **argv)
 
64
{
 
65
        char chr = *lp_winbind_separator();
 
66
        d_printf(
 
67
                "net usershare add [-l|--long] <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>]\n"
 
68
                "\tAdds the specified share name for this user.\n"
 
69
                "\t<sharename> is the new share name.\n"
 
70
                "\t<path> is the path on the filesystem to export.\n"
 
71
                "\t<comment> is the optional comment for the new share.\n"
 
72
                "\t<acl> is an optional share acl in the format \"DOMAIN%cname:X,DOMAIN%cname:X,....\"\n"
 
73
                "\t<guest_ok=y> if present sets \"guest ok = yes\" on this usershare.\n"
 
74
                "\t\t\"X\" represents a permission and can be any one of the characters f, r or d\n"
 
75
                "\t\twhere \"f\" means full control, \"r\" means read-only, \"d\" means deny access.\n"
 
76
                "\t\tname may be a domain user or group. For local users use the local server name "
 
77
                "instead of \"DOMAIN\"\n"
 
78
                "\t\tThe default acl is \"Everyone:r\" which allows everyone read-only access.\n"
 
79
                "\tAdd -l or --long to print the info on the newly added share.\n",
 
80
                chr, chr );
 
81
        return -1;
 
82
}
 
83
 
 
84
static int net_usershare_delete_usage(struct net_context *c, int argc, const char **argv)
 
85
{
 
86
        d_printf(
 
87
                "net usershare delete <sharename>\n"
 
88
                "\tdeletes the specified share name for this user.\n");
 
89
        return -1;
 
90
}
 
91
 
 
92
static int net_usershare_info_usage(struct net_context *c, int argc, const char **argv)
 
93
{
 
94
        d_printf(
 
95
                "net usershare info [-l|--long] [wildcard sharename]\n"
 
96
                "\tPrints out the path, comment and acl elements of shares that match the wildcard.\n"
 
97
                "\tBy default only gives info on shares owned by the current user\n"
 
98
                "\tAdd -l or --long to apply this to all shares\n"
 
99
                "\tOmit the sharename or use a wildcard of '*' to see all shares\n");
 
100
        return -1;
 
101
}
 
102
 
 
103
static int net_usershare_list_usage(struct net_context *c, int argc, const char **argv)
 
104
{
 
105
        d_printf(
 
106
                "net usershare list [-l|--long] [wildcard sharename]\n"
 
107
                "\tLists the names of all shares that match the wildcard.\n"
 
108
                "\tBy default only lists shares owned by the current user\n"
 
109
                "\tAdd -l or --long to apply this to all shares\n"
 
110
                "\tOmit the sharename or use a wildcard of '*' to see all shares\n");
 
111
        return -1;
 
112
}
 
113
 
 
114
int net_usershare_usage(struct net_context *c, int argc, const char **argv)
 
115
{
 
116
        d_printf("net usershare add <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>] to "
 
117
                                "add or change a user defined share.\n"
 
118
                "net usershare delete <sharename> to delete a user defined share.\n"
 
119
                "net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share.\n"
 
120
                "net usershare list [-l|--long] [wildcard sharename] to list user defined shares.\n"
 
121
                "net usershare help\n"
 
122
                "\nType \"net usershare help <option>\" to get more information on that option\n\n");
 
123
 
 
124
        net_common_flags_usage(c, argc, argv);
 
125
        return -1;
 
126
}
 
127
 
 
128
/***************************************************************************
 
129
***************************************************************************/
 
130
 
 
131
static char *get_basepath(TALLOC_CTX *ctx)
 
132
{
 
133
        char *basepath = talloc_strdup(ctx, lp_usershare_path());
 
134
 
 
135
        if (!basepath) {
 
136
                return NULL;
 
137
        }
 
138
        if ((basepath[0] != '\0') && (basepath[strlen(basepath)-1] == '/')) {
 
139
                basepath[strlen(basepath)-1] = '\0';
 
140
        }
 
141
        return basepath;
 
142
}
 
143
 
 
144
/***************************************************************************
 
145
 Delete a single userlevel share.
 
146
***************************************************************************/
 
147
 
 
148
static int net_usershare_delete(struct net_context *c, int argc, const char **argv)
 
149
{
 
150
        char *us_path;
 
151
        char *sharename;
 
152
 
 
153
        if (argc != 1 || c->display_usage) {
 
154
                return net_usershare_delete_usage(c, argc, argv);
 
155
        }
 
156
 
 
157
        if ((sharename = strdup_lower(argv[0])) == NULL) {
 
158
                d_fprintf(stderr, "strdup failed\n");
 
159
                return -1;
 
160
        }
 
161
 
 
162
        if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
 
163
                d_fprintf(stderr, "net usershare delete: share name %s contains "
 
164
                        "invalid characters (any of %s)\n",
 
165
                        sharename, INVALID_SHARENAME_CHARS);
 
166
                SAFE_FREE(sharename);
 
167
                return -1;
 
168
        }
 
169
 
 
170
        us_path = talloc_asprintf(talloc_tos(),
 
171
                                "%s/%s",
 
172
                                lp_usershare_path(),
 
173
                                sharename);
 
174
        if (!us_path) {
 
175
                SAFE_FREE(sharename);
 
176
                return -1;
 
177
        }
 
178
 
 
179
        if (unlink(us_path) != 0) {
 
180
                d_fprintf(stderr, "net usershare delete: unable to remove usershare %s. "
 
181
                        "Error was %s\n",
 
182
                        us_path, strerror(errno));
 
183
                SAFE_FREE(sharename);
 
184
                return -1;
 
185
        }
 
186
        SAFE_FREE(sharename);
 
187
        return 0;
 
188
}
 
189
 
 
190
/***************************************************************************
 
191
 Data structures to handle a list of usershare files.
 
192
***************************************************************************/
 
193
 
 
194
struct file_list {
 
195
        struct file_list *next, *prev;
 
196
        const char *pathname;
 
197
};
 
198
 
 
199
static struct file_list *flist;
 
200
 
 
201
/***************************************************************************
 
202
***************************************************************************/
 
203
 
 
204
static int get_share_list(TALLOC_CTX *ctx, const char *wcard, bool only_ours)
 
205
{
 
206
        SMB_STRUCT_DIR *dp;
 
207
        SMB_STRUCT_DIRENT *de;
 
208
        uid_t myuid = geteuid();
 
209
        struct file_list *fl = NULL;
 
210
        char *basepath = get_basepath(ctx);
 
211
 
 
212
        if (!basepath) {
 
213
                return -1;
 
214
        }
 
215
        dp = sys_opendir(basepath);
 
216
        if (!dp) {
 
217
                d_fprintf(stderr, "get_share_list: cannot open usershare directory %s. Error %s\n",
 
218
                        basepath, strerror(errno) );
 
219
                return -1;
 
220
        }
 
221
 
 
222
        while((de = sys_readdir(dp)) != 0) {
 
223
                SMB_STRUCT_STAT sbuf;
 
224
                char *path;
 
225
                const char *n = de->d_name;
 
226
 
 
227
                /* Ignore . and .. */
 
228
                if (*n == '.') {
 
229
                        if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
 
230
                                continue;
 
231
                        }
 
232
                }
 
233
 
 
234
                if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
 
235
                        d_fprintf(stderr, "get_share_list: ignoring bad share name %s\n",n);
 
236
                        continue;
 
237
                }
 
238
                path = talloc_asprintf(ctx,
 
239
                                        "%s/%s",
 
240
                                        basepath,
 
241
                                        n);
 
242
                if (!path) {
 
243
                        sys_closedir(dp);
 
244
                        return -1;
 
245
                }
 
246
 
 
247
                if (sys_lstat(path, &sbuf) != 0) {
 
248
                        d_fprintf(stderr, "get_share_list: can't lstat file %s. Error was %s\n",
 
249
                                path, strerror(errno) );
 
250
                        continue;
 
251
                }
 
252
 
 
253
                if (!S_ISREG(sbuf.st_mode)) {
 
254
                        d_fprintf(stderr, "get_share_list: file %s is not a regular file. Ignoring.\n",
 
255
                                path );
 
256
                        continue;
 
257
                }
 
258
 
 
259
                if (only_ours && sbuf.st_uid != myuid) {
 
260
                        continue;
 
261
                }
 
262
 
 
263
                if (!unix_wild_match(wcard, n)) {
 
264
                        continue;
 
265
                }
 
266
 
 
267
                /* (Finally) - add to list. */
 
268
                fl = TALLOC_P(ctx, struct file_list);
 
269
                if (!fl) {
 
270
                        sys_closedir(dp);
 
271
                        return -1;
 
272
                }
 
273
                fl->pathname = talloc_strdup(ctx, n);
 
274
                if (!fl->pathname) {
 
275
                        sys_closedir(dp);
 
276
                        return -1;
 
277
                }
 
278
 
 
279
                DLIST_ADD(flist, fl);
 
280
        }
 
281
 
 
282
        sys_closedir(dp);
 
283
        return 0;
 
284
}
 
285
 
 
286
enum us_priv_op { US_LIST_OP, US_INFO_OP};
 
287
 
 
288
struct us_priv_info {
 
289
        TALLOC_CTX *ctx;
 
290
        enum us_priv_op op;
 
291
        struct net_context *c;
 
292
};
 
293
 
 
294
/***************************************************************************
 
295
 Call a function for every share on the list.
 
296
***************************************************************************/
 
297
 
 
298
static int process_share_list(int (*fn)(struct file_list *, void *), void *priv)
 
299
{
 
300
        struct file_list *fl;
 
301
        int ret = 0;
 
302
 
 
303
        for (fl = flist; fl; fl = fl->next) {
 
304
                ret = (*fn)(fl, priv);
 
305
        }
 
306
 
 
307
        return ret;
 
308
}
 
309
 
 
310
/***************************************************************************
 
311
 Info function.
 
312
***************************************************************************/
 
313
 
 
314
static int info_fn(struct file_list *fl, void *priv)
 
315
{
 
316
        SMB_STRUCT_STAT sbuf;
 
317
        char **lines = NULL;
 
318
        struct us_priv_info *pi = (struct us_priv_info *)priv;
 
319
        TALLOC_CTX *ctx = pi->ctx;
 
320
        struct net_context *c = pi->c;
 
321
        int fd = -1;
 
322
        int numlines = 0;
 
323
        SEC_DESC *psd = NULL;
 
324
        char *basepath;
 
325
        char *sharepath = NULL;
 
326
        char *comment = NULL;
 
327
        char *acl_str;
 
328
        int num_aces;
 
329
        char sep_str[2];
 
330
        enum usershare_err us_err;
 
331
        bool guest_ok = false;
 
332
 
 
333
        sep_str[0] = *lp_winbind_separator();
 
334
        sep_str[1] = '\0';
 
335
 
 
336
        basepath = get_basepath(ctx);
 
337
        if (!basepath) {
 
338
                return -1;
 
339
        }
 
340
        basepath = talloc_asprintf_append(basepath,
 
341
                        "/%s",
 
342
                        fl->pathname);
 
343
        if (!basepath) {
 
344
                return -1;
 
345
        }
 
346
 
 
347
#ifdef O_NOFOLLOW
 
348
        fd = sys_open(basepath, O_RDONLY|O_NOFOLLOW, 0);
 
349
#else
 
350
        fd = sys_open(basepath, O_RDONLY, 0);
 
351
#endif
 
352
 
 
353
        if (fd == -1) {
 
354
                d_fprintf(stderr, "info_fn: unable to open %s. %s\n",
 
355
                        basepath, strerror(errno) );
 
356
                return -1;
 
357
        }
 
358
 
 
359
        /* Paranoia... */
 
360
        if (sys_fstat(fd, &sbuf) != 0) {
 
361
                d_fprintf(stderr, "info_fn: can't fstat file %s. Error was %s\n",
 
362
                        basepath, strerror(errno) );
 
363
                close(fd);
 
364
                return -1;
 
365
        }
 
366
 
 
367
        if (!S_ISREG(sbuf.st_mode)) {
 
368
                d_fprintf(stderr, "info_fn: file %s is not a regular file. Ignoring.\n",
 
369
                        basepath );
 
370
                close(fd);
 
371
                return -1;
 
372
        }
 
373
 
 
374
        lines = fd_lines_load(fd, &numlines, 10240, NULL);
 
375
        close(fd);
 
376
 
 
377
        if (lines == NULL) {
 
378
                return -1;
 
379
        }
 
380
 
 
381
        /* Ensure it's well formed. */
 
382
        us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines,
 
383
                                &sharepath,
 
384
                                &comment,
 
385
                                &psd,
 
386
                                &guest_ok);
 
387
 
 
388
        TALLOC_FREE(lines);
 
389
 
 
390
        if (us_err != USERSHARE_OK) {
 
391
                d_fprintf(stderr, "info_fn: file %s is not a well formed usershare file.\n",
 
392
                        basepath );
 
393
                d_fprintf(stderr, "info_fn: Error was %s.\n",
 
394
                        get_us_error_code(us_err) );
 
395
                return -1;
 
396
        }
 
397
 
 
398
        acl_str = talloc_strdup(ctx, "usershare_acl=");
 
399
        if (!acl_str) {
 
400
                return -1;
 
401
        }
 
402
 
 
403
        for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) {
 
404
                const char *domain;
 
405
                const char *name;
 
406
                NTSTATUS ntstatus;
 
407
 
 
408
                ntstatus = net_lookup_name_from_sid(c, ctx,
 
409
                                                    &psd->dacl->aces[num_aces].trustee,
 
410
                                                    &domain, &name);
 
411
 
 
412
                if (NT_STATUS_IS_OK(ntstatus)) {
 
413
                        if (domain && *domain) {
 
414
                                acl_str = talloc_asprintf_append(acl_str,
 
415
                                                "%s%s",
 
416
                                                domain,
 
417
                                                sep_str);
 
418
                                if (!acl_str) {
 
419
                                        return -1;
 
420
                                }
 
421
                        }
 
422
                        acl_str = talloc_asprintf_append(acl_str,
 
423
                                                "%s",
 
424
                                                name);
 
425
                        if (!acl_str) {
 
426
                                return -1;
 
427
                        }
 
428
 
 
429
                } else {
 
430
                        fstring sidstr;
 
431
                        sid_to_fstring(sidstr,
 
432
                                       &psd->dacl->aces[num_aces].trustee);
 
433
                        acl_str = talloc_asprintf_append(acl_str,
 
434
                                                "%s",
 
435
                                                sidstr);
 
436
                        if (!acl_str) {
 
437
                                return -1;
 
438
                        }
 
439
                }
 
440
                acl_str = talloc_asprintf_append(acl_str, ":");
 
441
                if (!acl_str) {
 
442
                        return -1;
 
443
                }
 
444
 
 
445
                if (psd->dacl->aces[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) {
 
446
                        acl_str = talloc_asprintf_append(acl_str, "D,");
 
447
                        if (!acl_str) {
 
448
                                return -1;
 
449
                        }
 
450
                } else {
 
451
                        if (psd->dacl->aces[num_aces].access_mask & GENERIC_ALL_ACCESS) {
 
452
                                acl_str = talloc_asprintf_append(acl_str, "F,");
 
453
                        } else {
 
454
                                acl_str = talloc_asprintf_append(acl_str, "R,");
 
455
                        }
 
456
                        if (!acl_str) {
 
457
                                return -1;
 
458
                        }
 
459
                }
 
460
        }
 
461
 
 
462
        if (pi->op == US_INFO_OP) {
 
463
                d_printf("[%s]\n", fl->pathname );
 
464
                d_printf("path=%s\n", sharepath );
 
465
                d_printf("comment=%s\n", comment);
 
466
                d_printf("%s\n", acl_str);
 
467
                d_printf("guest_ok=%c\n\n", guest_ok ? 'y' : 'n');
 
468
        } else if (pi->op == US_LIST_OP) {
 
469
                d_printf("%s\n", fl->pathname);
 
470
        }
 
471
 
 
472
        return 0;
 
473
}
 
474
 
 
475
/***************************************************************************
 
476
 Print out info (internal detail) on userlevel shares.
 
477
***************************************************************************/
 
478
 
 
479
static int net_usershare_info(struct net_context *c, int argc, const char **argv)
 
480
{
 
481
        fstring wcard;
 
482
        bool only_ours = true;
 
483
        int ret = -1;
 
484
        struct us_priv_info pi;
 
485
        TALLOC_CTX *ctx;
 
486
 
 
487
        fstrcpy(wcard, "*");
 
488
 
 
489
        if (c->display_usage)
 
490
                return net_usershare_info_usage(c, argc, argv);
 
491
 
 
492
        if (c->opt_long_list_entries) {
 
493
                only_ours = false;
 
494
        }
 
495
 
 
496
        switch (argc) {
 
497
                case 0:
 
498
                        break;
 
499
                case 1:
 
500
                        fstrcpy(wcard, argv[0]);
 
501
                        break;
 
502
                default:
 
503
                        return net_usershare_info_usage(c, argc, argv);
 
504
        }
 
505
 
 
506
        strlower_m(wcard);
 
507
 
 
508
        ctx = talloc_init("share_info");
 
509
        ret = get_share_list(ctx, wcard, only_ours);
 
510
        if (ret) {
 
511
                return ret;
 
512
        }
 
513
 
 
514
        pi.ctx = ctx;
 
515
        pi.op = US_INFO_OP;
 
516
        pi.c = c;
 
517
 
 
518
        ret = process_share_list(info_fn, &pi);
 
519
        talloc_destroy(ctx);
 
520
        return ret;
 
521
}
 
522
 
 
523
/***************************************************************************
 
524
 Count the current total number of usershares.
 
525
***************************************************************************/
 
526
 
 
527
static int count_num_usershares(void)
 
528
{
 
529
        SMB_STRUCT_DIR *dp;
 
530
        SMB_STRUCT_DIRENT *de;
 
531
        int num_usershares = 0;
 
532
        TALLOC_CTX *ctx = talloc_tos();
 
533
        char *basepath = get_basepath(ctx);
 
534
 
 
535
        if (!basepath) {
 
536
                return -1;
 
537
        }
 
538
 
 
539
        dp = sys_opendir(basepath);
 
540
        if (!dp) {
 
541
                d_fprintf(stderr, "count_num_usershares: cannot open usershare directory %s. Error %s\n",
 
542
                        basepath, strerror(errno) );
 
543
                return -1;
 
544
        }
 
545
 
 
546
        while((de = sys_readdir(dp)) != 0) {
 
547
                SMB_STRUCT_STAT sbuf;
 
548
                char *path;
 
549
                const char *n = de->d_name;
 
550
 
 
551
                /* Ignore . and .. */
 
552
                if (*n == '.') {
 
553
                        if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
 
554
                                continue;
 
555
                        }
 
556
                }
 
557
 
 
558
                if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
 
559
                        d_fprintf(stderr, "count_num_usershares: ignoring bad share name %s\n",n);
 
560
                        continue;
 
561
                }
 
562
                path = talloc_asprintf(ctx,
 
563
                                "%s/%s",
 
564
                                basepath,
 
565
                                n);
 
566
                if (!path) {
 
567
                        sys_closedir(dp);
 
568
                        return -1;
 
569
                }
 
570
 
 
571
                if (sys_lstat(path, &sbuf) != 0) {
 
572
                        d_fprintf(stderr, "count_num_usershares: can't lstat file %s. Error was %s\n",
 
573
                                path, strerror(errno) );
 
574
                        continue;
 
575
                }
 
576
 
 
577
                if (!S_ISREG(sbuf.st_mode)) {
 
578
                        d_fprintf(stderr, "count_num_usershares: file %s is not a regular file. Ignoring.\n",
 
579
                                path );
 
580
                        continue;
 
581
                }
 
582
                num_usershares++;
 
583
        }
 
584
 
 
585
        sys_closedir(dp);
 
586
        return num_usershares;
 
587
}
 
588
 
 
589
/***************************************************************************
 
590
 Add a single userlevel share.
 
591
***************************************************************************/
 
592
 
 
593
static int net_usershare_add(struct net_context *c, int argc, const char **argv)
 
594
{
 
595
        TALLOC_CTX *ctx = talloc_stackframe();
 
596
        SMB_STRUCT_STAT sbuf;
 
597
        SMB_STRUCT_STAT lsbuf;
 
598
        char *sharename;
 
599
        char *full_path;
 
600
        char *full_path_tmp;
 
601
        const char *us_path;
 
602
        const char *us_comment;
 
603
        const char *arg_acl;
 
604
        char *us_acl;
 
605
        char *file_img;
 
606
        int num_aces = 0;
 
607
        int i;
 
608
        int tmpfd;
 
609
        const char *pacl;
 
610
        size_t to_write;
 
611
        uid_t myeuid = geteuid();
 
612
        bool guest_ok = false;
 
613
        int num_usershares;
 
614
 
 
615
        us_comment = "";
 
616
        arg_acl = "S-1-1-0:R";
 
617
 
 
618
        if (c->display_usage)
 
619
                return net_usershare_add_usage(c, argc, argv);
 
620
 
 
621
        switch (argc) {
 
622
                case 0:
 
623
                case 1:
 
624
                default:
 
625
                        return net_usershare_add_usage(c, argc, argv);
 
626
                case 2:
 
627
                        sharename = strdup_lower(argv[0]);
 
628
                        us_path = argv[1];
 
629
                        break;
 
630
                case 3:
 
631
                        sharename = strdup_lower(argv[0]);
 
632
                        us_path = argv[1];
 
633
                        us_comment = argv[2];
 
634
                        break;
 
635
                case 4:
 
636
                        sharename = strdup_lower(argv[0]);
 
637
                        us_path = argv[1];
 
638
                        us_comment = argv[2];
 
639
                        arg_acl = argv[3];
 
640
                        break;
 
641
                case 5:
 
642
                        sharename = strdup_lower(argv[0]);
 
643
                        us_path = argv[1];
 
644
                        us_comment = argv[2];
 
645
                        arg_acl = argv[3];
 
646
                        if (strlen(arg_acl) == 0) {
 
647
                                arg_acl = "S-1-1-0:R";
 
648
                        }
 
649
                        if (!strnequal(argv[4], "guest_ok=", 9)) {
 
650
                                TALLOC_FREE(ctx);
 
651
                                return net_usershare_add_usage(c, argc, argv);
 
652
                        }
 
653
                        switch (argv[4][9]) {
 
654
                                case 'y':
 
655
                                case 'Y':
 
656
                                        guest_ok = true;
 
657
                                        break;
 
658
                                case 'n':
 
659
                                case 'N':
 
660
                                        guest_ok = false;
 
661
                                        break;
 
662
                                default:
 
663
                                        TALLOC_FREE(ctx);
 
664
                                        return net_usershare_add_usage(c, argc, argv);
 
665
                        }
 
666
                        break;
 
667
        }
 
668
 
 
669
        /* Ensure we're under the "usershare max shares" number. Advisory only. */
 
670
        num_usershares = count_num_usershares();
 
671
        if (num_usershares >= lp_usershare_max_shares()) {
 
672
                d_fprintf(stderr, "net usershare add: maximum number of allowed usershares (%d) reached\n",
 
673
                        lp_usershare_max_shares() );
 
674
                TALLOC_FREE(ctx);
 
675
                SAFE_FREE(sharename);
 
676
                return -1;
 
677
        }
 
678
 
 
679
        if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
 
680
                d_fprintf(stderr, "net usershare add: share name %s contains "
 
681
                        "invalid characters (any of %s)\n",
 
682
                        sharename, INVALID_SHARENAME_CHARS);
 
683
                TALLOC_FREE(ctx);
 
684
                SAFE_FREE(sharename);
 
685
                return -1;
 
686
        }
 
687
 
 
688
        /* Disallow shares the same as users. */
 
689
        if (getpwnam(sharename)) {
 
690
                d_fprintf(stderr, "net usershare add: share name %s is already a valid system user name\n",
 
691
                        sharename );
 
692
                TALLOC_FREE(ctx);
 
693
                SAFE_FREE(sharename);
 
694
                return -1;
 
695
        }
 
696
 
 
697
        /* Construct the full path for the usershare file. */
 
698
        full_path = get_basepath(ctx);
 
699
        if (!full_path) {
 
700
                TALLOC_FREE(ctx);
 
701
                SAFE_FREE(sharename);
 
702
                return -1;
 
703
        }
 
704
        full_path_tmp = talloc_asprintf(ctx,
 
705
                        "%s/:tmpXXXXXX",
 
706
                        full_path);
 
707
        if (!full_path_tmp) {
 
708
                TALLOC_FREE(ctx);
 
709
                SAFE_FREE(sharename);
 
710
                return -1;
 
711
        }
 
712
 
 
713
        full_path = talloc_asprintf_append(full_path,
 
714
                                        "/%s",
 
715
                                        sharename);
 
716
        if (!full_path) {
 
717
                TALLOC_FREE(ctx);
 
718
                SAFE_FREE(sharename);
 
719
                return -1;
 
720
        }
 
721
 
 
722
        /* The path *must* be absolute. */
 
723
        if (us_path[0] != '/') {
 
724
                d_fprintf(stderr,"net usershare add: path %s is not an absolute path.\n",
 
725
                        us_path);
 
726
                TALLOC_FREE(ctx);
 
727
                SAFE_FREE(sharename);
 
728
                return -1;
 
729
        }
 
730
 
 
731
        /* Check the directory to be shared exists. */
 
732
        if (sys_stat(us_path, &sbuf) != 0) {
 
733
                d_fprintf(stderr, "net usershare add: cannot stat path %s to ensure "
 
734
                        "this is a directory. Error was %s\n",
 
735
                        us_path, strerror(errno) );
 
736
                TALLOC_FREE(ctx);
 
737
                SAFE_FREE(sharename);
 
738
                return -1;
 
739
        }
 
740
 
 
741
        if (!S_ISDIR(sbuf.st_mode)) {
 
742
                d_fprintf(stderr, "net usershare add: path %s is not a directory.\n",
 
743
                        us_path );
 
744
                TALLOC_FREE(ctx);
 
745
                SAFE_FREE(sharename);
 
746
                return -1;
 
747
        }
 
748
 
 
749
        /* If we're not root, check if we're restricted to sharing out directories
 
750
           that we own only. */
 
751
 
 
752
        if ((myeuid != 0) && lp_usershare_owner_only() && (myeuid != sbuf.st_uid)) {
 
753
                d_fprintf(stderr, "net usershare add: cannot share path %s as "
 
754
                        "we are restricted to only sharing directories we own.\n"
 
755
                        "\tAsk the administrator to add the line \"usershare owner only = false\" \n"
 
756
                        "\tto the [global] section of the smb.conf to allow this.\n",
 
757
                        us_path );
 
758
                TALLOC_FREE(ctx);
 
759
                SAFE_FREE(sharename);
 
760
                return -1;
 
761
        }
 
762
 
 
763
        /* No validation needed on comment. Now go through and validate the
 
764
           acl string. Convert names to SID's as needed. Then run it through
 
765
           parse_usershare_acl to ensure it's valid. */
 
766
 
 
767
        /* Start off the string we'll append to. */
 
768
        us_acl = talloc_strdup(ctx, "");
 
769
        if (!us_acl) {
 
770
                TALLOC_FREE(ctx);
 
771
                return -1;
 
772
        }
 
773
 
 
774
        pacl = arg_acl;
 
775
        num_aces = 1;
 
776
 
 
777
        /* Add the number of ',' characters to get the number of aces. */
 
778
        num_aces += count_chars(pacl,',');
 
779
 
 
780
        for (i = 0; i < num_aces; i++) {
 
781
                DOM_SID sid;
 
782
                const char *pcolon = strchr_m(pacl, ':');
 
783
                const char *name;
 
784
 
 
785
                if (pcolon == NULL) {
 
786
                        d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n",
 
787
                                pacl );
 
788
                        TALLOC_FREE(ctx);
 
789
                        SAFE_FREE(sharename);
 
790
                        return -1;
 
791
                }
 
792
 
 
793
                switch(pcolon[1]) {
 
794
                        case 'f':
 
795
                        case 'F':
 
796
                        case 'd':
 
797
                        case 'r':
 
798
                        case 'R':
 
799
                                break;
 
800
                        default:
 
801
                                d_fprintf(stderr, "net usershare add: malformed acl %s "
 
802
                                        "(access control must be 'r', 'f', or 'd')\n",
 
803
                                        pacl );
 
804
                                TALLOC_FREE(ctx);
 
805
                                SAFE_FREE(sharename);
 
806
                                return -1;
 
807
                }
 
808
 
 
809
                if (pcolon[2] != ',' && pcolon[2] != '\0') {
 
810
                        d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n",
 
811
                                pacl );
 
812
                        TALLOC_FREE(ctx);
 
813
                        SAFE_FREE(sharename);
 
814
                        return -1;
 
815
                }
 
816
 
 
817
                /* Get the name */
 
818
                if ((name = talloc_strndup(ctx, pacl, pcolon - pacl)) == NULL) {
 
819
                        d_fprintf(stderr, "talloc_strndup failed\n");
 
820
                        TALLOC_FREE(ctx);
 
821
                        SAFE_FREE(sharename);
 
822
                        return -1;
 
823
                }
 
824
                if (!string_to_sid(&sid, name)) {
 
825
                        /* Convert to a SID */
 
826
                        NTSTATUS ntstatus = net_lookup_sid_from_name(c, ctx, name, &sid);
 
827
                        if (!NT_STATUS_IS_OK(ntstatus)) {
 
828
                                d_fprintf(stderr, "net usershare add: cannot convert name \"%s\" to a SID. %s.",
 
829
                                        name, get_friendly_nt_error_msg(ntstatus) );
 
830
                                if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_CONNECTION_REFUSED)) {
 
831
                                        d_fprintf(stderr,  " Maybe smbd is not running.\n");
 
832
                                } else {
 
833
                                        d_fprintf(stderr, "\n");
 
834
                                }
 
835
                                TALLOC_FREE(ctx);
 
836
                                SAFE_FREE(sharename);
 
837
                                return -1;
 
838
                        }
 
839
                }
 
840
                us_acl = talloc_asprintf_append(
 
841
                        us_acl, "%s:%c,", sid_string_tos(&sid), pcolon[1]);
 
842
 
 
843
                /* Move to the next ACL entry. */
 
844
                if (pcolon[2] == ',') {
 
845
                        pacl = &pcolon[3];
 
846
                }
 
847
        }
 
848
 
 
849
        /* Remove the last ',' */
 
850
        us_acl[strlen(us_acl)-1] = '\0';
 
851
 
 
852
        if (guest_ok && !lp_usershare_allow_guests()) {
 
853
                d_fprintf(stderr, "net usershare add: guest_ok=y requested "
 
854
                        "but the \"usershare allow guests\" parameter is not enabled "
 
855
                        "by this server.\n");
 
856
                TALLOC_FREE(ctx);
 
857
                SAFE_FREE(sharename);
 
858
                return -1;
 
859
        }
 
860
 
 
861
        /* Create a temporary filename for this share. */
 
862
        tmpfd = smb_mkstemp(full_path_tmp);
 
863
 
 
864
        if (tmpfd == -1) {
 
865
                d_fprintf(stderr, "net usershare add: cannot create tmp file %s\n",
 
866
                                full_path_tmp );
 
867
                TALLOC_FREE(ctx);
 
868
                SAFE_FREE(sharename);
 
869
                return -1;
 
870
        }
 
871
 
 
872
        /* Ensure we opened the file we thought we did. */
 
873
        if (sys_lstat(full_path_tmp, &lsbuf) != 0) {
 
874
                d_fprintf(stderr, "net usershare add: cannot lstat tmp file %s\n",
 
875
                                full_path_tmp );
 
876
                TALLOC_FREE(ctx);
 
877
                SAFE_FREE(sharename);
 
878
                return -1;
 
879
        }
 
880
 
 
881
        /* Check this is the same as the file we opened. */
 
882
        if (sys_fstat(tmpfd, &sbuf) != 0) {
 
883
                d_fprintf(stderr, "net usershare add: cannot fstat tmp file %s\n",
 
884
                                full_path_tmp );
 
885
                TALLOC_FREE(ctx);
 
886
                SAFE_FREE(sharename);
 
887
                return -1;
 
888
        }
 
889
 
 
890
        if (!S_ISREG(sbuf.st_mode) || sbuf.st_dev != lsbuf.st_dev || sbuf.st_ino != lsbuf.st_ino) {
 
891
                d_fprintf(stderr, "net usershare add: tmp file %s is not a regular file ?\n",
 
892
                                full_path_tmp );
 
893
                TALLOC_FREE(ctx);
 
894
                SAFE_FREE(sharename);
 
895
                return -1;
 
896
        }
 
897
 
 
898
        if (fchmod(tmpfd, 0644) == -1) {
 
899
                d_fprintf(stderr, "net usershare add: failed to fchmod tmp file %s to 0644n",
 
900
                                full_path_tmp );
 
901
                TALLOC_FREE(ctx);
 
902
                SAFE_FREE(sharename);
 
903
                return -1;
 
904
        }
 
905
 
 
906
        /* Create the in-memory image of the file. */
 
907
        file_img = talloc_strdup(ctx, "#VERSION 2\npath=");
 
908
        file_img = talloc_asprintf_append(file_img, "%s\ncomment=%s\nusershare_acl=%s\nguest_ok=%c\n",
 
909
                        us_path, us_comment, us_acl, guest_ok ? 'y' : 'n');
 
910
 
 
911
        to_write = strlen(file_img);
 
912
 
 
913
        if (write(tmpfd, file_img, to_write) != to_write) {
 
914
                d_fprintf(stderr, "net usershare add: failed to write %u bytes to file %s. Error was %s\n",
 
915
                        (unsigned int)to_write, full_path_tmp, strerror(errno));
 
916
                unlink(full_path_tmp);
 
917
                TALLOC_FREE(ctx);
 
918
                SAFE_FREE(sharename);
 
919
                return -1;
 
920
        }
 
921
 
 
922
        /* Attempt to replace any existing share by this name. */
 
923
        if (rename(full_path_tmp, full_path) != 0) {
 
924
                unlink(full_path_tmp);
 
925
                d_fprintf(stderr, "net usershare add: failed to add share %s. Error was %s\n",
 
926
                        sharename, strerror(errno));
 
927
                TALLOC_FREE(ctx);
 
928
                close(tmpfd);
 
929
                SAFE_FREE(sharename);
 
930
                return -1;
 
931
        }
 
932
 
 
933
        close(tmpfd);
 
934
 
 
935
        if (c->opt_long_list_entries) {
 
936
                const char *my_argv[2];
 
937
                my_argv[0] = sharename;
 
938
                my_argv[1] = NULL;
 
939
                net_usershare_info(c, 1, my_argv);
 
940
        }
 
941
 
 
942
        SAFE_FREE(sharename);
 
943
        TALLOC_FREE(ctx);
 
944
        return 0;
 
945
}
 
946
 
 
947
#if 0
 
948
/***************************************************************************
 
949
 List function.
 
950
***************************************************************************/
 
951
 
 
952
static int list_fn(struct file_list *fl, void *priv)
 
953
{
 
954
        d_printf("%s\n", fl->pathname);
 
955
        return 0;
 
956
}
 
957
#endif
 
958
 
 
959
/***************************************************************************
 
960
 List userlevel shares.
 
961
***************************************************************************/
 
962
 
 
963
static int net_usershare_list(struct net_context *c, int argc,
 
964
                              const char **argv)
 
965
{
 
966
        fstring wcard;
 
967
        bool only_ours = true;
 
968
        int ret = -1;
 
969
        struct us_priv_info pi;
 
970
        TALLOC_CTX *ctx;
 
971
 
 
972
        fstrcpy(wcard, "*");
 
973
 
 
974
        if (c->display_usage)
 
975
                return net_usershare_list_usage(c, argc, argv);
 
976
 
 
977
        if (c->opt_long_list_entries) {
 
978
                only_ours = false;
 
979
        }
 
980
 
 
981
        switch (argc) {
 
982
                case 0:
 
983
                        break;
 
984
                case 1:
 
985
                        fstrcpy(wcard, argv[0]);
 
986
                        break;
 
987
                default:
 
988
                        return net_usershare_list_usage(c, argc, argv);
 
989
        }
 
990
 
 
991
        strlower_m(wcard);
 
992
 
 
993
        ctx = talloc_init("share_list");
 
994
        ret = get_share_list(ctx, wcard, only_ours);
 
995
        if (ret) {
 
996
                return ret;
 
997
        }
 
998
 
 
999
        pi.ctx = ctx;
 
1000
        pi.op = US_LIST_OP;
 
1001
        pi.c = c;
 
1002
 
 
1003
        ret = process_share_list(info_fn, &pi);
 
1004
        talloc_destroy(ctx);
 
1005
        return ret;
 
1006
}
 
1007
 
 
1008
/***************************************************************************
 
1009
 Entry-point for all the USERSHARE functions.
 
1010
***************************************************************************/
 
1011
 
 
1012
int net_usershare(struct net_context *c, int argc, const char **argv)
 
1013
{
 
1014
        SMB_STRUCT_DIR *dp;
 
1015
 
 
1016
        struct functable func[] = {
 
1017
                {
 
1018
                        "add",
 
1019
                        net_usershare_add,
 
1020
                        NET_TRANSPORT_LOCAL,
 
1021
                        "Add/modify user defined share",
 
1022
                        "net usershare add\n"
 
1023
                        "    Add/modify user defined share"
 
1024
                },
 
1025
                {
 
1026
                        "delete",
 
1027
                        net_usershare_delete,
 
1028
                        NET_TRANSPORT_LOCAL,
 
1029
                        "Delete user defined share",
 
1030
                        "net usershare delete\n"
 
1031
                        "    Delete user defined share"
 
1032
                },
 
1033
                {
 
1034
                        "info",
 
1035
                        net_usershare_info,
 
1036
                        NET_TRANSPORT_LOCAL,
 
1037
                        "Display information about a user defined share",
 
1038
                        "net usershare info\n"
 
1039
                        "    Display information about a user defined share"
 
1040
                },
 
1041
                {
 
1042
                        "list",
 
1043
                        net_usershare_list,
 
1044
                        NET_TRANSPORT_LOCAL,
 
1045
                        "List user defined shares",
 
1046
                        "net usershare list\n"
 
1047
                        "    List user defined shares"
 
1048
                },
 
1049
                {NULL, NULL, 0, NULL, NULL}
 
1050
        };
 
1051
 
 
1052
        if (lp_usershare_max_shares() == 0) {
 
1053
                d_fprintf(stderr, "net usershare: usershares are currently disabled\n");
 
1054
                return -1;
 
1055
        }
 
1056
 
 
1057
        dp = sys_opendir(lp_usershare_path());
 
1058
        if (!dp) {
 
1059
                int err = errno;
 
1060
                d_fprintf(stderr, "net usershare: cannot open usershare directory %s. Error %s\n",
 
1061
                        lp_usershare_path(), strerror(err) );
 
1062
                if (err == EACCES) {
 
1063
                        d_fprintf(stderr, "You do not have permission to create a usershare. Ask your "
 
1064
                                "administrator to grant you permissions to create a share.\n");
 
1065
                } else if (err == ENOENT) {
 
1066
                        d_fprintf(stderr, "Please ask your system administrator to "
 
1067
                                "enable user sharing.\n");
 
1068
                }
 
1069
                return -1;
 
1070
        }
 
1071
        sys_closedir(dp);
 
1072
 
 
1073
        return net_run_function(c, argc, argv, "net usershare", func);
 
1074
}