Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netsmb/smb_conn.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2000-2001 Boris Popov
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
/*
30
* Connection engine.
31
*/
32
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/kernel.h>
36
#include <sys/malloc.h>
37
#include <sys/priv.h>
38
#include <sys/proc.h>
39
#include <sys/lock.h>
40
#include <sys/sysctl.h>
41
#include <sys/socketvar.h>
42
43
#include <sys/iconv.h>
44
45
#include <netsmb/smb.h>
46
#include <netsmb/smb_subr.h>
47
#include <netsmb/smb_conn.h>
48
#include <netsmb/smb_tran.h>
49
#include <netsmb/smb_trantcp.h>
50
51
static struct smb_connobj smb_vclist;
52
static int smb_vcnext = 1; /* next unique id for VC */
53
54
SYSCTL_NODE(_net, OID_AUTO, smb, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
55
"SMB protocol");
56
57
static MALLOC_DEFINE(M_SMBCONN, "smb_conn", "SMB connection");
58
59
static void smb_co_init(struct smb_connobj *cp, int level, char *ilockname,
60
char *lockname);
61
static void smb_co_done(struct smb_connobj *cp);
62
static int smb_vc_disconnect(struct smb_vc *vcp);
63
static void smb_vc_free(struct smb_connobj *cp);
64
static void smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred);
65
static smb_co_free_t smb_share_free;
66
static smb_co_gone_t smb_share_gone;
67
68
static int smb_sysctl_treedump(SYSCTL_HANDLER_ARGS);
69
70
SYSCTL_PROC(_net_smb, OID_AUTO, treedump,
71
CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE,
72
NULL, 0, smb_sysctl_treedump, "S,treedump",
73
"Requester tree");
74
75
int
76
smb_sm_init(void)
77
{
78
79
smb_co_init(&smb_vclist, SMBL_SM, "smbsm ilock", "smbsm");
80
sx_xlock(&smb_vclist.co_interlock);
81
smb_co_unlock(&smb_vclist);
82
sx_unlock(&smb_vclist.co_interlock);
83
return 0;
84
}
85
86
int
87
smb_sm_done(void)
88
{
89
90
/* XXX: hold the mutex */
91
if (smb_vclist.co_usecount > 1) {
92
SMBERROR("%d connections still active\n", smb_vclist.co_usecount - 1);
93
return EBUSY;
94
}
95
smb_co_done(&smb_vclist);
96
return 0;
97
}
98
99
static int
100
smb_sm_lockvclist(void)
101
{
102
int error;
103
104
sx_xlock(&smb_vclist.co_interlock);
105
error = smb_co_lock(&smb_vclist);
106
sx_unlock(&smb_vclist.co_interlock);
107
108
return error;
109
}
110
111
static void
112
smb_sm_unlockvclist(void)
113
{
114
115
sx_xlock(&smb_vclist.co_interlock);
116
smb_co_unlock(&smb_vclist);
117
sx_unlock(&smb_vclist.co_interlock);
118
}
119
120
static int
121
smb_sm_lookupint(struct smb_vcspec *vcspec, struct smb_sharespec *shspec,
122
struct smb_cred *scred, struct smb_vc **vcpp)
123
{
124
struct smb_connobj *scp;
125
struct smb_vc *vcp;
126
int exact = 1;
127
int error;
128
129
vcspec->shspec = shspec;
130
error = ENOENT;
131
vcp = NULL;
132
SMBCO_FOREACH(scp, &smb_vclist) {
133
vcp = (struct smb_vc *)scp;
134
error = smb_vc_lock(vcp);
135
if (error)
136
continue;
137
138
if ((vcp->obj.co_flags & SMBV_PRIVATE) ||
139
!CONNADDREQ(vcp->vc_paddr, vcspec->sap) ||
140
strcmp(vcp->vc_username, vcspec->username) != 0)
141
goto err1;
142
if (vcspec->owner != SMBM_ANY_OWNER) {
143
if (vcp->vc_uid != vcspec->owner)
144
goto err1;
145
} else
146
exact = 0;
147
if (vcspec->group != SMBM_ANY_GROUP) {
148
if (vcp->vc_grp != vcspec->group)
149
goto err1;
150
} else
151
exact = 0;
152
if (vcspec->mode & SMBM_EXACT) {
153
if (!exact || (vcspec->mode & SMBM_MASK) !=
154
vcp->vc_mode)
155
goto err1;
156
}
157
if (smb_vc_access(vcp, scred, vcspec->mode) != 0)
158
goto err1;
159
vcspec->ssp = NULL;
160
if (shspec) {
161
error = (int)smb_vc_lookupshare(vcp, shspec, scred,
162
&vcspec->ssp);
163
if (error)
164
goto fail;
165
}
166
error = 0;
167
break;
168
err1:
169
error = 1;
170
fail:
171
smb_vc_unlock(vcp);
172
}
173
if (vcp) {
174
smb_vc_ref(vcp);
175
*vcpp = vcp;
176
}
177
return (error);
178
}
179
180
int
181
smb_sm_lookup(struct smb_vcspec *vcspec, struct smb_sharespec *shspec,
182
struct smb_cred *scred, struct smb_vc **vcpp)
183
{
184
struct smb_vc *vcp;
185
struct smb_share *ssp = NULL;
186
int error;
187
188
*vcpp = vcp = NULL;
189
190
error = smb_sm_lockvclist();
191
if (error)
192
return error;
193
error = smb_sm_lookupint(vcspec, shspec, scred, vcpp);
194
if (error == 0 || (vcspec->flags & SMBV_CREATE) == 0) {
195
smb_sm_unlockvclist();
196
return error;
197
}
198
error = smb_sm_lookupint(vcspec, NULL, scred, &vcp);
199
if (error) {
200
error = smb_vc_create(vcspec, scred, &vcp);
201
if (error)
202
goto out;
203
error = smb_vc_connect(vcp, scred);
204
if (error)
205
goto out;
206
}
207
if (shspec == NULL)
208
goto out;
209
error = smb_share_create(vcp, shspec, scred, &ssp);
210
if (error)
211
goto out;
212
error = smb_smb_treeconnect(ssp, scred);
213
if (error == 0)
214
vcspec->ssp = ssp;
215
else
216
smb_share_put(ssp, scred);
217
out:
218
smb_sm_unlockvclist();
219
if (error == 0)
220
*vcpp = vcp;
221
else if (vcp) {
222
smb_vc_lock(vcp);
223
smb_vc_put(vcp, scred);
224
}
225
return error;
226
}
227
228
/*
229
* Common code for connection object
230
*/
231
static void
232
smb_co_init(struct smb_connobj *cp, int level, char *ilockname, char *lockname)
233
{
234
SLIST_INIT(&cp->co_children);
235
sx_init_flags(&cp->co_interlock, ilockname, SX_RECURSE);
236
cv_init(&cp->co_lock, "smblock");
237
cp->co_lockcnt = 0;
238
cp->co_locker = NULL;
239
cp->co_level = level;
240
cp->co_usecount = 1;
241
sx_xlock(&cp->co_interlock);
242
smb_co_lock(cp);
243
sx_unlock(&cp->co_interlock);
244
}
245
246
static void
247
smb_co_done(struct smb_connobj *cp)
248
{
249
250
sx_destroy(&cp->co_interlock);
251
cv_destroy(&cp->co_lock);
252
cp->co_locker = NULL;
253
cp->co_flags = 0;
254
cp->co_lockcnt = 0;
255
}
256
257
static void
258
smb_co_gone(struct smb_connobj *cp, struct smb_cred *scred)
259
{
260
struct smb_connobj *parent;
261
262
if (cp->co_gone)
263
cp->co_gone(cp, scred);
264
parent = cp->co_parent;
265
if (parent) {
266
sx_xlock(&parent->co_interlock);
267
smb_co_lock(parent);
268
sx_unlock(&parent->co_interlock);
269
SLIST_REMOVE(&parent->co_children, cp, smb_connobj, co_next);
270
smb_co_put(parent, scred);
271
}
272
if (cp->co_free)
273
cp->co_free(cp);
274
}
275
276
void
277
smb_co_ref(struct smb_connobj *cp)
278
{
279
280
sx_xlock(&cp->co_interlock);
281
cp->co_usecount++;
282
sx_unlock(&cp->co_interlock);
283
}
284
285
void
286
smb_co_rele(struct smb_connobj *cp, struct smb_cred *scred)
287
{
288
289
sx_xlock(&cp->co_interlock);
290
smb_co_unlock(cp);
291
if (cp->co_usecount > 1) {
292
cp->co_usecount--;
293
sx_unlock(&cp->co_interlock);
294
return;
295
}
296
if (cp->co_usecount == 0) {
297
SMBERROR("negative use_count for object %d", cp->co_level);
298
sx_unlock(&cp->co_interlock);
299
return;
300
}
301
cp->co_usecount--;
302
cp->co_flags |= SMBO_GONE;
303
sx_unlock(&cp->co_interlock);
304
smb_co_gone(cp, scred);
305
}
306
307
int
308
smb_co_get(struct smb_connobj *cp, struct smb_cred *scred)
309
{
310
int error;
311
312
MPASS(sx_xholder(&cp->co_interlock) == curthread);
313
cp->co_usecount++;
314
error = smb_co_lock(cp);
315
if (error)
316
cp->co_usecount--;
317
return error;
318
}
319
320
void
321
smb_co_put(struct smb_connobj *cp, struct smb_cred *scred)
322
{
323
324
sx_xlock(&cp->co_interlock);
325
if (cp->co_usecount > 1) {
326
cp->co_usecount--;
327
} else if (cp->co_usecount == 1) {
328
cp->co_usecount--;
329
cp->co_flags |= SMBO_GONE;
330
} else {
331
SMBERROR("negative usecount");
332
}
333
smb_co_unlock(cp);
334
sx_unlock(&cp->co_interlock);
335
if ((cp->co_flags & SMBO_GONE) == 0)
336
return;
337
smb_co_gone(cp, scred);
338
}
339
340
int
341
smb_co_lock(struct smb_connobj *cp)
342
{
343
344
MPASS(sx_xholder(&cp->co_interlock) == curthread);
345
for (;;) {
346
if (cp->co_flags & SMBO_GONE)
347
return EINVAL;
348
if (cp->co_locker == NULL) {
349
cp->co_locker = curthread;
350
return 0;
351
}
352
if (cp->co_locker == curthread) {
353
cp->co_lockcnt++;
354
return 0;
355
}
356
cv_wait(&cp->co_lock, &cp->co_interlock);
357
}
358
}
359
360
void
361
smb_co_unlock(struct smb_connobj *cp)
362
{
363
364
MPASS(sx_xholder(&cp->co_interlock) == curthread);
365
MPASS(cp->co_locker == curthread);
366
if (cp->co_lockcnt != 0) {
367
cp->co_lockcnt--;
368
return;
369
}
370
cp->co_locker = NULL;
371
cv_signal(&cp->co_lock);
372
}
373
374
static void
375
smb_co_addchild(struct smb_connobj *parent, struct smb_connobj *child)
376
{
377
378
smb_co_ref(parent);
379
SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
380
child->co_parent = parent;
381
}
382
383
/*
384
* Session implementation
385
*/
386
387
int
388
smb_vc_create(struct smb_vcspec *vcspec,
389
struct smb_cred *scred, struct smb_vc **vcpp)
390
{
391
struct smb_vc *vcp;
392
struct ucred *cred = scred->scr_cred;
393
uid_t uid = vcspec->owner;
394
gid_t gid = vcspec->group;
395
uid_t realuid = cred->cr_uid;
396
char *domain = vcspec->domain;
397
int error, isroot;
398
399
isroot = smb_suser(cred) == 0;
400
/*
401
* Only superuser can create VCs with different uid and gid
402
*/
403
if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot)
404
return EPERM;
405
if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot)
406
return EPERM;
407
408
vcp = smb_zmalloc(sizeof(*vcp), M_SMBCONN, M_WAITOK);
409
smb_co_init(VCTOCP(vcp), SMBL_VC, "smb_vc ilock", "smb_vc");
410
vcp->obj.co_free = smb_vc_free;
411
vcp->obj.co_gone = smb_vc_gone;
412
vcp->vc_number = smb_vcnext++;
413
vcp->vc_timo = SMB_DEFRQTIMO;
414
vcp->vc_smbuid = SMB_UID_UNKNOWN;
415
vcp->vc_mode = vcspec->rights & SMBM_MASK;
416
vcp->obj.co_flags = vcspec->flags & (SMBV_PRIVATE | SMBV_SINGLESHARE);
417
vcp->vc_tdesc = &smb_tran_nbtcp_desc;
418
vcp->vc_seqno = 0;
419
vcp->vc_mackey = NULL;
420
vcp->vc_mackeylen = 0;
421
422
if (uid == SMBM_ANY_OWNER)
423
uid = realuid;
424
if (gid == SMBM_ANY_GROUP)
425
gid = cred->cr_gid;
426
vcp->vc_uid = uid;
427
vcp->vc_grp = gid;
428
429
smb_sl_init(&vcp->vc_stlock, "vcstlock");
430
error = ENOMEM;
431
432
vcp->vc_paddr = sodupsockaddr(vcspec->sap, M_WAITOK);
433
if (vcp->vc_paddr == NULL)
434
goto fail;
435
vcp->vc_laddr = sodupsockaddr(vcspec->lap, M_WAITOK);
436
if (vcp->vc_laddr == NULL)
437
goto fail;
438
vcp->vc_pass = smb_strdup(vcspec->pass);
439
if (vcp->vc_pass == NULL)
440
goto fail;
441
vcp->vc_domain = smb_strdup((domain && domain[0]) ? domain :
442
"NODOMAIN");
443
if (vcp->vc_domain == NULL)
444
goto fail;
445
vcp->vc_srvname = smb_strdup(vcspec->srvname);
446
if (vcp->vc_srvname == NULL)
447
goto fail;
448
vcp->vc_username = smb_strdup(vcspec->username);
449
if (vcp->vc_username == NULL)
450
goto fail;
451
error = (int)iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower);
452
if (error)
453
goto fail;
454
error = (int)iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper);
455
if (error)
456
goto fail;
457
if (vcspec->servercs[0]) {
458
error = (int)iconv_open(vcspec->servercs, vcspec->localcs,
459
&vcp->vc_cp_toserver);
460
if (error)
461
goto fail;
462
error = (int)iconv_open(vcspec->localcs, vcspec->servercs,
463
&vcp->vc_cp_tolocal);
464
if (error)
465
goto fail;
466
vcp->vc_toserver = vcp->vc_cp_toserver;
467
vcp->vc_tolocal = vcp->vc_cp_tolocal;
468
iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, SMB_UNICODE_NAME);
469
iconv_add(ENCODING_UNICODE, SMB_UNICODE_NAME, ENCODING_UNICODE);
470
error = (int)iconv_open(SMB_UNICODE_NAME, vcspec->localcs,
471
&vcp->vc_ucs_toserver);
472
if (!error) {
473
error = (int)iconv_open(vcspec->localcs, SMB_UNICODE_NAME,
474
&vcp->vc_ucs_tolocal);
475
}
476
if (error) {
477
if (vcp->vc_ucs_toserver)
478
iconv_close(vcp->vc_ucs_toserver);
479
vcp->vc_ucs_toserver = NULL;
480
vcp->vc_ucs_tolocal = NULL;
481
}
482
}
483
error = (int)smb_iod_create(vcp);
484
if (error)
485
goto fail;
486
*vcpp = vcp;
487
smb_co_addchild(&smb_vclist, VCTOCP(vcp));
488
return (0);
489
490
fail:
491
smb_vc_put(vcp, scred);
492
return (error);
493
}
494
495
static void
496
smb_vc_free(struct smb_connobj *cp)
497
{
498
struct smb_vc *vcp = CPTOVC(cp);
499
500
if (vcp->vc_iod)
501
smb_iod_destroy(vcp->vc_iod);
502
SMB_STRFREE(vcp->vc_username);
503
SMB_STRFREE(vcp->vc_srvname);
504
SMB_STRFREE(vcp->vc_pass);
505
SMB_STRFREE(vcp->vc_domain);
506
if (vcp->vc_mackey)
507
free(vcp->vc_mackey, M_SMBTEMP);
508
if (vcp->vc_paddr)
509
free(vcp->vc_paddr, M_SONAME);
510
if (vcp->vc_laddr)
511
free(vcp->vc_laddr, M_SONAME);
512
if (vcp->vc_tolower)
513
iconv_close(vcp->vc_tolower);
514
if (vcp->vc_toupper)
515
iconv_close(vcp->vc_toupper);
516
if (vcp->vc_tolocal)
517
vcp->vc_tolocal = NULL;
518
if (vcp->vc_toserver)
519
vcp->vc_toserver = NULL;
520
if (vcp->vc_cp_tolocal)
521
iconv_close(vcp->vc_cp_tolocal);
522
if (vcp->vc_cp_toserver)
523
iconv_close(vcp->vc_cp_toserver);
524
if (vcp->vc_ucs_tolocal)
525
iconv_close(vcp->vc_ucs_tolocal);
526
if (vcp->vc_ucs_toserver)
527
iconv_close(vcp->vc_ucs_toserver);
528
smb_co_done(VCTOCP(vcp));
529
smb_sl_destroy(&vcp->vc_stlock);
530
free(vcp, M_SMBCONN);
531
}
532
533
/*
534
* Called when use count of VC dropped to zero.
535
*/
536
static void
537
smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred)
538
{
539
struct smb_vc *vcp = CPTOVC(cp);
540
541
smb_vc_disconnect(vcp);
542
}
543
544
void
545
smb_vc_ref(struct smb_vc *vcp)
546
{
547
smb_co_ref(VCTOCP(vcp));
548
}
549
550
void
551
smb_vc_rele(struct smb_vc *vcp, struct smb_cred *scred)
552
{
553
smb_co_rele(VCTOCP(vcp), scred);
554
}
555
556
int
557
smb_vc_get(struct smb_vc *vcp, struct smb_cred *scred)
558
{
559
struct smb_connobj *cp;
560
int error;
561
562
cp = VCTOCP(vcp);
563
sx_xlock(&cp->co_interlock);
564
error = smb_co_get(cp, scred);
565
sx_unlock(&cp->co_interlock);
566
return error;
567
}
568
569
void
570
smb_vc_put(struct smb_vc *vcp, struct smb_cred *scred)
571
{
572
smb_co_put(VCTOCP(vcp), scred);
573
}
574
575
int
576
smb_vc_lock(struct smb_vc *vcp)
577
{
578
struct smb_connobj *cp;
579
int error;
580
581
cp = VCTOCP(vcp);
582
sx_xlock(&cp->co_interlock);
583
error = smb_co_lock(cp);
584
sx_unlock(&cp->co_interlock);
585
return error;
586
}
587
588
void
589
smb_vc_unlock(struct smb_vc *vcp)
590
{
591
592
struct smb_connobj *cp;
593
594
cp = VCTOCP(vcp);
595
sx_xlock(&cp->co_interlock);
596
smb_co_unlock(cp);
597
sx_unlock(&cp->co_interlock);
598
}
599
600
int
601
smb_vc_access(struct smb_vc *vcp, struct smb_cred *scred, mode_t mode)
602
{
603
struct ucred *cred = scred->scr_cred;
604
605
if (smb_suser(cred) == 0 || cred->cr_uid == vcp->vc_uid)
606
return 0;
607
mode >>= 3;
608
if (!groupmember(vcp->vc_grp, cred))
609
mode >>= 3;
610
return (vcp->vc_mode & mode) == mode ? 0 : EACCES;
611
}
612
613
static int
614
smb_vc_cmpshare(struct smb_share *ssp, struct smb_sharespec *dp)
615
{
616
int exact = 1;
617
618
if (strcmp(ssp->ss_name, dp->name) != 0)
619
return 1;
620
if (dp->owner != SMBM_ANY_OWNER) {
621
if (ssp->ss_uid != dp->owner)
622
return 1;
623
} else
624
exact = 0;
625
if (dp->group != SMBM_ANY_GROUP) {
626
if (ssp->ss_grp != dp->group)
627
return 1;
628
} else
629
exact = 0;
630
631
if (dp->mode & SMBM_EXACT) {
632
if (!exact)
633
return 1;
634
return (dp->mode & SMBM_MASK) == ssp->ss_mode ? 0 : 1;
635
}
636
if (smb_share_access(ssp, dp->scred, dp->mode) != 0)
637
return 1;
638
return 0;
639
}
640
641
/*
642
* Lookup share in the given VC. Share referenced and locked on return.
643
* VC expected to be locked on entry and will be left locked on exit.
644
*/
645
int
646
smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *dp,
647
struct smb_cred *scred, struct smb_share **sspp)
648
{
649
struct smb_connobj *scp = NULL;
650
struct smb_share *ssp = NULL;
651
int error;
652
653
*sspp = NULL;
654
dp->scred = scred;
655
SMBCO_FOREACH(scp, VCTOCP(vcp)) {
656
ssp = (struct smb_share *)scp;
657
error = smb_share_lock(ssp);
658
if (error)
659
continue;
660
if (smb_vc_cmpshare(ssp, dp) == 0)
661
break;
662
smb_share_unlock(ssp);
663
}
664
if (ssp) {
665
smb_share_ref(ssp);
666
*sspp = ssp;
667
error = 0;
668
} else
669
error = ENOENT;
670
return error;
671
}
672
673
int
674
smb_vc_connect(struct smb_vc *vcp, struct smb_cred *scred)
675
{
676
677
return smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
678
}
679
680
/*
681
* Destroy VC to server, invalidate shares linked with it.
682
* Transport should be locked on entry.
683
*/
684
int
685
smb_vc_disconnect(struct smb_vc *vcp)
686
{
687
688
if (vcp->vc_iod != NULL)
689
smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT |
690
SMBIOD_EV_SYNC, NULL);
691
return 0;
692
}
693
694
static char smb_emptypass[] = "";
695
696
const char *
697
smb_vc_getpass(struct smb_vc *vcp)
698
{
699
if (vcp->vc_pass)
700
return vcp->vc_pass;
701
return smb_emptypass;
702
}
703
704
static int
705
smb_vc_getinfo(struct smb_vc *vcp, struct smb_vc_info *vip)
706
{
707
bzero(vip, sizeof(struct smb_vc_info));
708
vip->itype = SMB_INFO_VC;
709
vip->usecount = vcp->obj.co_usecount;
710
vip->uid = vcp->vc_uid;
711
vip->gid = vcp->vc_grp;
712
vip->mode = vcp->vc_mode;
713
vip->flags = vcp->obj.co_flags;
714
vip->sopt = vcp->vc_sopt;
715
vip->iodstate = vcp->vc_iod->iod_state;
716
bzero(&vip->sopt.sv_skey, sizeof(vip->sopt.sv_skey));
717
snprintf(vip->srvname, sizeof(vip->srvname), "%s", vcp->vc_srvname);
718
snprintf(vip->vcname, sizeof(vip->vcname), "%s", vcp->vc_username);
719
return 0;
720
}
721
722
u_short
723
smb_vc_nextmid(struct smb_vc *vcp)
724
{
725
u_short r;
726
727
sx_xlock(&vcp->obj.co_interlock);
728
r = vcp->vc_mid++;
729
sx_unlock(&vcp->obj.co_interlock);
730
return r;
731
}
732
733
/*
734
* Share implementation
735
*/
736
/*
737
* Allocate share structure and attach it to the given VC
738
* Connection expected to be locked on entry. Share will be returned
739
* in locked state.
740
*/
741
int
742
smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
743
struct smb_cred *scred, struct smb_share **sspp)
744
{
745
struct smb_share *ssp;
746
struct ucred *cred = scred->scr_cred;
747
uid_t realuid = cred->cr_uid;
748
uid_t uid = shspec->owner;
749
gid_t gid = shspec->group;
750
int error, isroot;
751
752
isroot = smb_suser(cred) == 0;
753
/*
754
* Only superuser can create shares with different uid and gid
755
*/
756
if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot)
757
return EPERM;
758
if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot)
759
return EPERM;
760
error = smb_vc_lookupshare(vcp, shspec, scred, &ssp);
761
if (!error) {
762
smb_share_put(ssp, scred);
763
return EEXIST;
764
}
765
if (uid == SMBM_ANY_OWNER)
766
uid = realuid;
767
if (gid == SMBM_ANY_GROUP)
768
gid = cred->cr_gid;
769
ssp = smb_zmalloc(sizeof(*ssp), M_SMBCONN, M_WAITOK);
770
smb_co_init(SSTOCP(ssp), SMBL_SHARE, "smbss ilock", "smbss");
771
ssp->obj.co_free = smb_share_free;
772
ssp->obj.co_gone = smb_share_gone;
773
smb_sl_init(&ssp->ss_stlock, "ssstlock");
774
ssp->ss_name = smb_strdup(shspec->name);
775
if (shspec->pass && shspec->pass[0])
776
ssp->ss_pass = smb_strdup(shspec->pass);
777
ssp->ss_type = shspec->stype;
778
ssp->ss_tid = SMB_TID_UNKNOWN;
779
ssp->ss_uid = uid;
780
ssp->ss_grp = gid;
781
ssp->ss_mode = shspec->rights & SMBM_MASK;
782
smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
783
*sspp = ssp;
784
return 0;
785
}
786
787
static void
788
smb_share_free(struct smb_connobj *cp)
789
{
790
struct smb_share *ssp = CPTOSS(cp);
791
792
SMB_STRFREE(ssp->ss_name);
793
SMB_STRFREE(ssp->ss_pass);
794
smb_sl_destroy(&ssp->ss_stlock);
795
smb_co_done(SSTOCP(ssp));
796
free(ssp, M_SMBCONN);
797
}
798
799
static void
800
smb_share_gone(struct smb_connobj *cp, struct smb_cred *scred)
801
{
802
struct smb_share *ssp = CPTOSS(cp);
803
804
smb_smb_treedisconnect(ssp, scred);
805
}
806
807
void
808
smb_share_ref(struct smb_share *ssp)
809
{
810
smb_co_ref(SSTOCP(ssp));
811
}
812
813
void
814
smb_share_rele(struct smb_share *ssp, struct smb_cred *scred)
815
{
816
smb_co_rele(SSTOCP(ssp), scred);
817
}
818
819
int
820
smb_share_get(struct smb_share *ssp, struct smb_cred *scred)
821
{
822
struct smb_connobj *cp = SSTOCP(ssp);
823
int error;
824
825
sx_xlock(&cp->co_interlock);
826
error = smb_co_get(cp, scred);
827
sx_unlock(&cp->co_interlock);
828
return error;
829
}
830
831
void
832
smb_share_put(struct smb_share *ssp, struct smb_cred *scred)
833
{
834
835
smb_co_put(SSTOCP(ssp), scred);
836
}
837
838
int
839
smb_share_lock(struct smb_share *ssp)
840
{
841
struct smb_connobj *cp;
842
int error;
843
844
cp = SSTOCP(ssp);
845
sx_xlock(&cp->co_interlock);
846
error = smb_co_lock(cp);
847
sx_unlock(&cp->co_interlock);
848
return error;
849
}
850
851
void
852
smb_share_unlock(struct smb_share *ssp)
853
{
854
struct smb_connobj *cp;
855
856
cp = SSTOCP(ssp);
857
sx_xlock(&cp->co_interlock);
858
smb_co_unlock(cp);
859
sx_unlock(&cp->co_interlock);
860
}
861
862
int
863
smb_share_access(struct smb_share *ssp, struct smb_cred *scred, mode_t mode)
864
{
865
struct ucred *cred = scred->scr_cred;
866
867
if (smb_suser(cred) == 0 || cred->cr_uid == ssp->ss_uid)
868
return 0;
869
mode >>= 3;
870
if (!groupmember(ssp->ss_grp, cred))
871
mode >>= 3;
872
return (ssp->ss_mode & mode) == mode ? 0 : EACCES;
873
}
874
875
void
876
smb_share_invalidate(struct smb_share *ssp)
877
{
878
ssp->ss_tid = SMB_TID_UNKNOWN;
879
}
880
881
int
882
smb_share_valid(struct smb_share *ssp)
883
{
884
return ssp->ss_tid != SMB_TID_UNKNOWN &&
885
ssp->ss_vcgenid == SSTOVC(ssp)->vc_genid;
886
}
887
888
const char*
889
smb_share_getpass(struct smb_share *ssp)
890
{
891
struct smb_vc *vcp;
892
893
if (ssp->ss_pass)
894
return ssp->ss_pass;
895
vcp = SSTOVC(ssp);
896
if (vcp->vc_pass)
897
return vcp->vc_pass;
898
return smb_emptypass;
899
}
900
901
static int
902
smb_share_getinfo(struct smb_share *ssp, struct smb_share_info *sip)
903
{
904
bzero(sip, sizeof(struct smb_share_info));
905
sip->itype = SMB_INFO_SHARE;
906
sip->usecount = ssp->obj.co_usecount;
907
sip->tid = ssp->ss_tid;
908
sip->type= ssp->ss_type;
909
sip->uid = ssp->ss_uid;
910
sip->gid = ssp->ss_grp;
911
sip->mode= ssp->ss_mode;
912
sip->flags = ssp->obj.co_flags;
913
snprintf(sip->sname, sizeof(sip->sname), "%s", ssp->ss_name);
914
return 0;
915
}
916
917
/*
918
* Dump an entire tree into sysctl call
919
*/
920
static int
921
smb_sysctl_treedump(SYSCTL_HANDLER_ARGS)
922
{
923
struct smb_connobj *scp1, *scp2;
924
struct smb_vc *vcp;
925
struct smb_share *ssp;
926
struct smb_vc_info vci;
927
struct smb_share_info ssi;
928
int error, itype;
929
930
error = sysctl_wire_old_buffer(req, 0);
931
if (error)
932
return (error);
933
error = smb_sm_lockvclist();
934
if (error)
935
return error;
936
SMBCO_FOREACH(scp1, &smb_vclist) {
937
vcp = (struct smb_vc *)scp1;
938
error = smb_vc_lock(vcp);
939
if (error)
940
continue;
941
smb_vc_getinfo(vcp, &vci);
942
error = SYSCTL_OUT(req, &vci, sizeof(struct smb_vc_info));
943
if (error) {
944
smb_vc_unlock(vcp);
945
break;
946
}
947
SMBCO_FOREACH(scp2, VCTOCP(vcp)) {
948
ssp = (struct smb_share *)scp2;
949
error = smb_share_lock(ssp);
950
if (error) {
951
error = 0;
952
continue;
953
}
954
smb_share_getinfo(ssp, &ssi);
955
smb_share_unlock(ssp);
956
error = SYSCTL_OUT(req, &ssi, sizeof(struct smb_share_info));
957
if (error)
958
break;
959
}
960
smb_vc_unlock(vcp);
961
if (error)
962
break;
963
}
964
if (!error) {
965
itype = SMB_INFO_NONE;
966
error = SYSCTL_OUT(req, &itype, sizeof(itype));
967
}
968
smb_sm_unlockvclist();
969
return error;
970
}
971
972