Added
Link Here
|
1 |
--- docs-xml/wscript_build.orig 2019-06-25 00:52:38 UTC |
2 |
+++ docs-xml/wscript_build |
3 |
@@ -79,6 +79,7 @@ vfs_module_manpages = ['vfs_acl_tdb', |
4 |
'vfs_extd_audit', |
5 |
'vfs_fake_perms', |
6 |
'vfs_fileid', |
7 |
+ 'vfs_freebsd', |
8 |
'vfs_fruit', |
9 |
'vfs_full_audit', |
10 |
'vfs_glusterfs', |
11 |
--- source3/modules/wscript_build.orig 2019-05-07 08:38:21 UTC |
12 |
+++ source3/modules/wscript_build |
13 |
@@ -630,6 +630,14 @@ bld.SAMBA3_MODULE('vfs_delay_inject', |
14 |
enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_delay_inject'), |
15 |
install=False) |
16 |
|
17 |
+bld.SAMBA3_MODULE('vfs_freebsd', |
18 |
+ subsystem='vfs', |
19 |
+ source='vfs_freebsd.c', |
20 |
+ deps='samba-util', |
21 |
+ init_function='', |
22 |
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_freebsd'), |
23 |
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_freebsd')) |
24 |
+ |
25 |
bld.SAMBA3_MODULE('vfs_widelinks', |
26 |
subsystem='vfs', |
27 |
source='vfs_widelinks.c', |
28 |
--- source3/modules/vfs_freebsd.c.orig 2019-06-22 11:56:57 UTC |
29 |
+++ source3/modules/vfs_freebsd.c |
30 |
@@ -0,0 +1,800 @@ |
31 |
+/* |
32 |
+ * This module implements VFS calls specific to FreeBSD |
33 |
+ * |
34 |
+ * Copyright (C) Timur I. Bakeyev, 2018 |
35 |
+ * |
36 |
+ * This program is free software; you can redistribute it and/or modify |
37 |
+ * it under the terms of the GNU General Public License as published by |
38 |
+ * the Free Software Foundation; either version 3 of the License, or |
39 |
+ * (at your option) any later version. |
40 |
+ * |
41 |
+ * This program is distributed in the hope that it will be useful, |
42 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
43 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
44 |
+ * GNU General Public License for more details. |
45 |
+ * |
46 |
+ * You should have received a copy of the GNU General Public License |
47 |
+ * along with this program; if not, see <http://www.gnu.org/licenses/>. |
48 |
+ */ |
49 |
+ |
50 |
+#include "includes.h" |
51 |
+ |
52 |
+#include "lib/util/tevent_unix.h" |
53 |
+#include "lib/util/tevent_ntstatus.h" |
54 |
+#include "system/filesys.h" |
55 |
+ |
56 |
+#include <sys/sysctl.h> |
57 |
+ |
58 |
+static int vfs_freebsd_debug_level = DBGC_VFS; |
59 |
+ |
60 |
+#undef DBGC_CLASS |
61 |
+#define DBGC_CLASS vfs_freebsd_debug_level |
62 |
+ |
63 |
+#ifndef EXTATTR_MAXNAMELEN |
64 |
+#define EXTATTR_MAXNAMELEN UINT8_MAX |
65 |
+#endif |
66 |
+ |
67 |
+#define EXTATTR_NAMESPACE(NS) EXTATTR_NAMESPACE_ ## NS, \ |
68 |
+ EXTATTR_NAMESPACE_ ## NS ## _STRING ".", \ |
69 |
+ .data.len = (sizeof(EXTATTR_NAMESPACE_ ## NS ## _STRING ".") - 1) |
70 |
+ |
71 |
+#define EXTATTR_EMPTY 0x00 |
72 |
+#define EXTATTR_USER 0x01 |
73 |
+#define EXTATTR_SYSTEM 0x02 |
74 |
+#define EXTATTR_SECURITY 0x03 |
75 |
+#define EXTATTR_TRUSTED 0x04 |
76 |
+ |
77 |
+enum extattr_mode { |
78 |
+ FREEBSD_EXTATTR_SECURE, |
79 |
+ FREEBSD_EXTATTR_COMPAT, |
80 |
+ FREEBSD_EXTATTR_LEGACY |
81 |
+}; |
82 |
+ |
83 |
+typedef struct { |
84 |
+ int namespace; |
85 |
+ char name[EXTATTR_MAXNAMELEN+1]; |
86 |
+ union { |
87 |
+ uint16_t len; |
88 |
+ uint16_t flags; |
89 |
+ } data; |
90 |
+} extattr_attr; |
91 |
+ |
92 |
+typedef struct { |
93 |
+ enum { |
94 |
+ EXTATTR_FILE, EXTATTR_LINK, EXTATTR_FDES |
95 |
+ } method; |
96 |
+ union { |
97 |
+ const char *path; |
98 |
+ int filedes; |
99 |
+ } param; |
100 |
+} extattr_arg; |
101 |
+ |
102 |
+static const struct enum_list extattr_mode_param[] = { |
103 |
+ { FREEBSD_EXTATTR_SECURE, "secure" }, /* */ |
104 |
+ { FREEBSD_EXTATTR_COMPAT, "compat" }, /* */ |
105 |
+ { FREEBSD_EXTATTR_LEGACY, "legacy" }, /* */ |
106 |
+ { -1, NULL } |
107 |
+}; |
108 |
+ |
109 |
+ |
110 |
+/* */ |
111 |
+struct freebsd_handle_data { |
112 |
+ enum extattr_mode extattr_mode; |
113 |
+}; |
114 |
+ |
115 |
+ |
116 |
+/* XXX: This order doesn't match namespace ids order! */ |
117 |
+static extattr_attr extattr[] = { |
118 |
+ { EXTATTR_NAMESPACE(EMPTY) }, |
119 |
+ { EXTATTR_NAMESPACE(SYSTEM) }, |
120 |
+ { EXTATTR_NAMESPACE(USER) }, |
121 |
+}; |
122 |
+ |
123 |
+ |
124 |
+static bool freebsd_in_jail(void) { |
125 |
+ int val = 0; |
126 |
+ size_t val_len = sizeof(val); |
127 |
+ |
128 |
+ if((sysctlbyname("security.jail.jailed", &val, &val_len, NULL, 0) != -1) && val == 1) { |
129 |
+ return true; |
130 |
+ } |
131 |
+ return false; |
132 |
+} |
133 |
+ |
134 |
+static uint16_t freebsd_map_attrname(const char *name) |
135 |
+{ |
136 |
+ if(name == NULL || name[0] == '\0') { |
137 |
+ return EXTATTR_EMPTY; |
138 |
+ } |
139 |
+ |
140 |
+ switch(name[0]) { |
141 |
+ case 'u': |
142 |
+ if(strncmp(name, "user.", 5) == 0) |
143 |
+ return EXTATTR_USER; |
144 |
+ break; |
145 |
+ case 't': |
146 |
+ if(strncmp(name, "trusted.", 8) == 0) |
147 |
+ return EXTATTR_TRUSTED; |
148 |
+ break; |
149 |
+ case 's': |
150 |
+ /* name[1] could be any character, including '\0' */ |
151 |
+ switch(name[1]) { |
152 |
+ case 'e': |
153 |
+ if(strncmp(name, "security.", 9) == 0) |
154 |
+ return EXTATTR_SECURITY; |
155 |
+ break; |
156 |
+ case 'y': |
157 |
+ if(strncmp(name, "system.", 7) == 0) |
158 |
+ return EXTATTR_SYSTEM; |
159 |
+ break; |
160 |
+ } |
161 |
+ break; |
162 |
+ } |
163 |
+ return EXTATTR_USER; |
164 |
+} |
165 |
+ |
166 |
+/* security, system, trusted or user */ |
167 |
+static extattr_attr* freebsd_map_xattr(enum extattr_mode extattr_mode, const char *name, extattr_attr *attr) |
168 |
+{ |
169 |
+ int attrnamespace = EXTATTR_NAMESPACE_EMPTY; |
170 |
+ const char *p, *attrname = name; |
171 |
+ |
172 |
+ if(name == NULL || name[0] == '\0') { |
173 |
+ return NULL; |
174 |
+ } |
175 |
+ |
176 |
+ if(attr == NULL) { |
177 |
+ return NULL; |
178 |
+ } |
179 |
+ |
180 |
+ uint16_t flags = freebsd_map_attrname(name); |
181 |
+ |
182 |
+ switch(flags) { |
183 |
+ case EXTATTR_SECURITY: |
184 |
+ case EXTATTR_TRUSTED: |
185 |
+ case EXTATTR_SYSTEM: |
186 |
+ attrnamespace = (extattr_mode == FREEBSD_EXTATTR_SECURE) ? |
187 |
+ EXTATTR_NAMESPACE_SYSTEM : |
188 |
+ EXTATTR_NAMESPACE_USER; |
189 |
+ break; |
190 |
+ case EXTATTR_USER: |
191 |
+ attrnamespace = EXTATTR_NAMESPACE_USER; |
192 |
+ break; |
193 |
+ default: |
194 |
+ /* Default to "user" namespace if nothing else was specified */ |
195 |
+ attrnamespace = EXTATTR_NAMESPACE_USER; |
196 |
+ flags = EXTATTR_USER; |
197 |
+ break; |
198 |
+ } |
199 |
+ |
200 |
+ if (extattr_mode == FREEBSD_EXTATTR_LEGACY) { |
201 |
+ switch(flags) { |
202 |
+ case EXTATTR_SECURITY: |
203 |
+ attrname = name + 9; |
204 |
+ break; |
205 |
+ case EXTATTR_TRUSTED: |
206 |
+ attrname = name + 8; |
207 |
+ break; |
208 |
+ case EXTATTR_SYSTEM: |
209 |
+ attrname = name + 7; |
210 |
+ break; |
211 |
+ case EXTATTR_USER: |
212 |
+ attrname = name + 5; |
213 |
+ break; |
214 |
+ default: |
215 |
+ attrname = ((p=strchr(name, '.')) != NULL) ? p + 1 : name; |
216 |
+ break; |
217 |
+ } |
218 |
+ } |
219 |
+ |
220 |
+ attr->namespace = attrnamespace; |
221 |
+ attr->data.flags = flags; |
222 |
+ strlcpy(attr->name, attrname, EXTATTR_MAXNAMELEN + 1); |
223 |
+ |
224 |
+ return attr; |
225 |
+} |
226 |
+ |
227 |
+static ssize_t extattr_size(extattr_arg arg, extattr_attr *attr) |
228 |
+{ |
229 |
+ ssize_t result; |
230 |
+ |
231 |
+ switch(arg.method) { |
232 |
+#if defined(HAVE_XATTR_EXTATTR) |
233 |
+ case EXTATTR_FILE: |
234 |
+ result = extattr_get_file(arg.param.path, attr->namespace, attr->name, NULL, 0); |
235 |
+ break; |
236 |
+ case EXTATTR_LINK: |
237 |
+ result = extattr_get_link(arg.param.path, attr->namespace, attr->name, NULL, 0); |
238 |
+ break; |
239 |
+ case EXTATTR_FDES: |
240 |
+ result = extattr_get_fd(arg.param.filedes, attr->namespace, attr->name, NULL, 0); |
241 |
+ break; |
242 |
+#endif |
243 |
+ default: |
244 |
+ errno = ENOSYS; |
245 |
+ return -1; |
246 |
+ } |
247 |
+ |
248 |
+ if(result < 0) { |
249 |
+ errno = EINVAL; |
250 |
+ return -1; |
251 |
+ } |
252 |
+ |
253 |
+ return result; |
254 |
+} |
255 |
+ |
256 |
+ |
257 |
+/* |
258 |
+ * The list of names is returned as an unordered array of NULL-terminated |
259 |
+ * character strings (attribute names are separated by NULL characters), |
260 |
+ * like this: |
261 |
+ * user.name1\0system.name1\0user.name2\0 |
262 |
+ * |
263 |
+ * Filesystems like ext2, ext3 and XFS which implement POSIX ACLs using |
264 |
+ * extended attributes, might return a list like this: |
265 |
+ * system.posix_acl_access\0system.posix_acl_default\0 |
266 |
+ */ |
267 |
+/* |
268 |
+ * The extattr_list_file() returns a list of attributes present in the |
269 |
+ * requested namespace. Each list entry consists of a single byte containing |
270 |
+ * the length of the attribute name, followed by the attribute name. The |
271 |
+ * attribute name is not terminated by ASCII 0 (nul). |
272 |
+*/ |
273 |
+ |
274 |
+static ssize_t freebsd_extattr_list(extattr_arg arg, enum extattr_mode extattr_mode, char *list, size_t size) |
275 |
+{ |
276 |
+ ssize_t list_size, total_size = 0; |
277 |
+ char *p, *q, *list_end; |
278 |
+ int len; |
279 |
+ /* |
280 |
+ Ignore all but user namespace when we are not root or in jail |
281 |
+ See: https://bugzilla.samba.org/show_bug.cgi?id=10247 |
282 |
+ */ |
283 |
+ bool as_root = (geteuid() == 0); |
284 |
+ |
285 |
+ int ns = (extattr_mode == FREEBSD_EXTATTR_SECURE && as_root) ? 1 : 2; |
286 |
+ |
287 |
+ /* Iterate through extattr(2) namespaces */ |
288 |
+ for(; ns < ARRAY_SIZE(extattr); ns++) { |
289 |
+ switch(arg.method) { |
290 |
+#if defined(HAVE_XATTR_EXTATTR) |
291 |
+ case EXTATTR_FILE: |
292 |
+ list_size = extattr_list_file(arg.param.path, extattr[ns].namespace, list, size); |
293 |
+ break; |
294 |
+ case EXTATTR_LINK: |
295 |
+ list_size = extattr_list_link(arg.param.path, extattr[ns].namespace, list, size); |
296 |
+ break; |
297 |
+ case EXTATTR_FDES: |
298 |
+ list_size = extattr_list_fd(arg.param.filedes, extattr[ns].namespace, list, size); |
299 |
+ break; |
300 |
+#endif |
301 |
+ default: |
302 |
+ errno = ENOSYS; |
303 |
+ return -1; |
304 |
+ } |
305 |
+ /* Some error happend. Errno should be set by the previous call */ |
306 |
+ if(list_size < 0) |
307 |
+ return -1; |
308 |
+ /* No attributes in this namespace */ |
309 |
+ if(list_size == 0) |
310 |
+ continue; |
311 |
+ /* |
312 |
+ Call with an empty buffer may be used to calculate |
313 |
+ necessary buffer size. |
314 |
+ */ |
315 |
+ if(list == NULL) { |
316 |
+ /* |
317 |
+ XXX: Unfortunately, we can't say, how many attributes were |
318 |
+ returned, so here is the potential problem with the emulation. |
319 |
+ */ |
320 |
+ if(extattr_mode == FREEBSD_EXTATTR_LEGACY) { |
321 |
+ /* |
322 |
+ Take the worse case of one char attribute names - |
323 |
+ two bytes per name plus one more for sanity. |
324 |
+ */ |
325 |
+ total_size += list_size + (list_size/2 + 1)*extattr[ns].data.len; |
326 |
+ } |
327 |
+ else { |
328 |
+ total_size += list_size; |
329 |
+ } |
330 |
+ continue; |
331 |
+ } |
332 |
+ |
333 |
+ if(extattr_mode == FREEBSD_EXTATTR_LEGACY) { |
334 |
+ /* Count necessary offset to fit namespace prefixes */ |
335 |
+ int extra_len = 0; |
336 |
+ uint16_t flags; |
337 |
+ list_end = list + list_size; |
338 |
+ for(list_size = 0, p = q = list; p < list_end; p += len) { |
339 |
+ len = p[0] + 1; |
340 |
+ (void)strlcpy(q, p + 1, len); |
341 |
+ flags = freebsd_map_attrname(q); |
342 |
+ /* Skip secure attributes for non-root user */ |
343 |
+ if(extattr_mode != FREEBSD_EXTATTR_SECURE && !as_root && flags > EXTATTR_USER) { |
344 |
+ continue; |
345 |
+ } |
346 |
+ if(flags <= EXTATTR_USER) { |
347 |
+ /* Don't count trailing '\0' */ |
348 |
+ extra_len += extattr[ns].data.len; |
349 |
+ } |
350 |
+ list_size += len; |
351 |
+ q += len; |
352 |
+ } |
353 |
+ total_size += list_size + extra_len; |
354 |
+ /* Buffer is too small to fit the results */ |
355 |
+ if(total_size > size) { |
356 |
+ errno = ERANGE; |
357 |
+ return -1; |
358 |
+ } |
359 |
+ /* Shift results backwards, so we can prepend prefixes */ |
360 |
+ list_end = list + extra_len; |
361 |
+ p = (char*)memmove(list_end, list, list_size); |
362 |
+ /* |
363 |
+ We enter the loop with `p` pointing to the shifted list and |
364 |
+ `extra_len` having the total margin between `list` and `p` |
365 |
+ */ |
366 |
+ for(list_end += list_size; p < list_end; p += len) { |
367 |
+ len = strlen(p) + 1; |
368 |
+ flags = freebsd_map_attrname(p); |
369 |
+ if(flags <= EXTATTR_USER) { |
370 |
+ /* Add namespace prefix */ |
371 |
+ (void)strncpy(list, extattr[ns].name, extattr[ns].data.len); |
372 |
+ list += extattr[ns].data.len; |
373 |
+ } |
374 |
+ /* Append attribute name */ |
375 |
+ (void)strlcpy(list, p, len); |
376 |
+ list += len; |
377 |
+ } |
378 |
+ } |
379 |
+ else { |
380 |
+ /* Convert UCSD strings into nul-terminated strings */ |
381 |
+ for(list_end = list + list_size; list < list_end; list += len) { |
382 |
+ len = list[0] + 1; |
383 |
+ (void)strlcpy(list, list + 1, len); |
384 |
+ } |
385 |
+ total_size += list_size; |
386 |
+ } |
387 |
+ } |
388 |
+ return total_size; |
389 |
+} |
390 |
+ |
391 |
+/* |
392 |
+static ssize_t freebsd_getxattr_size(vfs_handle_struct *handle, |
393 |
+ const struct smb_filename *smb_fname, |
394 |
+ const char *name) |
395 |
+{ |
396 |
+ struct freebsd_handle_data *data; |
397 |
+ extattr_arg arg = { EXTATTR_FILE, smb_fname->base_name }; |
398 |
+ extattr_attr attr; |
399 |
+ |
400 |
+ |
401 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
402 |
+ struct freebsd_handle_data, |
403 |
+ return -1); |
404 |
+ |
405 |
+ if(!freebsd_map_xattr(data->extattr_mode, name, &attr)) { |
406 |
+ errno = EINVAL; |
407 |
+ return -1; |
408 |
+ } |
409 |
+ |
410 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
411 |
+ errno = ENOATTR; |
412 |
+ return -1; |
413 |
+ } |
414 |
+ |
415 |
+ return extattr_size(arg, &attr); |
416 |
+} |
417 |
+*/ |
418 |
+ |
419 |
+/* VFS entries */ |
420 |
+static ssize_t freebsd_getxattr(vfs_handle_struct *handle, |
421 |
+ const struct smb_filename *smb_fname, |
422 |
+ const char *name, |
423 |
+ void *value, |
424 |
+ size_t size) |
425 |
+{ |
426 |
+#if defined(HAVE_XATTR_EXTATTR) |
427 |
+ struct freebsd_handle_data *data; |
428 |
+ extattr_arg arg = { EXTATTR_FILE, .param.path = smb_fname->base_name }; |
429 |
+ extattr_attr attr; |
430 |
+ ssize_t res; |
431 |
+ |
432 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
433 |
+ struct freebsd_handle_data, |
434 |
+ return -1); |
435 |
+ |
436 |
+ if(!freebsd_map_xattr(data->extattr_mode, name, &attr)) { |
437 |
+ errno = EINVAL; |
438 |
+ return -1; |
439 |
+ } |
440 |
+ |
441 |
+ /* Filter out 'secure' entries */ |
442 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
443 |
+ errno = ENOATTR; |
444 |
+ return -1; |
445 |
+ } |
446 |
+ |
447 |
+ /* |
448 |
+ * The BSD implementation has a nasty habit of silently truncating |
449 |
+ * the returned value to the size of the buffer, so we have to check |
450 |
+ * that the buffer is large enough to fit the returned value. |
451 |
+ */ |
452 |
+ if((res=extattr_size(arg, &attr)) < 0) { |
453 |
+ return -1; |
454 |
+ } |
455 |
+ |
456 |
+ if (size == 0) { |
457 |
+ return res; |
458 |
+ } |
459 |
+ else if (res > size) { |
460 |
+ errno = ERANGE; |
461 |
+ return -1; |
462 |
+ } |
463 |
+ |
464 |
+ if((res=extattr_get_file(smb_fname->base_name, attr.namespace, attr.name, value, size)) >= 0) { |
465 |
+ return res; |
466 |
+ } |
467 |
+ return -1; |
468 |
+#else |
469 |
+ errno = ENOSYS; |
470 |
+ return -1; |
471 |
+#endif |
472 |
+} |
473 |
+ |
474 |
+ |
475 |
+static ssize_t freebsd_fgetxattr(vfs_handle_struct *handle, |
476 |
+ struct files_struct *fsp, const char *name, |
477 |
+ void *value, size_t size) |
478 |
+{ |
479 |
+#if defined(HAVE_XATTR_EXTATTR) |
480 |
+ struct freebsd_handle_data *data; |
481 |
+ extattr_arg arg = { EXTATTR_FDES, .param.filedes = fsp->fh->fd }; |
482 |
+ extattr_attr attr; |
483 |
+ ssize_t res; |
484 |
+ |
485 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
486 |
+ struct freebsd_handle_data, |
487 |
+ return -1); |
488 |
+ |
489 |
+ if(!freebsd_map_xattr(data->extattr_mode, name, &attr)) { |
490 |
+ errno = EINVAL; |
491 |
+ return -1; |
492 |
+ } |
493 |
+ |
494 |
+ /* Filter out 'secure' entries */ |
495 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
496 |
+ errno = ENOATTR; |
497 |
+ return -1; |
498 |
+ } |
499 |
+ |
500 |
+ /* |
501 |
+ * The BSD implementation has a nasty habit of silently truncating |
502 |
+ * the returned value to the size of the buffer, so we have to check |
503 |
+ * that the buffer is large enough to fit the returned value. |
504 |
+ */ |
505 |
+ if((res=extattr_size(arg, &attr)) < 0) { |
506 |
+ return -1; |
507 |
+ } |
508 |
+ |
509 |
+ if (size == 0) { |
510 |
+ return res; |
511 |
+ } |
512 |
+ else if (res > size) { |
513 |
+ errno = ERANGE; |
514 |
+ return -1; |
515 |
+ } |
516 |
+ |
517 |
+ if((res=extattr_get_fd(fsp->fh->fd, attr.namespace, attr.name, value, size)) >= 0) { |
518 |
+ return res; |
519 |
+ } |
520 |
+ return -1; |
521 |
+#else |
522 |
+ errno = ENOSYS; |
523 |
+ return -1; |
524 |
+#endif |
525 |
+} |
526 |
+ |
527 |
+ |
528 |
+static ssize_t freebsd_listxattr(vfs_handle_struct *handle, |
529 |
+ const struct smb_filename *smb_fname, |
530 |
+ char *list, |
531 |
+ size_t size) |
532 |
+{ |
533 |
+#if defined(HAVE_XATTR_EXTATTR) |
534 |
+ struct freebsd_handle_data *data; |
535 |
+ |
536 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
537 |
+ struct freebsd_handle_data, |
538 |
+ return -1); |
539 |
+ |
540 |
+ extattr_arg arg = { EXTATTR_FILE, .param.path = smb_fname->base_name }; |
541 |
+ |
542 |
+ return freebsd_extattr_list(arg, data->extattr_mode, list, size); |
543 |
+#else |
544 |
+ errno = ENOSYS; |
545 |
+ return -1; |
546 |
+#endif |
547 |
+} |
548 |
+ |
549 |
+ |
550 |
+static ssize_t freebsd_flistxattr(vfs_handle_struct *handle, |
551 |
+ struct files_struct *fsp, char *list, |
552 |
+ size_t size) |
553 |
+{ |
554 |
+#if defined(HAVE_XATTR_EXTATTR) |
555 |
+ struct freebsd_handle_data *data; |
556 |
+ extattr_arg arg = { EXTATTR_FDES, .param.filedes = fsp->fh->fd }; |
557 |
+ |
558 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
559 |
+ struct freebsd_handle_data, |
560 |
+ return -1); |
561 |
+ |
562 |
+ return freebsd_extattr_list(arg, data->extattr_mode, list, size); |
563 |
+#else |
564 |
+ errno = ENOSYS; |
565 |
+ return -1; |
566 |
+#endif |
567 |
+} |
568 |
+ |
569 |
+static int freebsd_removexattr(vfs_handle_struct *handle, |
570 |
+ const struct smb_filename *smb_fname, |
571 |
+ const char *name) |
572 |
+{ |
573 |
+#if defined(HAVE_XATTR_EXTATTR) |
574 |
+ struct freebsd_handle_data *data; |
575 |
+ extattr_attr attr; |
576 |
+ |
577 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
578 |
+ struct freebsd_handle_data, |
579 |
+ return -1); |
580 |
+ |
581 |
+ |
582 |
+ /* Filter out 'secure' entries */ |
583 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
584 |
+ errno = ENOATTR; |
585 |
+ return -1; |
586 |
+ } |
587 |
+ |
588 |
+ return extattr_delete_file(smb_fname->base_name, attr.namespace, attr.name); |
589 |
+#else |
590 |
+ errno = ENOSYS; |
591 |
+ return -1; |
592 |
+#endif |
593 |
+} |
594 |
+ |
595 |
+ |
596 |
+static int freebsd_fremovexattr(vfs_handle_struct *handle, |
597 |
+ struct files_struct *fsp, const char *name) |
598 |
+{ |
599 |
+#if defined(HAVE_XATTR_EXTATTR) |
600 |
+ struct freebsd_handle_data *data; |
601 |
+ extattr_attr attr; |
602 |
+ |
603 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
604 |
+ struct freebsd_handle_data, |
605 |
+ return -1); |
606 |
+ |
607 |
+ if(!freebsd_map_xattr(data->extattr_mode, name, &attr)) { |
608 |
+ errno = EINVAL; |
609 |
+ return -1; |
610 |
+ } |
611 |
+ |
612 |
+ /* Filter out 'secure' entries */ |
613 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
614 |
+ errno = ENOATTR; |
615 |
+ return -1; |
616 |
+ } |
617 |
+ |
618 |
+ return extattr_delete_fd(fsp->fh->fd, attr.namespace, attr.name); |
619 |
+#else |
620 |
+ errno = ENOSYS; |
621 |
+ return -1; |
622 |
+#endif |
623 |
+} |
624 |
+ |
625 |
+ |
626 |
+static int freebsd_setxattr(vfs_handle_struct *handle, |
627 |
+ const struct smb_filename *smb_fname, |
628 |
+ const char *name, |
629 |
+ const void *value, |
630 |
+ size_t size, |
631 |
+ int flags) |
632 |
+{ |
633 |
+#if defined(HAVE_XATTR_EXTATTR) |
634 |
+ struct freebsd_handle_data *data; |
635 |
+ extattr_attr attr; |
636 |
+ ssize_t res; |
637 |
+ |
638 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
639 |
+ struct freebsd_handle_data, |
640 |
+ return -1); |
641 |
+ |
642 |
+ if(!freebsd_map_xattr(data->extattr_mode, name, &attr)) { |
643 |
+ errno = EINVAL; |
644 |
+ return -1; |
645 |
+ } |
646 |
+ |
647 |
+ /* Filter out 'secure' entries */ |
648 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
649 |
+ errno = ENOATTR; |
650 |
+ return -1; |
651 |
+ } |
652 |
+ |
653 |
+ if (flags) { |
654 |
+ extattr_arg arg = { EXTATTR_FILE, .param.path = smb_fname->base_name }; |
655 |
+ /* Check attribute existence */ |
656 |
+ res = extattr_size(arg, &attr); |
657 |
+ if (res < 0) { |
658 |
+ /* REPLACE attribute, that doesn't exist */ |
659 |
+ if ((flags & XATTR_REPLACE) && errno == ENOATTR) { |
660 |
+ errno = ENOATTR; |
661 |
+ return -1; |
662 |
+ } |
663 |
+ /* Ignore other errors */ |
664 |
+ } |
665 |
+ else { |
666 |
+ /* CREATE attribute, that already exists */ |
667 |
+ if (flags & XATTR_CREATE) { |
668 |
+ errno = EEXIST; |
669 |
+ return -1; |
670 |
+ } |
671 |
+ } |
672 |
+ } |
673 |
+ res = extattr_set_file(smb_fname->base_name, attr.namespace, attr.name, value, size); |
674 |
+ |
675 |
+ return (res >= 0) ? 0 : -1; |
676 |
+#else |
677 |
+ errno = ENOSYS; |
678 |
+ return -1; |
679 |
+#endif |
680 |
+} |
681 |
+ |
682 |
+ |
683 |
+static int freebsd_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, |
684 |
+ const char *name, const void *value, size_t size, |
685 |
+ int flags) |
686 |
+{ |
687 |
+#if defined(HAVE_XATTR_EXTATTR) |
688 |
+ struct freebsd_handle_data *data; |
689 |
+ extattr_attr attr; |
690 |
+ ssize_t res; |
691 |
+ |
692 |
+ SMB_VFS_HANDLE_GET_DATA(handle, data, |
693 |
+ struct freebsd_handle_data, |
694 |
+ return -1); |
695 |
+ |
696 |
+ if(!freebsd_map_xattr(data->extattr_mode, name, &attr)) { |
697 |
+ errno = EINVAL; |
698 |
+ return -1; |
699 |
+ } |
700 |
+ |
701 |
+ /* Filter out 'secure' entries */ |
702 |
+ if(data->extattr_mode != FREEBSD_EXTATTR_SECURE && geteuid() != 0 && attr.data.flags > EXTATTR_USER) { |
703 |
+ errno = ENOATTR; |
704 |
+ return -1; |
705 |
+ } |
706 |
+ |
707 |
+ if (flags) { |
708 |
+ extattr_arg arg = { EXTATTR_FDES, .param.filedes = fsp->fh->fd }; |
709 |
+ /* Check attribute existence */ |
710 |
+ res = extattr_size(arg, &attr); |
711 |
+ if (res < 0) { |
712 |
+ /* REPLACE attribute, that doesn't exist */ |
713 |
+ if ((flags & XATTR_REPLACE) && errno == ENOATTR) { |
714 |
+ errno = ENOATTR; |
715 |
+ return -1; |
716 |
+ } |
717 |
+ /* Ignore other errors */ |
718 |
+ } |
719 |
+ else { |
720 |
+ /* CREATE attribute, that already exists */ |
721 |
+ if (flags & XATTR_CREATE) { |
722 |
+ errno = EEXIST; |
723 |
+ return -1; |
724 |
+ } |
725 |
+ } |
726 |
+ } |
727 |
+ |
728 |
+ res = extattr_set_fd(fsp->fh->fd, attr.namespace, attr.name, value, size); |
729 |
+ |
730 |
+ return (res >= 0) ? 0 : -1; |
731 |
+#else |
732 |
+ errno = ENOSYS; |
733 |
+ return -1; |
734 |
+#endif |
735 |
+} |
736 |
+ |
737 |
+static int freebsd_connect(vfs_handle_struct *handle, const char *service, |
738 |
+ const char *user) |
739 |
+{ |
740 |
+ struct freebsd_handle_data *data; |
741 |
+ int enumval, saved_errno; |
742 |
+ |
743 |
+ int ret = SMB_VFS_NEXT_CONNECT(handle, service, user); |
744 |
+ |
745 |
+ if (ret < 0) { |
746 |
+ return ret; |
747 |
+ } |
748 |
+ |
749 |
+ data = talloc_zero(handle->conn, struct freebsd_handle_data); |
750 |
+ if (!data) { |
751 |
+ saved_errno = errno; |
752 |
+ SMB_VFS_NEXT_DISCONNECT(handle); |
753 |
+ DEBUG(0, ("talloc_zero() failed\n")); |
754 |
+ errno = saved_errno; |
755 |
+ return -1; |
756 |
+ } |
757 |
+ |
758 |
+ enumval = lp_parm_enum(SNUM(handle->conn), "freebsd", |
759 |
+ "extattr mode", extattr_mode_param, FREEBSD_EXTATTR_LEGACY); |
760 |
+ if (enumval == -1) { |
761 |
+ saved_errno = errno; |
762 |
+ SMB_VFS_NEXT_DISCONNECT(handle); |
763 |
+ DBG_DEBUG("value for freebsd: 'extattr mode' is unknown\n"); |
764 |
+ errno = saved_errno; |
765 |
+ return -1; |
766 |
+ } |
767 |
+ |
768 |
+ if(freebsd_in_jail()) { |
769 |
+ enumval = FREEBSD_EXTATTR_COMPAT; |
770 |
+ DBG_WARNING("running in jail, enforcing 'compat' mode\n"); |
771 |
+ } |
772 |
+ |
773 |
+ data->extattr_mode = (enum extattr_mode)enumval; |
774 |
+ |
775 |
+ SMB_VFS_HANDLE_SET_DATA(handle, data, NULL, |
776 |
+ struct freebsd_handle_data, |
777 |
+ return -1); |
778 |
+ |
779 |
+ DBG_DEBUG("connect to service[%s] with '%s' extattr mode\n", |
780 |
+ service, extattr_mode_param[data->extattr_mode].name); |
781 |
+ |
782 |
+ return 0; |
783 |
+} |
784 |
+ |
785 |
+static void freebsd_disconnect(vfs_handle_struct *handle) |
786 |
+{ |
787 |
+ SMB_VFS_NEXT_DISCONNECT(handle); |
788 |
+} |
789 |
+ |
790 |
+/* VFS operations structure */ |
791 |
+ |
792 |
+struct vfs_fn_pointers freebsd_fns = { |
793 |
+ /* Disk operations */ |
794 |
+ |
795 |
+ .connect_fn = freebsd_connect, |
796 |
+ .disconnect_fn = freebsd_disconnect, |
797 |
+ |
798 |
+ /* EA operations. */ |
799 |
+ .getxattr_fn = freebsd_getxattr, |
800 |
+ .fgetxattr_fn = freebsd_fgetxattr, |
801 |
+ .listxattr_fn = freebsd_listxattr, |
802 |
+ .flistxattr_fn = freebsd_flistxattr, |
803 |
+ .removexattr_fn = freebsd_removexattr, |
804 |
+ .fremovexattr_fn = freebsd_fremovexattr, |
805 |
+ .setxattr_fn = freebsd_setxattr, |
806 |
+ .fsetxattr_fn = freebsd_fsetxattr, |
807 |
+}; |
808 |
+ |
809 |
+static_decl_vfs; |
810 |
+NTSTATUS vfs_freebsd_init(TALLOC_CTX *ctx) |
811 |
+{ |
812 |
+ NTSTATUS ret; |
813 |
+ |
814 |
+ ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "freebsd", |
815 |
+ &freebsd_fns); |
816 |
+ |
817 |
+ if (!NT_STATUS_IS_OK(ret)) { |
818 |
+ return ret; |
819 |
+ } |
820 |
+ |
821 |
+ vfs_freebsd_debug_level = debug_add_class("freebsd"); |
822 |
+ if (vfs_freebsd_debug_level == -1) { |
823 |
+ vfs_freebsd_debug_level = DBGC_VFS; |
824 |
+ DEBUG(0, ("vfs_freebsd: Couldn't register custom debugging class!\n")); |
825 |
+ } else { |
826 |
+ DEBUG(10, ("vfs_freebsd: Debug class number of 'fileid': %d\n", vfs_freebsd_debug_level)); |
827 |
+ } |
828 |
+ |
829 |
+ return ret; |
830 |
+} |
831 |
--- docs-xml/manpages/vfs_freebsd.8.xml.orig 2019-06-25 00:51:54 UTC |
832 |
+++ docs-xml/manpages/vfs_freebsd.8.xml |
833 |
@@ -0,0 +1,169 @@ |
834 |
+<?xml version="1.0" encoding="iso-8859-1"?> |
835 |
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc"> |
836 |
+<refentry id="vfs_freebsd.8"> |
837 |
+ |
838 |
+<refmeta> |
839 |
+ <refentrytitle>vfs_freebsd</refentrytitle> |
840 |
+ <manvolnum>8</manvolnum> |
841 |
+ <refmiscinfo class="source">Samba</refmiscinfo> |
842 |
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo> |
843 |
+ <refmiscinfo class="version">&doc.version;</refmiscinfo> |
844 |
+</refmeta> |
845 |
+ |
846 |
+<refnamediv> |
847 |
+ <refname>vfs_freebsd</refname> |
848 |
+ <refpurpose>FreeBSD-specific VFS functions</refpurpose> |
849 |
+</refnamediv> |
850 |
+ |
851 |
+<refsynopsisdiv> |
852 |
+ <cmdsynopsis> |
853 |
+ <command>vfs objects = freebsd</command> |
854 |
+ </cmdsynopsis> |
855 |
+</refsynopsisdiv> |
856 |
+ |
857 |
+<refsect1> |
858 |
+ <title>DESCRIPTION</title> |
859 |
+ |
860 |
+ <para>This VFS module is part of the <citerefentry><refentrytitle>samba</refentrytitle> |
861 |
+ <manvolnum>7</manvolnum></citerefentry> suite.</para> |
862 |
+ |
863 |
+ <para>The <command>vfs_freebsd</command> module implements some of the FreeBSD-specific VFS functions.</para> |
864 |
+ |
865 |
+ <para>This module is stackable.</para> |
866 |
+</refsect1> |
867 |
+ |
868 |
+ |
869 |
+<refsect1> |
870 |
+ <title>OPTIONS</title> |
871 |
+ |
872 |
+ <variablelist> |
873 |
+ |
874 |
+ <varlistentry> |
875 |
+ <term>freebsd:extattr mode=[legacy|compat|secure]</term> |
876 |
+ <listitem> |
877 |
+ <para>This parameter defines how the emulation of the Linux attr(5) extended attributes |
878 |
+ is performed through the FreeBSD native extattr(9) system calls.</para> |
879 |
+ |
880 |
+ <para>Currently the <emphasis>security</emphasis>, <emphasis>system</emphasis>, |
881 |
+ <emphasis>trusted</emphasis> and <emphasis>user</emphasis> extended attribute(xattr) |
882 |
+ classes are defined in Linux. Contrary FreeBSD has only <emphasis>USER</emphasis> |
883 |
+ and <emphasis>SYSTEM</emphasis> extended attribute(extattr) namespaces, so mapping |
884 |
+ of one set into another isn't straightforward and can be done in different ways.</para> |
885 |
+ |
886 |
+ <para>Historically the Samba(7) built-in xattr mapping implementation simply converted |
887 |
+ <emphasis>system</emphasis> and <emphasis>user</emphasis> xattr into corresponding |
888 |
+ <emphasis>SYSTEM</emphasis> and <emphasis>USER</emphasis> extattr namespaces, dropping |
889 |
+ the class prefix name with the separating dot and using attribute name only within the |
890 |
+ mapped namespace. It also rejected any other xattr classes, like <emphasis>security</emphasis> |
891 |
+ and <emphasis>trusted</emphasis> as invalid. Such behavior in particular broke AD |
892 |
+ provisioning on UFS2 file systems as essential <emphasis>security.NTACL</emphasis> |
893 |
+ xattr was rejected as invalid.</para> |
894 |
+ |
895 |
+ <para>This module tries to address this problem and provide secure, where it's possible, |
896 |
+ way to map Linux xattr into FreeBSD's extattr.</para> |
897 |
+ |
898 |
+ <para>When <emphasis>mode</emphasis> is set to the <emphasis>legacy (default)</emphasis> |
899 |
+ then modified version of built-in mapping is used, where <emphasis>system</emphasis> xattr |
900 |
+ is mapped into SYSTEM namespace, while <emphasis>secure</emphasis>, <emphasis>trusted</emphasis> |
901 |
+ and <emphasis>user</emphasis> xattr are all mapped into the USER namespace, dropping class |
902 |
+ prefixes and mix them all together. This is the way how Samba FreeBSD ports were patched |
903 |
+ up to the 4.9 version and that created multiple potential security issues. This mode is aimed for |
904 |
+ the compatibility with the legacy installations only and should be avoided in new setups.</para> |
905 |
+ |
906 |
+ <para>The <emphasis>compat</emphasis> mode is mostly designed for the jailed environments, |
907 |
+ where it's not possible to write extattrs into the secure SYSTEM namespace, so all four |
908 |
+ classes are mapped into the USER namespace. To preserve information about origin of the |
909 |
+ extended attribute it is stored together with the class preffix in the <emphasis>class.attribute</emphasis> |
910 |
+ format.</para> |
911 |
+ |
912 |
+ <para>The <emphasis>secure</emphasis> mode is meant for storing extended attributes in a secure |
913 |
+ manner, so that <emphasis>security</emphasis>, <emphasis>system</emphasis> and <emphasis>trusted</emphasis> |
914 |
+ are stored in the SYSTEM namespace, which can be modified only by root. |
915 |
+ </para> |
916 |
+ </listitem> |
917 |
+ </varlistentry> |
918 |
+ |
919 |
+ |
920 |
+ </variablelist> |
921 |
+</refsect1> |
922 |
+ |
923 |
+<refsect1> |
924 |
+ <table frame="all" rowheader="firstcol"> |
925 |
+ <title>Attributes mapping</title> |
926 |
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'> |
927 |
+ <thead> |
928 |
+ <row> |
929 |
+ <entry> </entry> |
930 |
+ <entry>built-in</entry> |
931 |
+ <entry>legacy</entry> |
932 |
+ <entry>compat/jail</entry> |
933 |
+ <entry>secure</entry> |
934 |
+ </row> |
935 |
+ </thead> |
936 |
+ <tbody> |
937 |
+ <row> |
938 |
+ <entry>user</entry> |
939 |
+ <entry>USER; attribute</entry> |
940 |
+ <entry>USER; attribute</entry> |
941 |
+ <entry>USER; user.attribute</entry> |
942 |
+ <entry>USER; user.attribute</entry> |
943 |
+ </row> |
944 |
+ <row> |
945 |
+ <entry>system</entry> |
946 |
+ <entry>SYSTEM; attribute</entry> |
947 |
+ <entry>SYSTEM; attribute</entry> |
948 |
+ <entry>USER; system.attribute</entry> |
949 |
+ <entry>SYSTEM; system.attribute</entry> |
950 |
+ </row> |
951 |
+ <row> |
952 |
+ <entry>trusted</entry> |
953 |
+ <entry>FAIL</entry> |
954 |
+ <entry>USER; attribute</entry> |
955 |
+ <entry>USER; trusted.attribute</entry> |
956 |
+ <entry>SYSTEM; trusted.attribute</entry> |
957 |
+ </row> |
958 |
+ <row> |
959 |
+ <entry>security</entry> |
960 |
+ <entry>FAIL</entry> |
961 |
+ <entry>USER; attribute</entry> |
962 |
+ <entry>USER; security.attribute</entry> |
963 |
+ <entry>SYSTEM; security.attribute</entry> |
964 |
+ </row> |
965 |
+ </tbody> |
966 |
+ </tgroup> |
967 |
+ </table> |
968 |
+</refsect1> |
969 |
+ |
970 |
+<refsect1> |
971 |
+ <title>EXAMPLES</title> |
972 |
+ |
973 |
+ <para>Use secure method of setting extended attributes on the share:</para> |
974 |
+ |
975 |
+<programlisting> |
976 |
+ <smbconfsection name="[sysvol]"/> |
977 |
+ <smbconfoption name="vfs objects">freebsd</smbconfoption> |
978 |
+ <smbconfoption name="freebsd:extattr mode">secure</smbconfoption> |
979 |
+</programlisting> |
980 |
+ |
981 |
+</refsect1> |
982 |
+ |
983 |
+<refsect1> |
984 |
+ <title>VERSION</title> |
985 |
+ |
986 |
+ <para>This man page is part of version &doc.version; of the Samba suite. |
987 |
+ </para> |
988 |
+</refsect1> |
989 |
+ |
990 |
+<refsect1> |
991 |
+ <title>AUTHOR</title> |
992 |
+ |
993 |
+ <para>The original Samba software and related utilities |
994 |
+ were created by Andrew Tridgell. Samba is now developed |
995 |
+ by the Samba Team as an Open Source project similar |
996 |
+ to the way the Linux kernel is developed.</para> |
997 |
+ |
998 |
+ <para>This module was written by Timur I. Bakeyev</para> |
999 |
+ |
1000 |
+</refsect1> |
1001 |
+ |
1002 |
+</refentry> |