Skip to content

Commit b68c8d6

Browse files
bugclerkwilliam-gr
andauthored
NAS-139116: Add hosts allow/deny fields to SMB share purposes (#13056)
(cherry picked from commit 28b3164) Co-authored-by: William Grzybowski <[email protected]>
1 parent 51df6a6 commit b68c8d6

File tree

4 files changed

+96
-43
lines changed

4 files changed

+96
-43
lines changed

src/app/helptext/sharing/smb/smb.ts

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -114,34 +114,29 @@ export const helptextSharingSmb = {
114114
),
115115

116116
hostsallowLabel: T('Hosts Allow'),
117-
hostsAllowTooltip: T('Enter a list of allowed hostnames or IP addresses.\
118-
Separate entries by pressing <code>Enter</code>. A more detailed description \
119-
with examples can be found \
120-
<a href="https://wiki.samba.org/index.php/1.4_Samba_Security" target="_blank">here</a>. <br><br> \
121-
If neither *Hosts Allow* or *Hosts Deny* contains \
122-
an entry, then SMB share access is allowed for any host. <br><br> \
123-
If there is a *Hosts Allow* list but no *Hosts Deny* list, then only allow \
124-
hosts on the *Hosts Allow* list. <br><br> \
125-
If there is a *Hosts Deny* list but no *Hosts Allow* list, then allow all \
126-
hosts that are not on the *Hosts Deny* list. <br><br> \
127-
If there is both a *Hosts Allow* and *Hosts Deny* list, then allow all hosts \
128-
that are on the *Hosts Allow* list. <br><br> \
129-
If there is a host not on the *Hosts Allow* and not on the *Hosts Deny* list, \
130-
then allow it.'),
117+
hostsAllowTooltip: T('A list of IP addresses or subnets that are allowed to access the SMB share. \
118+
Separate entries by pressing <code>Enter</code>. The EXCEPT keyword may be used to limit a wildcard list. \
119+
<br><br><b>Note:</b> Hostname lookups are disabled on the SMB server for performance reasons. \
120+
<br><br><b>Examples:</b><br> \
121+
• Single IPs: <code>192.168.0.200</code>, <code>150.203.</code><br> \
122+
• CIDR notation: <code>150.203.15.0/255.255.255.0</code><br> \
123+
• EXCEPT syntax: <code>150.203. EXCEPT 150.203.6.66</code> \
124+
<br><br><b>Behavior:</b><br> \
125+
• If neither <i>Hosts Allow</i> nor <i>Hosts Deny</i> contains an entry, SMB share access is allowed for any host.<br> \
126+
• If there is a <i>Hosts Allow</i> list but no <i>Hosts Deny</i> list, only allow hosts on the <i>Hosts Allow</i> list.<br> \
127+
• If there is both a <i>Hosts Allow</i> and <i>Hosts Deny</i> list, allow all hosts on the <i>Hosts Allow</i> list.<br> \
128+
• Hosts not on either list are allowed.'),
131129
hostsdenyLabel: T('Hosts Deny'),
132130
hostsdenyTooltip: T(
133-
'Enter a list of denied hostnames or IP addresses.\
134-
Separate entries by pressing <code>Enter</code>. \
135-
If neither *Hosts Allow* or *Hosts Deny* contains \
136-
an entry, then SMB share access is allowed for any host. <br><br> \
137-
If there is a *Hosts Allow* list but no *Hosts Deny* list, then only allow \
138-
hosts on the *Hosts Allow* list. <br><br> \
139-
If there is a *Hosts Deny* list but no *Hosts Allow* list, then allow all \
140-
hosts that are not on the *Hosts Deny* list. <br><br> \
141-
If there is both a *Hosts Allow* and *Hosts Deny* list, then allow all hosts \
142-
that are on the *Hosts Allow* list. <br><br> \
143-
If there is a host not on the *Hosts Allow* and not on the *Hosts Deny* list, \
144-
then allow it.',
131+
'A list of IP addresses or subnets that are not allowed to access the SMB share. \
132+
Separate entries by pressing <code>Enter</code>. The keyword <code>ALL</code> or the netmask \
133+
<code>0.0.0.0/0</code> may be used to deny all by default. \
134+
<br><br><b>Examples:</b><br> \
135+
• Partial IPs: <code>150.203.4.</code><br> \
136+
• Deny all: <code>ALL</code> or <code>0.0.0.0/0</code> \
137+
<br><br><b>Behavior:</b><br> \
138+
• If there is a <i>Hosts Deny</i> list but no <i>Hosts Allow</i> list, allow all hosts not on the <i>Hosts Deny</i> list.<br> \
139+
• If there is both a <i>Hosts Allow</i> and <i>Hosts Deny</i> list, the <i>Hosts Allow</i> list takes precedence.',
145140
),
146141

147142
shadowcopyLabel: T('Enable Shadow Copies'),

src/app/interfaces/smb-share.interface.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export interface ExternalSmbShare extends BaseShare {
106106

107107
export interface VeeamRepositorySmbShare extends BaseShare {
108108
purpose: SmbSharePurpose.VeeamRepositoryShare;
109-
options: Record<string, never>;
109+
options: VeeamRepositorySmbShareOptions;
110110
}
111111

112112
export interface FcpSmbShare extends BaseShare {
@@ -116,6 +116,8 @@ export interface FcpSmbShare extends BaseShare {
116116

117117
export interface FcpSmbShareOptions {
118118
aapl_name_mangling?: boolean;
119+
hostsallow?: string[];
120+
hostsdeny?: string[];
119121
}
120122

121123
export type SmbShareOptions =
@@ -126,6 +128,7 @@ export type SmbShareOptions =
126128
| TimeLockedSmbShareOptions
127129
| PrivateDatasetsSmbShareOptions
128130
| ExternalSmbShareOptions
131+
| VeeamRepositorySmbShareOptions
129132
| FcpSmbShareOptions;
130133

131134
export interface LegacySmbShareOptions {
@@ -150,6 +153,8 @@ export interface LegacySmbShareOptions {
150153

151154
export interface DefaultSmbShareOptions {
152155
aapl_name_mangling?: boolean;
156+
hostsallow?: string[];
157+
hostsdeny?: string[];
153158
}
154159

155160
export interface TimeMachineSmbShareOptions {
@@ -158,27 +163,40 @@ export interface TimeMachineSmbShareOptions {
158163
auto_snapshot?: boolean;
159164
auto_dataset_creation?: boolean;
160165
dataset_naming_schema?: string | null;
166+
hostsallow?: string[];
167+
hostsdeny?: string[];
161168
}
162169

163170
export interface MultiProtocolSmbShareOptions {
164171
aapl_name_mangling?: boolean;
172+
hostsallow?: string[];
173+
hostsdeny?: string[];
165174
}
166175

167176
export interface TimeLockedSmbShareOptions {
168177
grace_period?: number;
169178
aapl_name_mangling?: boolean;
179+
hostsallow?: string[];
180+
hostsdeny?: string[];
170181
}
171182

172183
export interface PrivateDatasetsSmbShareOptions {
173184
dataset_naming_schema?: string | null;
174185
auto_quota?: number;
175186
aapl_name_mangling?: boolean;
187+
hostsallow?: string[];
188+
hostsdeny?: string[];
176189
}
177190

178191
export interface ExternalSmbShareOptions {
179192
remote_path?: string[];
180193
}
181194

195+
export interface VeeamRepositorySmbShareOptions {
196+
hostsallow?: string[];
197+
hostsdeny?: string[];
198+
}
199+
182200
export interface SmbSharesec {
183201
id: number;
184202
share_acl: SmbSharesecAce[];
Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
import {
2-
SmbSharePurpose, SmbShare,
2+
SmbSharePurpose, SmbShareOptions,
33
} from 'app/interfaces/smb-share.interface';
44

5-
export const presetEnabledFields: Partial<{
6-
[T in SmbSharePurpose]: (keyof Extract<SmbShare, { purpose: T }>['options'])[]
7-
}> = {
5+
// Distribute keyof over union to get all possible option keys
6+
type AllOptionKeys<T> = T extends unknown ? keyof T : never;
7+
type OptionKeys = AllOptionKeys<SmbShareOptions>;
8+
9+
export const presetEnabledFields: Partial<Record<SmbSharePurpose, OptionKeys[]>> = {
810
[SmbSharePurpose.LegacyShare]: [
9-
'recyclebin', 'path_suffix', 'hostsallow', 'hostsdeny', 'guestok', 'streams',
10-
'durablehandle', 'shadowcopy', 'fsrvp', 'home', 'acl', 'afp', 'timemachine',
11-
'timemachine_quota', 'aapl_name_mangling', 'auxsmbconf', 'vuid',
11+
'recyclebin', 'path_suffix', 'guestok', 'streams', 'durablehandle', 'shadowcopy',
12+
'fsrvp', 'home', 'acl', 'afp', 'timemachine', 'timemachine_quota',
13+
'aapl_name_mangling', 'auxsmbconf', 'vuid', 'hostsallow', 'hostsdeny',
1214
],
13-
[SmbSharePurpose.DefaultShare]: ['aapl_name_mangling'],
15+
[SmbSharePurpose.DefaultShare]: ['aapl_name_mangling', 'hostsallow', 'hostsdeny'],
1416
[SmbSharePurpose.TimeMachineShare]: [
15-
'timemachine_quota', 'vuid', 'auto_snapshot',
16-
'auto_dataset_creation', 'dataset_naming_schema',
17+
'timemachine_quota', 'vuid', 'auto_snapshot', 'auto_dataset_creation',
18+
'dataset_naming_schema', 'hostsallow', 'hostsdeny',
1719
],
18-
[SmbSharePurpose.MultiProtocolShare]: ['aapl_name_mangling'],
19-
[SmbSharePurpose.TimeLockedShare]: ['grace_period', 'aapl_name_mangling'],
20+
[SmbSharePurpose.MultiProtocolShare]: ['aapl_name_mangling', 'hostsallow', 'hostsdeny'],
21+
[SmbSharePurpose.TimeLockedShare]: ['grace_period', 'aapl_name_mangling', 'hostsallow', 'hostsdeny'],
2022
[SmbSharePurpose.PrivateDatasetsShare]: [
21-
'dataset_naming_schema', 'auto_quota', 'aapl_name_mangling',
23+
'dataset_naming_schema', 'auto_quota', 'aapl_name_mangling', 'hostsallow', 'hostsdeny',
2224
],
2325
[SmbSharePurpose.ExternalShare]: ['remote_path'],
24-
[SmbSharePurpose.VeeamRepositoryShare]: [],
25-
[SmbSharePurpose.FcpShare]: ['aapl_name_mangling'],
26+
[SmbSharePurpose.VeeamRepositoryShare]: ['hostsallow', 'hostsdeny'],
27+
[SmbSharePurpose.FcpShare]: ['aapl_name_mangling', 'hostsallow', 'hostsdeny'],
2628
};

src/app/pages/sharing/smb/smb-form/smb-form.component.spec.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ describe('SmbFormComponent', () => {
321321
},
322322
options: {
323323
aapl_name_mangling: true,
324+
hostsallow: [],
325+
hostsdeny: [],
324326
},
325327
}]);
326328
});
@@ -345,6 +347,8 @@ describe('SmbFormComponent', () => {
345347
auto_snapshot: true,
346348
auto_dataset_creation: true,
347349
dataset_naming_schema: '%u',
350+
hostsallow: [],
351+
hostsdeny: [],
348352
},
349353
}),
350354
]);
@@ -362,6 +366,8 @@ describe('SmbFormComponent', () => {
362366
purpose: SmbSharePurpose.MultiProtocolShare,
363367
options: {
364368
aapl_name_mangling: true,
369+
hostsallow: [],
370+
hostsdeny: [],
365371
},
366372
}),
367373
]);
@@ -381,6 +387,8 @@ describe('SmbFormComponent', () => {
381387
options: {
382388
grace_period: 900,
383389
aapl_name_mangling: true,
390+
hostsallow: [],
391+
hostsdeny: [],
384392
},
385393
}),
386394
]);
@@ -402,6 +410,8 @@ describe('SmbFormComponent', () => {
402410
dataset_naming_schema: '%u',
403411
auto_quota: 20,
404412
aapl_name_mangling: true,
413+
hostsallow: [],
414+
hostsdeny: [],
405415
},
406416
}),
407417
]);
@@ -433,7 +443,10 @@ describe('SmbFormComponent', () => {
433443
expect(api.call).toHaveBeenLastCalledWith('sharing.smb.create', [
434444
expect.objectContaining({
435445
purpose: SmbSharePurpose.VeeamRepositoryShare,
436-
options: {},
446+
options: {
447+
hostsallow: [],
448+
hostsdeny: [],
449+
},
437450
}),
438451
]);
439452
});
@@ -461,10 +474,31 @@ describe('SmbFormComponent', () => {
461474
},
462475
options: {
463476
aapl_name_mangling: true,
477+
hostsallow: [],
478+
hostsdeny: [],
464479
},
465480
}),
466481
]);
467482
});
483+
484+
it('sends hosts allow and deny values when specified', async () => {
485+
await submitForm({
486+
...commonValues,
487+
Purpose: 'Default Share',
488+
'Hosts Allow': ['192.168.1.0/24', '10.0.0.1'],
489+
'Hosts Deny': ['172.16.0.0/16'],
490+
});
491+
492+
expect(api.call).toHaveBeenLastCalledWith('sharing.smb.create', [
493+
expect.objectContaining({
494+
purpose: SmbSharePurpose.DefaultShare,
495+
options: expect.objectContaining({
496+
hostsallow: ['192.168.1.0/24', '10.0.0.1'],
497+
hostsdeny: ['172.16.0.0/16'],
498+
}),
499+
}),
500+
]);
501+
});
468502
});
469503

470504
describe('edit default share', () => {
@@ -488,6 +522,8 @@ describe('SmbFormComponent', () => {
488522
'Browsable to Network Clients': true,
489523
'Access Based Share Enumeration': true,
490524
'Enable Logging': false,
525+
'Hosts Allow': [],
526+
'Hosts Deny': [],
491527

492528
'Use Apple-style Character Encoding': true,
493529
});
@@ -625,6 +661,8 @@ describe('SmbFormComponent', () => {
625661
'Export Read Only',
626662
'Browsable to Network Clients',
627663
'Access Based Share Enumeration',
664+
'Hosts Allow',
665+
'Hosts Deny',
628666
'Enable Logging',
629667
'Use Apple-style Character Encoding',
630668
]);

0 commit comments

Comments
 (0)