1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Samba VFS module for GPFS filesystem
4  *  Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
5  *  Copyright (C) Christof Schmitt 2015
6  *  Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
7  *                           and Gomati Mohanan <gomati.mohanan@in.ibm.com>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "includes.h"
24 #include "smbd/smbd.h"
25 #include "include/smbprofile.h"
26 #include "modules/non_posix_acls.h"
27 #include "libcli/security/security.h"
28 #include "nfs4_acls.h"
29 #include "system/filesys.h"
30 #include "auth.h"
31 #include "lib/util/tevent_unix.h"
32 #include "lib/util/gpfswrap.h"
33 
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
36 #include "lib/crypto/gnutls_helpers.h"
37 
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_VFS
40 
41 #ifndef GPFS_GETACL_NATIVE
42 #define GPFS_GETACL_NATIVE 0x00000004
43 #endif
44 
45 struct gpfs_config_data {
46 	struct smbacl4_vfs_params nfs4_params;
47 	bool sharemodes;
48 	bool leases;
49 	bool hsm;
50 	bool syncio;
51 	bool winattr;
52 	bool ftruncate;
53 	bool getrealfilename;
54 	bool dfreequota;
55 	bool acl;
56 	bool settimes;
57 	bool recalls;
58 };
59 
60 struct gpfs_fsp_extension {
61 	bool offline;
62 };
63 
gpfs_acl_flags(gpfs_acl_t * gacl)64 static inline unsigned int gpfs_acl_flags(gpfs_acl_t *gacl)
65 {
66 	if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
67 		return gacl->v4Level1.acl_flags;
68 	}
69 	return 0;
70 }
71 
gpfs_ace_ptr(gpfs_acl_t * gacl,unsigned int i)72 static inline gpfs_ace_v4_t *gpfs_ace_ptr(gpfs_acl_t *gacl, unsigned int i)
73 {
74 	if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
75 		return &gacl->v4Level1.ace_v4[i];
76 	}
77 	return &gacl->ace_v4[i];
78 }
79 
vfs_gpfs_access_mask_to_allow(uint32_t access_mask)80 static unsigned int vfs_gpfs_access_mask_to_allow(uint32_t access_mask)
81 {
82 	unsigned int allow = GPFS_SHARE_NONE;
83 
84 	if (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) {
85 		allow |= GPFS_SHARE_WRITE;
86 	}
87 	if (access_mask & (FILE_READ_DATA|FILE_EXECUTE)) {
88 		allow |= GPFS_SHARE_READ;
89 	}
90 
91 	return allow;
92 }
93 
vfs_gpfs_share_access_to_deny(uint32_t share_access)94 static unsigned int vfs_gpfs_share_access_to_deny(uint32_t share_access)
95 {
96 	unsigned int deny = GPFS_DENY_NONE;
97 
98 	if (!(share_access & FILE_SHARE_WRITE)) {
99 		deny |= GPFS_DENY_WRITE;
100 	}
101 	if (!(share_access & FILE_SHARE_READ)) {
102 		deny |= GPFS_DENY_READ;
103 	}
104 
105 	/*
106 	 * GPFS_DENY_DELETE can only be set together with either
107 	 * GPFS_DENY_WRITE or GPFS_DENY_READ.
108 	 */
109 	if ((deny & (GPFS_DENY_WRITE|GPFS_DENY_READ)) &&
110 	    !(share_access & FILE_SHARE_DELETE)) {
111 		deny |= GPFS_DENY_DELETE;
112 	}
113 
114 	return deny;
115 }
116 
set_gpfs_sharemode(files_struct * fsp,uint32_t access_mask,uint32_t share_access)117 static int set_gpfs_sharemode(files_struct *fsp, uint32_t access_mask,
118 			      uint32_t share_access)
119 {
120 	unsigned int allow = GPFS_SHARE_NONE;
121 	unsigned int deny = GPFS_DENY_NONE;
122 	int result;
123 
124 	if (access_mask == 0) {
125 		DBG_DEBUG("Clearing file system share mode.\n");
126 	} else {
127 		allow = vfs_gpfs_access_mask_to_allow(access_mask);
128 		deny = vfs_gpfs_share_access_to_deny(share_access);
129 	}
130 	DBG_DEBUG("access_mask=0x%x, allow=0x%x, share_access=0x%x, "
131 		  "deny=0x%x\n", access_mask, allow, share_access, deny);
132 
133 	result = gpfswrap_set_share(fsp->fh->fd, allow, deny);
134 	if (result == 0) {
135 		return 0;
136 	}
137 
138 	if (errno == EACCES) {
139 		DBG_NOTICE("GPFS share mode denied for %s/%s.\n",
140 			   fsp->conn->connectpath,
141 			   fsp->fsp_name->base_name);
142 	} else if (errno == EPERM) {
143 		DBG_ERR("Samba requested GPFS sharemode for %s/%s, but the "
144 			"GPFS file system is not configured accordingly. "
145 			"Configure file system with mmchfs -D nfs4 or "
146 			"set gpfs:sharemodes=no in Samba.\n",
147 			fsp->conn->connectpath,
148 			fsp->fsp_name->base_name);
149 	} else {
150 		DBG_ERR("gpfs_set_share failed: %s\n", strerror(errno));
151 	}
152 
153 	return result;
154 }
155 
vfs_gpfs_kernel_flock(vfs_handle_struct * handle,files_struct * fsp,uint32_t share_access,uint32_t access_mask)156 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
157 				 uint32_t share_access, uint32_t access_mask)
158 {
159 
160 	struct gpfs_config_data *config;
161 	int ret = 0;
162 
163 	START_PROFILE(syscall_kernel_flock);
164 
165 	SMB_VFS_HANDLE_GET_DATA(handle, config,
166 				struct gpfs_config_data,
167 				return -1);
168 
169 	if(!config->sharemodes) {
170 		return 0;
171 	}
172 
173 	/*
174 	 * A named stream fsp will have the basefile open in the fsp
175 	 * fd, so lacking a distinct fd for the stream we have to skip
176 	 * kernel_flock and set_gpfs_sharemode for stream.
177 	 */
178 	if (is_named_stream(fsp->fsp_name)) {
179 		DBG_NOTICE("Not requesting GPFS sharemode on stream: %s/%s\n",
180 			   fsp->conn->connectpath,
181 			   fsp_str_dbg(fsp));
182 		return 0;
183 	}
184 
185 	kernel_flock(fsp->fh->fd, share_access, access_mask);
186 
187 	ret = set_gpfs_sharemode(fsp, access_mask, share_access);
188 
189 	END_PROFILE(syscall_kernel_flock);
190 
191 	return ret;
192 }
193 
vfs_gpfs_close(vfs_handle_struct * handle,files_struct * fsp)194 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
195 {
196 
197 	struct gpfs_config_data *config;
198 
199 	SMB_VFS_HANDLE_GET_DATA(handle, config,
200 				struct gpfs_config_data,
201 				return -1);
202 
203 	if (config->sharemodes && fsp->kernel_share_modes_taken) {
204 		/*
205 		 * Always clear GPFS sharemode in case the actual
206 		 * close gets deferred due to outstanding POSIX locks
207 		 * (see fd_close_posix)
208 		 */
209 		int ret = gpfswrap_set_share(fsp->fh->fd, 0, 0);
210 		if (ret != 0) {
211 			DBG_ERR("Clearing GPFS sharemode on close failed for "
212 				" %s/%s: %s\n",
213 				fsp->conn->connectpath,
214 				fsp->fsp_name->base_name,
215 				strerror(errno));
216 		}
217 	}
218 
219 	return SMB_VFS_NEXT_CLOSE(handle, fsp);
220 }
221 
set_gpfs_lease(int fd,int leasetype)222 static int set_gpfs_lease(int fd, int leasetype)
223 {
224 	int gpfs_type = GPFS_LEASE_NONE;
225 
226 	if (leasetype == F_RDLCK) {
227 		gpfs_type = GPFS_LEASE_READ;
228 	}
229 	if (leasetype == F_WRLCK) {
230 		gpfs_type = GPFS_LEASE_WRITE;
231 	}
232 
233 	/* we unconditionally set CAP_LEASE, rather than looking for
234 	   -1/EACCES as there is a bug in some versions of
235 	   libgpfs_gpl.so which results in a leaked fd on /dev/ss0
236 	   each time we try this with the wrong capabilities set
237 	*/
238 	linux_set_lease_capability();
239 	return gpfswrap_set_lease(fd, gpfs_type);
240 }
241 
vfs_gpfs_setlease(vfs_handle_struct * handle,files_struct * fsp,int leasetype)242 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp,
243 			     int leasetype)
244 {
245 	struct gpfs_config_data *config;
246 	int ret=0;
247 
248 	START_PROFILE(syscall_linux_setlease);
249 
250 	SMB_VFS_HANDLE_GET_DATA(handle, config,
251 				struct gpfs_config_data,
252 				return -1);
253 
254 	if (linux_set_lease_sighandler(fsp->fh->fd) == -1) {
255 		ret = -1;
256 		goto failure;
257 	}
258 
259 	if (config->leases) {
260 		/*
261 		 * Ensure the lease owner is root to allow
262 		 * correct delivery of lease-break signals.
263 		 */
264 		become_root();
265 		ret = set_gpfs_lease(fsp->fh->fd,leasetype);
266 		unbecome_root();
267 	}
268 
269 failure:
270 	END_PROFILE(syscall_linux_setlease);
271 
272 	return ret;
273 }
274 
vfs_gpfs_get_real_filename(struct vfs_handle_struct * handle,const char * path,const char * name,TALLOC_CTX * mem_ctx,char ** found_name)275 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
276 				      const char *path,
277 				      const char *name,
278 				      TALLOC_CTX *mem_ctx,
279 				      char **found_name)
280 {
281 	int result;
282 	char *full_path = NULL;
283 	char *to_free = NULL;
284 	char real_pathname[PATH_MAX+1], tmpbuf[PATH_MAX];
285 	size_t full_path_len;
286 	int buflen;
287 	bool mangled;
288 	struct gpfs_config_data *config;
289 
290 	SMB_VFS_HANDLE_GET_DATA(handle, config,
291 				struct gpfs_config_data,
292 				return -1);
293 
294 	if (!config->getrealfilename) {
295 		return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
296 						      mem_ctx, found_name);
297 	}
298 
299 	mangled = mangle_is_mangled(name, handle->conn->params);
300 	if (mangled) {
301 		return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
302 						      mem_ctx, found_name);
303 	}
304 
305 	full_path_len = full_path_tos(path, name, tmpbuf, sizeof(tmpbuf),
306 				      &full_path, &to_free);
307 	if (full_path_len == -1) {
308 		errno = ENOMEM;
309 		return -1;
310 	}
311 
312 	buflen = sizeof(real_pathname) - 1;
313 
314 	result = gpfswrap_get_realfilename_path(full_path, real_pathname,
315 						&buflen);
316 
317 	TALLOC_FREE(to_free);
318 
319 	if ((result == -1) && (errno == ENOSYS)) {
320 		return SMB_VFS_NEXT_GET_REAL_FILENAME(
321 			handle, path, name, mem_ctx, found_name);
322 	}
323 
324 	if (result == -1) {
325 		DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
326 			   strerror(errno)));
327 		return -1;
328 	}
329 
330 	/*
331 	 * GPFS does not necessarily null-terminate the returned path
332 	 * but instead returns the buffer length in buflen.
333 	 */
334 
335 	if (buflen < sizeof(real_pathname)) {
336 		real_pathname[buflen] = '\0';
337 	} else {
338 		real_pathname[sizeof(real_pathname)-1] = '\0';
339 	}
340 
341 	DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
342 		   path, name, real_pathname));
343 
344 	name = strrchr_m(real_pathname, '/');
345 	if (name == NULL) {
346 		errno = ENOENT;
347 		return -1;
348 	}
349 
350 	*found_name = talloc_strdup(mem_ctx, name+1);
351 	if (*found_name == NULL) {
352 		errno = ENOMEM;
353 		return -1;
354 	}
355 
356 	return 0;
357 }
358 
sd2gpfs_control(uint16_t control,struct gpfs_acl * gacl)359 static void sd2gpfs_control(uint16_t control, struct gpfs_acl *gacl)
360 {
361 	unsigned int gpfs_aclflags = 0;
362 	control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
363 		SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
364 		SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
365 		SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
366 	gpfs_aclflags = control << 8;
367 	if (!(control & SEC_DESC_DACL_PRESENT))
368 		gpfs_aclflags |= ACL4_FLAG_NULL_DACL;
369 	if (!(control & SEC_DESC_SACL_PRESENT))
370 		gpfs_aclflags |= ACL4_FLAG_NULL_SACL;
371 	gacl->acl_level = GPFS_ACL_LEVEL_V4FLAGS;
372 	gacl->v4Level1.acl_flags = gpfs_aclflags;
373 }
374 
gpfs2sd_control(unsigned int gpfs_aclflags)375 static uint16_t gpfs2sd_control(unsigned int gpfs_aclflags)
376 {
377 	uint16_t control = gpfs_aclflags >> 8;
378 	control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
379 		SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
380 		SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
381 		SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
382 	control |= SEC_DESC_SELF_RELATIVE;
383 	return control;
384 }
385 
gpfs_dumpacl(int level,struct gpfs_acl * gacl)386 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
387 {
388 	gpfs_aclCount_t i;
389 	if (gacl==NULL)
390 	{
391 		DEBUG(0, ("gpfs acl is NULL\n"));
392 		return;
393 	}
394 
395 	DEBUG(level, ("len: %d, level: %d, version: %d, nace: %d, "
396 		      "control: %x\n",
397 		      gacl->acl_len, gacl->acl_level, gacl->acl_version,
398 		      gacl->acl_nace, gpfs_acl_flags(gacl)));
399 
400 	for(i=0; i<gacl->acl_nace; i++)
401 	{
402 		struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
403 		DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, "
404 			      "iflags:0x%x, who:%u\n",
405 			      i, gace->aceType, gace->aceFlags, gace->aceMask,
406 			      gace->aceIFlags, gace->aceWho));
407 	}
408 }
409 
gpfs_getacl_with_capability(const char * fname,int flags,void * buf)410 static int gpfs_getacl_with_capability(const char *fname, int flags, void *buf)
411 {
412 	int ret, saved_errno;
413 
414 	set_effective_capability(DAC_OVERRIDE_CAPABILITY);
415 
416 	ret = gpfswrap_getacl(discard_const_p(char, fname), flags, buf);
417 	saved_errno = errno;
418 
419 	drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
420 
421 	errno = saved_errno;
422 	return ret;
423 }
424 
425 /*
426  * get the ACL from GPFS, allocated on the specified mem_ctx
427  * internally retries when initial buffer was too small
428  *
429  * caller needs to cast result to either
430  * raw = yes: struct gpfs_opaque_acl
431  * raw = no: struct gpfs_acl
432  *
433  */
vfs_gpfs_getacl(TALLOC_CTX * mem_ctx,const char * fname,const bool raw,const gpfs_aclType_t type)434 static void *vfs_gpfs_getacl(TALLOC_CTX *mem_ctx,
435 			 const char *fname,
436 			 const bool raw,
437 			 const gpfs_aclType_t type)
438 {
439 
440 	void *aclbuf;
441 	size_t size = 512;
442 	int ret, flags;
443 	unsigned int *len;
444 	size_t struct_size;
445 	bool use_capability = false;
446 
447 again:
448 
449 	aclbuf = talloc_zero_size(mem_ctx, size);
450 	if (aclbuf == NULL) {
451 		errno = ENOMEM;
452 		return NULL;
453 	}
454 
455 	if (raw) {
456 		struct gpfs_opaque_acl *buf = (struct gpfs_opaque_acl *) aclbuf;
457 		buf->acl_type = type;
458 		flags = GPFS_GETACL_NATIVE;
459 		len = (unsigned int *) &(buf->acl_buffer_len);
460 		struct_size = sizeof(struct gpfs_opaque_acl);
461 	} else {
462 		struct gpfs_acl *buf = (struct gpfs_acl *) aclbuf;
463 		buf->acl_type = type;
464 		buf->acl_level = GPFS_ACL_LEVEL_V4FLAGS;
465 		flags = GPFS_GETACL_STRUCT;
466 		len = &(buf->acl_len);
467 		/* reserve space for control flags in gpfs 3.5 and beyond */
468 		struct_size = sizeof(struct gpfs_acl) + sizeof(unsigned int);
469 	}
470 
471 	/* set the length of the buffer as input value */
472 	*len = size;
473 
474 	if (use_capability) {
475 		ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
476 	} else {
477 		ret = gpfswrap_getacl(discard_const_p(char, fname),
478 				      flags, aclbuf);
479 		if ((ret != 0) && (errno == EACCES)) {
480 			DBG_DEBUG("Retry with DAC capability for %s\n", fname);
481 			use_capability = true;
482 			ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
483 		}
484 	}
485 
486 	if ((ret != 0) && (errno == ENOSPC)) {
487 		/*
488 		 * get the size needed to accommodate the complete buffer
489 		 *
490 		 * the value returned only applies to the ACL blob in the
491 		 * struct so make sure to also have headroom for the first
492 		 * struct members by adding room for the complete struct
493 		 * (might be a few bytes too much then)
494 		 */
495 		size = *len + struct_size;
496 		talloc_free(aclbuf);
497 		DEBUG(10, ("Increasing ACL buffer size to %zu\n", size));
498 		goto again;
499 	}
500 
501 	if (ret != 0) {
502 		DEBUG(5, ("smbd_gpfs_getacl failed with %s\n",
503 			  strerror(errno)));
504 		talloc_free(aclbuf);
505 		return NULL;
506 	}
507 
508 	return aclbuf;
509 }
510 
511 /* Tries to get nfs4 acls and returns SMB ACL allocated.
512  * On failure returns 1 if it got non-NFSv4 ACL to prompt
513  * retry with POSIX ACL checks.
514  * On failure returns -1 if there is system (GPFS) error, check errno.
515  * Returns 0 on success
516  */
gpfs_get_nfs4_acl(TALLOC_CTX * mem_ctx,const char * fname,struct SMB4ACL_T ** ppacl)517 static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname,
518 			     struct SMB4ACL_T **ppacl)
519 {
520 	gpfs_aclCount_t i;
521 	struct gpfs_acl *gacl = NULL;
522 	DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
523 
524 	/* Get the ACL */
525 	gacl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(), fname,
526 						  false, 0);
527 	if (gacl == NULL) {
528 		DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
529 			   fname, strerror(errno)));
530 		if (errno == ENODATA) {
531 			/*
532 			 * GPFS returns ENODATA for snapshot
533 			 * directories. Retry with POSIX ACLs check.
534 			 */
535 			return 1;
536 		}
537 
538 		return -1;
539 	}
540 
541 	if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
542 		DEBUG(10, ("Got non-nfsv4 acl\n"));
543 		/* Retry with POSIX ACLs check */
544 		talloc_free(gacl);
545 		return 1;
546 	}
547 
548 	*ppacl = smb_create_smb4acl(mem_ctx);
549 
550 	if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
551 		uint16_t control = gpfs2sd_control(gpfs_acl_flags(gacl));
552 		smbacl4_set_controlflags(*ppacl, control);
553 	}
554 
555 	DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d, control: %x\n",
556 		   gacl->acl_len, gacl->acl_level, gacl->acl_version,
557 		   gacl->acl_nace, gpfs_acl_flags(gacl)));
558 
559 	for (i=0; i<gacl->acl_nace; i++) {
560 		struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
561 		SMB_ACE4PROP_T smbace = { 0 };
562 		DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
563 			   "who: %d\n", gace->aceType, gace->aceIFlags,
564 			   gace->aceFlags, gace->aceMask, gace->aceWho));
565 
566 		if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
567 			smbace.flags |= SMB_ACE4_ID_SPECIAL;
568 			switch (gace->aceWho) {
569 			case ACE4_SPECIAL_OWNER:
570 				smbace.who.special_id = SMB_ACE4_WHO_OWNER;
571 				break;
572 			case ACE4_SPECIAL_GROUP:
573 				smbace.who.special_id = SMB_ACE4_WHO_GROUP;
574 				break;
575 			case ACE4_SPECIAL_EVERYONE:
576 				smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
577 				break;
578 			default:
579 				DEBUG(8, ("invalid special gpfs id %d "
580 					  "ignored\n", gace->aceWho));
581 				continue; /* don't add it */
582 			}
583 		} else {
584 			if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
585 				smbace.who.gid = gace->aceWho;
586 			else
587 				smbace.who.uid = gace->aceWho;
588 		}
589 
590 		/* remove redundant deny entries */
591 		if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
592 			struct gpfs_ace_v4 *prev = gpfs_ace_ptr(gacl, i - 1);
593 			if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
594 			    prev->aceFlags == gace->aceFlags &&
595 			    prev->aceIFlags == gace->aceIFlags &&
596 			    (gace->aceMask & prev->aceMask) == 0 &&
597 			    gace->aceWho == prev->aceWho) {
598 				/* it's redundant - skip it */
599 				continue;
600 			}
601 		}
602 
603 		smbace.aceType = gace->aceType;
604 		smbace.aceFlags = gace->aceFlags;
605 		smbace.aceMask = gace->aceMask;
606 		smb_add_ace4(*ppacl, &smbace);
607 	}
608 
609 	talloc_free(gacl);
610 
611 	return 0;
612 }
613 
gpfsacl_fget_nt_acl(vfs_handle_struct * handle,files_struct * fsp,uint32_t security_info,TALLOC_CTX * mem_ctx,struct security_descriptor ** ppdesc)614 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
615 	files_struct *fsp, uint32_t security_info,
616 	TALLOC_CTX *mem_ctx,
617 	struct security_descriptor **ppdesc)
618 {
619 	struct SMB4ACL_T *pacl = NULL;
620 	int	result;
621 	struct gpfs_config_data *config;
622 	TALLOC_CTX *frame = talloc_stackframe();
623 	NTSTATUS status;
624 
625 	*ppdesc = NULL;
626 
627 	SMB_VFS_HANDLE_GET_DATA(handle, config,
628 				struct gpfs_config_data,
629 				return NT_STATUS_INTERNAL_ERROR);
630 
631 	if (!config->acl) {
632 		status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
633 						  mem_ctx, ppdesc);
634 		TALLOC_FREE(frame);
635 		return status;
636 	}
637 
638 	result = gpfs_get_nfs4_acl(frame, fsp->fsp_name->base_name, &pacl);
639 
640 	if (result == 0) {
641 		status = smb_fget_nt_acl_nfs4(fsp, &config->nfs4_params,
642 					      security_info,
643 					      mem_ctx, ppdesc, pacl);
644 		TALLOC_FREE(frame);
645 		return status;
646 	}
647 
648 	if (result > 0) {
649 		DEBUG(10, ("retrying with posix acl...\n"));
650 		status = posix_fget_nt_acl(fsp, security_info,
651 					   mem_ctx, ppdesc);
652 		TALLOC_FREE(frame);
653 		return status;
654 	}
655 
656 	TALLOC_FREE(frame);
657 
658 	/* GPFS ACL was not read, something wrong happened, error code is set in errno */
659 	return map_nt_error_from_unix(errno);
660 }
661 
gpfsacl_get_nt_acl(vfs_handle_struct * handle,const struct smb_filename * smb_fname,uint32_t security_info,TALLOC_CTX * mem_ctx,struct security_descriptor ** ppdesc)662 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
663 				   const struct smb_filename *smb_fname,
664 				   uint32_t security_info,
665 				   TALLOC_CTX *mem_ctx,
666 				   struct security_descriptor **ppdesc)
667 {
668 	struct SMB4ACL_T *pacl = NULL;
669 	int	result;
670 	struct gpfs_config_data *config;
671 	TALLOC_CTX *frame = talloc_stackframe();
672 	NTSTATUS status;
673 
674 	*ppdesc = NULL;
675 
676 	SMB_VFS_HANDLE_GET_DATA(handle, config,
677 				struct gpfs_config_data,
678 				return NT_STATUS_INTERNAL_ERROR);
679 
680 	if (!config->acl) {
681 		status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
682 						 security_info,
683 						 mem_ctx, ppdesc);
684 		TALLOC_FREE(frame);
685 		return status;
686 	}
687 
688 	result = gpfs_get_nfs4_acl(frame, smb_fname->base_name, &pacl);
689 
690 	if (result == 0) {
691 		status = smb_get_nt_acl_nfs4(handle->conn, smb_fname,
692 					     &config->nfs4_params,
693 					     security_info, mem_ctx, ppdesc,
694 					     pacl);
695 		TALLOC_FREE(frame);
696 		return status;
697 	}
698 
699 	if (result > 0) {
700 		DEBUG(10, ("retrying with posix acl...\n"));
701 		status = posix_get_nt_acl(handle->conn, smb_fname,
702 					  security_info, mem_ctx, ppdesc);
703 		TALLOC_FREE(frame);
704 		return status;
705 	}
706 
707 	/* GPFS ACL was not read, something wrong happened, error code is set in errno */
708 	TALLOC_FREE(frame);
709 	return map_nt_error_from_unix(errno);
710 }
711 
vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T * nfs4_ace,struct gpfs_ace_v4 * gace,uid_t owner_uid)712 static bool vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T *nfs4_ace,
713 					  struct gpfs_ace_v4 *gace,
714 					  uid_t owner_uid)
715 {
716 	gace->aceType = nfs4_ace->aceType;
717 	gace->aceFlags = nfs4_ace->aceFlags;
718 	gace->aceMask = nfs4_ace->aceMask;
719 
720 	if (nfs4_ace->flags & SMB_ACE4_ID_SPECIAL) {
721 		switch(nfs4_ace->who.special_id) {
722 		case SMB_ACE4_WHO_EVERYONE:
723 			gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID;
724 			gace->aceWho = ACE4_SPECIAL_EVERYONE;
725 			break;
726 		case SMB_ACE4_WHO_OWNER:
727 			/*
728 			 * With GPFS it is not possible to deny ACL or
729 			 * attribute access to the owner. Setting an
730 			 * ACL with such an entry is not possible.
731 			 * Denying ACL or attribute access for the
732 			 * owner through a named ACL entry can be
733 			 * stored in an ACL, it is just not effective.
734 			 *
735 			 * Map this case to a named entry to allow at
736 			 * least setting this ACL, which will be
737 			 * enforced by the smbd permission check. Do
738 			 * not do this for an inheriting OWNER entry,
739 			 * as this represents a CREATOR OWNER ACE. The
740 			 * remaining limitation is that CREATOR OWNER
741 			 * cannot deny ACL or attribute access.
742 			 */
743 			if (!nfs_ace_is_inherit(nfs4_ace) &&
744 			    nfs4_ace->aceType ==
745 					SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
746 			    nfs4_ace->aceMask & (SMB_ACE4_READ_ATTRIBUTES|
747 						 SMB_ACE4_WRITE_ATTRIBUTES|
748 						 SMB_ACE4_READ_ACL|
749 						 SMB_ACE4_WRITE_ACL)) {
750 				gace->aceIFlags = 0;
751 				gace->aceWho = owner_uid;
752 			} else {
753 				gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID;
754 				gace->aceWho = ACE4_SPECIAL_OWNER;
755 			}
756 			break;
757 		case SMB_ACE4_WHO_GROUP:
758 			gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID;
759 			gace->aceWho = ACE4_SPECIAL_GROUP;
760 			break;
761 		default:
762 			DBG_WARNING("Unsupported special_id %d\n",
763 				    nfs4_ace->who.special_id);
764 			return false;
765 		}
766 
767 		return true;
768 	}
769 
770 	gace->aceIFlags = 0;
771 	gace->aceWho = (nfs4_ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) ?
772 		nfs4_ace->who.gid : nfs4_ace->who.uid;
773 
774 	return true;
775 }
776 
vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX * mem_ctx,files_struct * fsp,struct SMB4ACL_T * smbacl,bool controlflags)777 static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx,
778 						files_struct *fsp,
779 						struct SMB4ACL_T *smbacl,
780 						bool controlflags)
781 {
782 	struct gpfs_acl *gacl;
783 	gpfs_aclLen_t gacl_len;
784 	struct SMB4ACE_T *smbace;
785 
786 	gacl_len = offsetof(gpfs_acl_t, ace_v4) + sizeof(unsigned int)
787 		+ smb_get_naces(smbacl) * sizeof(gpfs_ace_v4_t);
788 
789 	gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
790 	if (gacl == NULL) {
791 		DEBUG(0, ("talloc failed\n"));
792 		errno = ENOMEM;
793 		return NULL;
794 	}
795 
796 	gacl->acl_level = GPFS_ACL_LEVEL_BASE;
797 	gacl->acl_version = GPFS_ACL_VERSION_NFS4;
798 	gacl->acl_type = GPFS_ACL_TYPE_NFS4;
799 	gacl->acl_nace = 0; /* change later... */
800 
801 	if (controlflags) {
802 		gacl->acl_level = GPFS_ACL_LEVEL_V4FLAGS;
803 		sd2gpfs_control(smbacl4_get_controlflags(smbacl), gacl);
804 	}
805 
806 	for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
807 		struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, gacl->acl_nace);
808 		SMB_ACE4PROP_T	*aceprop = smb_get_ace4(smbace);
809 		bool add_ace;
810 
811 		add_ace = vfs_gpfs_nfs4_ace_to_gpfs_ace(aceprop, gace,
812 							fsp->fsp_name->st.st_ex_uid);
813 		if (!add_ace) {
814 			continue;
815 		}
816 
817 		gacl->acl_nace++;
818 	}
819 	gacl->acl_len = (char *)gpfs_ace_ptr(gacl, gacl->acl_nace)
820 		- (char *)gacl;
821 	return gacl;
822 }
823 
gpfsacl_process_smbacl(vfs_handle_struct * handle,files_struct * fsp,struct SMB4ACL_T * smbacl)824 static bool gpfsacl_process_smbacl(vfs_handle_struct *handle,
825 				   files_struct *fsp,
826 				   struct SMB4ACL_T *smbacl)
827 {
828 	int ret;
829 	struct gpfs_acl *gacl;
830 	TALLOC_CTX *mem_ctx = talloc_tos();
831 
832 	gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, true);
833 	if (gacl == NULL) { /* out of memory */
834 		return False;
835 	}
836 	ret = gpfswrap_putacl(fsp->fsp_name->base_name,
837 			      GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
838 
839 	if ((ret != 0) && (errno == EINVAL)) {
840 		DEBUG(10, ("Retry without nfs41 control flags\n"));
841 		talloc_free(gacl);
842 		gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, false);
843 		if (gacl == NULL) { /* out of memory */
844 			return False;
845 		}
846 		ret = gpfswrap_putacl(fsp->fsp_name->base_name,
847 				      GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA,
848 				      gacl);
849 	}
850 
851 	if (ret != 0) {
852 		DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
853 		gpfs_dumpacl(8, gacl);
854 		return False;
855 	}
856 
857 	DEBUG(10, ("gpfs_putacl succeeded\n"));
858 	return True;
859 }
860 
gpfsacl_set_nt_acl_internal(vfs_handle_struct * handle,files_struct * fsp,uint32_t security_info_sent,const struct security_descriptor * psd)861 static NTSTATUS gpfsacl_set_nt_acl_internal(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
862 {
863 	struct gpfs_acl *acl;
864 	NTSTATUS result = NT_STATUS_ACCESS_DENIED;
865 
866 	acl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(),
867 						 fsp->fsp_name->base_name,
868 						 false, 0);
869 	if (acl == NULL) {
870 		return map_nt_error_from_unix(errno);
871 	}
872 
873 	if (acl->acl_version == GPFS_ACL_VERSION_NFS4) {
874 		struct gpfs_config_data *config;
875 
876 		if (lp_parm_bool(fsp->conn->params->service, "gpfs",
877 				 "refuse_dacl_protected", false)
878 		    && (psd->type&SEC_DESC_DACL_PROTECTED)) {
879 			DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
880 			talloc_free(acl);
881 			return NT_STATUS_NOT_SUPPORTED;
882 		}
883 
884 		SMB_VFS_HANDLE_GET_DATA(handle, config,
885 					struct gpfs_config_data,
886 					return NT_STATUS_INTERNAL_ERROR);
887 
888 		result = smb_set_nt_acl_nfs4(handle,
889 			fsp, &config->nfs4_params, security_info_sent, psd,
890 			gpfsacl_process_smbacl);
891 	} else { /* assume POSIX ACL - by default... */
892 		result = set_nt_acl(fsp, security_info_sent, psd);
893 	}
894 
895 	talloc_free(acl);
896 	return result;
897 }
898 
gpfsacl_fset_nt_acl(vfs_handle_struct * handle,files_struct * fsp,uint32_t security_info_sent,const struct security_descriptor * psd)899 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
900 {
901 	struct gpfs_config_data *config;
902 
903 	SMB_VFS_HANDLE_GET_DATA(handle, config,
904 				struct gpfs_config_data,
905 				return NT_STATUS_INTERNAL_ERROR);
906 
907 	if (!config->acl) {
908 		return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
909 	}
910 
911 	return gpfsacl_set_nt_acl_internal(handle, fsp, security_info_sent, psd);
912 }
913 
gpfs2smb_acl(const struct gpfs_acl * pacl,TALLOC_CTX * mem_ctx)914 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl, TALLOC_CTX *mem_ctx)
915 {
916 	SMB_ACL_T result;
917 	gpfs_aclCount_t i;
918 
919 	result = sys_acl_init(mem_ctx);
920 	if (result == NULL) {
921 		errno = ENOMEM;
922 		return NULL;
923 	}
924 
925 	result->count = pacl->acl_nace;
926 	result->acl = talloc_realloc(result, result->acl, struct smb_acl_entry,
927 				     result->count);
928 	if (result->acl == NULL) {
929 		TALLOC_FREE(result);
930 		errno = ENOMEM;
931 		return NULL;
932 	}
933 
934 	for (i=0; i<pacl->acl_nace; i++) {
935 		struct smb_acl_entry *ace = &result->acl[i];
936 		const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
937 
938 		DEBUG(10, ("Converting type %d id %lu perm %x\n",
939 			   (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
940 			   (int)g_ace->ace_perm));
941 
942 		switch (g_ace->ace_type) {
943 		case GPFS_ACL_USER:
944 			ace->a_type = SMB_ACL_USER;
945 			ace->info.user.uid = (uid_t)g_ace->ace_who;
946 			break;
947 		case GPFS_ACL_USER_OBJ:
948 			ace->a_type = SMB_ACL_USER_OBJ;
949 			break;
950 		case GPFS_ACL_GROUP:
951 			ace->a_type = SMB_ACL_GROUP;
952 			ace->info.group.gid = (gid_t)g_ace->ace_who;
953 			break;
954 		case GPFS_ACL_GROUP_OBJ:
955  			ace->a_type = SMB_ACL_GROUP_OBJ;
956 			break;
957 		case GPFS_ACL_OTHER:
958 			ace->a_type = SMB_ACL_OTHER;
959 			break;
960 		case GPFS_ACL_MASK:
961 			ace->a_type = SMB_ACL_MASK;
962 			break;
963 		default:
964 			DEBUG(10, ("Got invalid ace_type: %d\n",
965 				   g_ace->ace_type));
966 			TALLOC_FREE(result);
967 			errno = EINVAL;
968 			return NULL;
969 		}
970 
971 		ace->a_perm = 0;
972 		ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
973 			SMB_ACL_READ : 0;
974 		ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
975 			SMB_ACL_WRITE : 0;
976 		ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
977 			SMB_ACL_EXECUTE : 0;
978 
979 		DEBUGADD(10, ("Converted to %d perm %x\n",
980 			      ace->a_type, ace->a_perm));
981 	}
982 
983 	return result;
984 }
985 
gpfsacl_get_posix_acl(const char * path,gpfs_aclType_t type,TALLOC_CTX * mem_ctx)986 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type,
987 				       TALLOC_CTX *mem_ctx)
988 {
989 	struct gpfs_acl *pacl;
990 	SMB_ACL_T result = NULL;
991 
992 	pacl = vfs_gpfs_getacl(talloc_tos(), path, false, type);
993 
994 	if (pacl == NULL) {
995 		DEBUG(10, ("vfs_gpfs_getacl failed for %s with %s\n",
996 			   path, strerror(errno)));
997 		if (errno == 0) {
998 			errno = EINVAL;
999 		}
1000 		goto done;
1001 	}
1002 
1003 	if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
1004 		DEBUG(10, ("Got acl version %d, expected %d\n",
1005 			   pacl->acl_version, GPFS_ACL_VERSION_POSIX));
1006 		errno = EINVAL;
1007 		goto done;
1008 	}
1009 
1010 	DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
1011 		   pacl->acl_len, pacl->acl_level, pacl->acl_version,
1012 		   pacl->acl_nace));
1013 
1014 	result = gpfs2smb_acl(pacl, mem_ctx);
1015 	if (result != NULL) {
1016 		errno = 0;
1017 	}
1018 
1019  done:
1020 
1021 	if (pacl != NULL) {
1022 		talloc_free(pacl);
1023 	}
1024 	if (errno != 0) {
1025 		TALLOC_FREE(result);
1026 	}
1027 	return result;
1028 }
1029 
gpfsacl_sys_acl_get_file(vfs_handle_struct * handle,const struct smb_filename * smb_fname,SMB_ACL_TYPE_T type,TALLOC_CTX * mem_ctx)1030 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
1031 					  const struct smb_filename *smb_fname,
1032 					  SMB_ACL_TYPE_T type,
1033 					  TALLOC_CTX *mem_ctx)
1034 {
1035 	gpfs_aclType_t gpfs_type;
1036 	struct gpfs_config_data *config;
1037 
1038 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1039 				struct gpfs_config_data,
1040 				return NULL);
1041 
1042 	if (!config->acl) {
1043 		return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
1044 						     type, mem_ctx);
1045 	}
1046 
1047 	switch(type) {
1048 	case SMB_ACL_TYPE_ACCESS:
1049 		gpfs_type = GPFS_ACL_TYPE_ACCESS;
1050 		break;
1051 	case SMB_ACL_TYPE_DEFAULT:
1052 		gpfs_type = GPFS_ACL_TYPE_DEFAULT;
1053 		break;
1054 	default:
1055 		DEBUG(0, ("Got invalid type: %d\n", type));
1056 		smb_panic("exiting");
1057 	}
1058 
1059 	return gpfsacl_get_posix_acl(smb_fname->base_name, gpfs_type, mem_ctx);
1060 }
1061 
gpfsacl_sys_acl_get_fd(vfs_handle_struct * handle,files_struct * fsp,TALLOC_CTX * mem_ctx)1062 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
1063 					files_struct *fsp,
1064 					TALLOC_CTX *mem_ctx)
1065 {
1066 	struct gpfs_config_data *config;
1067 
1068 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1069 				struct gpfs_config_data,
1070 				return NULL);
1071 
1072 	if (!config->acl) {
1073 		return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
1074 	}
1075 
1076 	return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
1077 				     GPFS_ACL_TYPE_ACCESS, mem_ctx);
1078 }
1079 
gpfsacl_sys_acl_blob_get_file(vfs_handle_struct * handle,const struct smb_filename * smb_fname,TALLOC_CTX * mem_ctx,char ** blob_description,DATA_BLOB * blob)1080 static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
1081 				      const struct smb_filename *smb_fname,
1082 				      TALLOC_CTX *mem_ctx,
1083 				      char **blob_description,
1084 				      DATA_BLOB *blob)
1085 {
1086 	struct gpfs_config_data *config;
1087 	struct gpfs_opaque_acl *acl = NULL;
1088 	DATA_BLOB aclblob;
1089 	int result;
1090 	const char *path_p = smb_fname->base_name;
1091 
1092 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1093 				struct gpfs_config_data,
1094 				return -1);
1095 
1096 	if (!config->acl) {
1097 		return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle, smb_fname,
1098 							  mem_ctx,
1099 							  blob_description,
1100 							  blob);
1101 	}
1102 
1103 	errno = 0;
1104 	acl = (struct gpfs_opaque_acl *)
1105 			vfs_gpfs_getacl(mem_ctx,
1106 					path_p,
1107 					true,
1108 					GPFS_ACL_TYPE_NFS4);
1109 
1110 	if (errno) {
1111 		DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
1112 					errno, strerror(errno)));
1113 
1114 		/* EINVAL means POSIX ACL, bail out on other cases */
1115 		if (errno != EINVAL) {
1116 			return -1;
1117 		}
1118 	}
1119 
1120 	if (acl != NULL) {
1121 		/*
1122 		 * file has NFSv4 ACL
1123 		 *
1124 		 * we only need the actual ACL blob here
1125 		 * acl_version will always be NFS4 because we asked
1126 		 * for NFS4
1127 		 * acl_type is only used for POSIX ACLs
1128 		 */
1129 		aclblob.data = (uint8_t*) acl->acl_var_data;
1130 		aclblob.length = acl->acl_buffer_len;
1131 
1132 		*blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
1133 		if (!*blob_description) {
1134 			talloc_free(acl);
1135 			errno = ENOMEM;
1136 			return -1;
1137 		}
1138 
1139 		result = non_posix_sys_acl_blob_get_file_helper(handle, smb_fname,
1140 								aclblob,
1141 								mem_ctx, blob);
1142 
1143 		talloc_free(acl);
1144 		return result;
1145 	}
1146 
1147 	/* fall back to POSIX ACL */
1148 	return posix_sys_acl_blob_get_file(handle, smb_fname, mem_ctx,
1149 					   blob_description, blob);
1150 }
1151 
gpfsacl_sys_acl_blob_get_fd(vfs_handle_struct * handle,files_struct * fsp,TALLOC_CTX * mem_ctx,char ** blob_description,DATA_BLOB * blob)1152 static int gpfsacl_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1153 				      files_struct *fsp,
1154 				      TALLOC_CTX *mem_ctx,
1155 				      char **blob_description,
1156 				      DATA_BLOB *blob)
1157 {
1158 	struct gpfs_config_data *config;
1159 	struct gpfs_opaque_acl *acl = NULL;
1160 	DATA_BLOB aclblob;
1161 	int result;
1162 
1163 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1164 				struct gpfs_config_data,
1165 				return -1);
1166 
1167 	if (!config->acl) {
1168 		return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1169 							blob_description, blob);
1170 	}
1171 
1172 	errno = 0;
1173 	acl = (struct gpfs_opaque_acl *) vfs_gpfs_getacl(mem_ctx,
1174 						fsp->fsp_name->base_name,
1175 						true,
1176 						GPFS_ACL_TYPE_NFS4);
1177 
1178 	if (errno) {
1179 		DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
1180 					errno, strerror(errno)));
1181 
1182 		/* EINVAL means POSIX ACL, bail out on other cases */
1183 		if (errno != EINVAL) {
1184 			return -1;
1185 		}
1186 	}
1187 
1188 	if (acl != NULL) {
1189 		/*
1190 		 * file has NFSv4 ACL
1191 		 *
1192 		 * we only need the actual ACL blob here
1193 		 * acl_version will always be NFS4 because we asked
1194 		 * for NFS4
1195 		 * acl_type is only used for POSIX ACLs
1196 		 */
1197 		aclblob.data = (uint8_t*) acl->acl_var_data;
1198 		aclblob.length = acl->acl_buffer_len;
1199 
1200 		*blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
1201 		if (!*blob_description) {
1202 			talloc_free(acl);
1203 			errno = ENOMEM;
1204 			return -1;
1205 		}
1206 
1207 		result = non_posix_sys_acl_blob_get_fd_helper(handle, fsp,
1208 							      aclblob, mem_ctx,
1209 							      blob);
1210 
1211 		talloc_free(acl);
1212 		return result;
1213 	}
1214 
1215 	/* fall back to POSIX ACL */
1216 	return posix_sys_acl_blob_get_fd(handle, fsp, mem_ctx,
1217 					 blob_description, blob);
1218 }
1219 
smb2gpfs_acl(const SMB_ACL_T pacl,SMB_ACL_TYPE_T type)1220 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
1221 				     SMB_ACL_TYPE_T type)
1222 {
1223 	gpfs_aclLen_t len;
1224 	struct gpfs_acl *result;
1225 	int i;
1226 
1227 	DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
1228 
1229 	len = offsetof(gpfs_acl_t, ace_v1) + (pacl->count) *
1230 		sizeof(gpfs_ace_v1_t);
1231 
1232 	result = (struct gpfs_acl *)SMB_MALLOC(len);
1233 	if (result == NULL) {
1234 		errno = ENOMEM;
1235 		return result;
1236 	}
1237 
1238 	result->acl_len = len;
1239 	result->acl_level = 0;
1240 	result->acl_version = GPFS_ACL_VERSION_POSIX;
1241 	result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
1242 		GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
1243 	result->acl_nace = pacl->count;
1244 
1245 	for (i=0; i<pacl->count; i++) {
1246 		const struct smb_acl_entry *ace = &pacl->acl[i];
1247 		struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
1248 
1249 		DEBUG(10, ("Converting type %d perm %x\n",
1250 			   (int)ace->a_type, (int)ace->a_perm));
1251 
1252 		g_ace->ace_perm = 0;
1253 
1254 		switch(ace->a_type) {
1255 		case SMB_ACL_USER:
1256 			g_ace->ace_type = GPFS_ACL_USER;
1257 			g_ace->ace_who = (gpfs_uid_t)ace->info.user.uid;
1258 			break;
1259 		case SMB_ACL_USER_OBJ:
1260 			g_ace->ace_type = GPFS_ACL_USER_OBJ;
1261 			g_ace->ace_perm |= ACL_PERM_CONTROL;
1262 			g_ace->ace_who = 0;
1263 			break;
1264 		case SMB_ACL_GROUP:
1265 			g_ace->ace_type = GPFS_ACL_GROUP;
1266 			g_ace->ace_who = (gpfs_uid_t)ace->info.group.gid;
1267 			break;
1268 		case SMB_ACL_GROUP_OBJ:
1269 			g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
1270 			g_ace->ace_who = 0;
1271 			break;
1272 		case SMB_ACL_MASK:
1273 			g_ace->ace_type = GPFS_ACL_MASK;
1274 			g_ace->ace_perm = 0x8f;
1275 			g_ace->ace_who = 0;
1276 			break;
1277 		case SMB_ACL_OTHER:
1278 			g_ace->ace_type = GPFS_ACL_OTHER;
1279 			g_ace->ace_who = 0;
1280 			break;
1281 		default:
1282 			DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
1283 			errno = EINVAL;
1284 			SAFE_FREE(result);
1285 			return NULL;
1286 		}
1287 
1288 		g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
1289 			ACL_PERM_READ : 0;
1290 		g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
1291 			ACL_PERM_WRITE : 0;
1292 		g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
1293 			ACL_PERM_EXECUTE : 0;
1294 
1295 		DEBUGADD(10, ("Converted to %d id %d perm %x\n",
1296 			      g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
1297 	}
1298 
1299 	return result;
1300 }
1301 
gpfsacl_sys_acl_set_file(vfs_handle_struct * handle,const struct smb_filename * smb_fname,SMB_ACL_TYPE_T type,SMB_ACL_T theacl)1302 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
1303 				    const struct smb_filename *smb_fname,
1304 				    SMB_ACL_TYPE_T type,
1305 				    SMB_ACL_T theacl)
1306 {
1307 	struct gpfs_acl *gpfs_acl;
1308 	int result;
1309 	struct gpfs_config_data *config;
1310 
1311 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1312 				struct gpfs_config_data,
1313 				return -1);
1314 
1315 	if (!config->acl) {
1316 		return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
1317 				type, theacl);
1318 	}
1319 
1320 	gpfs_acl = smb2gpfs_acl(theacl, type);
1321 	if (gpfs_acl == NULL) {
1322 		return -1;
1323 	}
1324 
1325 	result = gpfswrap_putacl(discard_const_p(char, smb_fname->base_name),
1326 				 GPFS_PUTACL_STRUCT|GPFS_ACL_SAMBA, gpfs_acl);
1327 
1328 	SAFE_FREE(gpfs_acl);
1329 	return result;
1330 }
1331 
gpfsacl_sys_acl_set_fd(vfs_handle_struct * handle,files_struct * fsp,SMB_ACL_T theacl)1332 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
1333 				  files_struct *fsp,
1334 				  SMB_ACL_T theacl)
1335 {
1336 	struct gpfs_config_data *config;
1337 
1338 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1339 				struct gpfs_config_data,
1340 				return -1);
1341 
1342 	if (!config->acl) {
1343 		return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
1344 	}
1345 
1346 	return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name,
1347 					SMB_ACL_TYPE_ACCESS, theacl);
1348 }
1349 
gpfsacl_sys_acl_delete_def_file(vfs_handle_struct * handle,const struct smb_filename * smb_fname)1350 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
1351 				const struct smb_filename *smb_fname)
1352 {
1353 	struct gpfs_config_data *config;
1354 
1355 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1356 				struct gpfs_config_data,
1357 				return -1);
1358 
1359 	if (!config->acl) {
1360 		return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, smb_fname);
1361 	}
1362 
1363 	errno = ENOTSUP;
1364 	return -1;
1365 }
1366 
1367 /*
1368  * Assumed: mode bits are shiftable and standard
1369  * Output: the new aceMask field for an smb nfs4 ace
1370  */
gpfsacl_mask_filter(uint32_t aceType,uint32_t aceMask,uint32_t rwx)1371 static uint32_t gpfsacl_mask_filter(uint32_t aceType, uint32_t aceMask, uint32_t rwx)
1372 {
1373 	const uint32_t posix_nfs4map[3] = {
1374                 SMB_ACE4_EXECUTE, /* execute */
1375 		SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
1376                 SMB_ACE4_READ_DATA /* read */
1377 	};
1378 	int     i;
1379 	uint32_t        posix_mask = 0x01;
1380 	uint32_t        posix_bit;
1381 	uint32_t        nfs4_bits;
1382 
1383 	for(i=0; i<3; i++) {
1384 		nfs4_bits = posix_nfs4map[i];
1385 		posix_bit = rwx & posix_mask;
1386 
1387 		if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
1388 			if (posix_bit)
1389 				aceMask |= nfs4_bits;
1390 			else
1391 				aceMask &= ~nfs4_bits;
1392 		} else {
1393 			/* add deny bits when suitable */
1394 			if (!posix_bit)
1395 				aceMask |= nfs4_bits;
1396 			else
1397 				aceMask &= ~nfs4_bits;
1398 		} /* other ace types are unexpected */
1399 
1400 		posix_mask <<= 1;
1401 	}
1402 
1403 	return aceMask;
1404 }
1405 
gpfsacl_emu_chmod(vfs_handle_struct * handle,const char * path,mode_t mode)1406 static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
1407 			     const char *path, mode_t mode)
1408 {
1409 	struct SMB4ACL_T *pacl = NULL;
1410 	int     result;
1411 	bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
1412 	int     i;
1413 	files_struct fake_fsp = { 0 }; /* TODO: rationalize parametrization */
1414 	struct SMB4ACE_T *smbace;
1415 	TALLOC_CTX *frame = talloc_stackframe();
1416 
1417 	DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
1418 
1419 	result = gpfs_get_nfs4_acl(frame, path, &pacl);
1420 	if (result) {
1421 		TALLOC_FREE(frame);
1422 		return result;
1423 	}
1424 
1425 	if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
1426 		DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
1427 	}
1428 
1429 	for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
1430 		SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
1431 		uint32_t        specid = ace->who.special_id;
1432 
1433 		if (ace->flags&SMB_ACE4_ID_SPECIAL &&
1434 		    ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
1435 		    specid <= SMB_ACE4_WHO_EVERYONE) {
1436 
1437 			uint32_t newMask;
1438 
1439 			if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
1440 				haveAllowEntry[specid] = True;
1441 
1442 			/* mode >> 6 for @owner, mode >> 3 for @group,
1443 			 * mode >> 0 for @everyone */
1444 			newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
1445 						      mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
1446 			if (ace->aceMask!=newMask) {
1447 				DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
1448 					   path, ace->aceMask, newMask, specid));
1449 			}
1450 			ace->aceMask = newMask;
1451 		}
1452 	}
1453 
1454 	/* make sure we have at least ALLOW entries
1455 	 * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
1456 	 * - if necessary
1457 	 */
1458 	for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
1459 		SMB_ACE4PROP_T ace = { 0 };
1460 
1461 		if (haveAllowEntry[i]==True)
1462 			continue;
1463 
1464 		ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
1465 		ace.flags |= SMB_ACE4_ID_SPECIAL;
1466 		ace.who.special_id = i;
1467 
1468 		if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
1469 			ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
1470 
1471 		ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
1472 						  mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
1473 
1474 		/* don't add unnecessary aces */
1475 		if (!ace.aceMask)
1476 			continue;
1477 
1478 		/* we add it to the END - as windows expects allow aces */
1479 		smb_add_ace4(pacl, &ace);
1480 		DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
1481 			   path, mode, i, ace.aceMask));
1482 	}
1483 
1484 	/* don't add complementary DENY ACEs here */
1485 	fake_fsp.fsp_name = synthetic_smb_fname(
1486 		frame, path, NULL, NULL, 0);
1487 	if (fake_fsp.fsp_name == NULL) {
1488 		errno = ENOMEM;
1489 		TALLOC_FREE(frame);
1490 		return -1;
1491 	}
1492 	/* put the acl */
1493 	if (gpfsacl_process_smbacl(handle, &fake_fsp, pacl) == False) {
1494 		TALLOC_FREE(frame);
1495 		return -1;
1496 	}
1497 
1498 	TALLOC_FREE(frame);
1499 	return 0; /* ok for [f]chmod */
1500 }
1501 
vfs_gpfs_chmod(vfs_handle_struct * handle,const struct smb_filename * smb_fname,mode_t mode)1502 static int vfs_gpfs_chmod(vfs_handle_struct *handle,
1503 			const struct smb_filename *smb_fname,
1504 			mode_t mode)
1505 {
1506 	struct smb_filename *smb_fname_cpath;
1507 	int rc;
1508 
1509 	smb_fname_cpath = cp_smb_filename(talloc_tos(), smb_fname);
1510 	if (smb_fname_cpath == NULL) {
1511 		errno = ENOMEM;
1512 		return -1;
1513 	}
1514 
1515 	if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
1516 		TALLOC_FREE(smb_fname_cpath);
1517 		return -1;
1518 	}
1519 
1520 	/* avoid chmod() if possible, to preserve acls */
1521 	if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
1522 		TALLOC_FREE(smb_fname_cpath);
1523 		return 0;
1524 	}
1525 
1526 	rc = gpfsacl_emu_chmod(handle, smb_fname->base_name, mode);
1527 	if (rc == 1)
1528 		return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1529 
1530 	TALLOC_FREE(smb_fname_cpath);
1531 	return rc;
1532 }
1533 
vfs_gpfs_fchmod(vfs_handle_struct * handle,files_struct * fsp,mode_t mode)1534 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
1535 {
1536 		 SMB_STRUCT_STAT st;
1537 		 int rc;
1538 
1539 		 if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
1540 			 return -1;
1541 		 }
1542 
1543 		 /* avoid chmod() if possible, to preserve acls */
1544 		 if ((st.st_ex_mode & ~S_IFMT) == mode) {
1545 			 return 0;
1546 		 }
1547 
1548 		 rc = gpfsacl_emu_chmod(handle, fsp->fsp_name->base_name,
1549 					mode);
1550 		 if (rc == 1)
1551 			 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1552 		 return rc;
1553 }
1554 
vfs_gpfs_winattrs_to_dosmode(unsigned int winattrs)1555 static uint32_t vfs_gpfs_winattrs_to_dosmode(unsigned int winattrs)
1556 {
1557 	uint32_t dosmode = 0;
1558 
1559 	if (winattrs & GPFS_WINATTR_ARCHIVE){
1560 		dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1561 	}
1562 	if (winattrs & GPFS_WINATTR_HIDDEN){
1563 		dosmode |= FILE_ATTRIBUTE_HIDDEN;
1564 	}
1565 	if (winattrs & GPFS_WINATTR_SYSTEM){
1566 		dosmode |= FILE_ATTRIBUTE_SYSTEM;
1567 	}
1568 	if (winattrs & GPFS_WINATTR_READONLY){
1569 		dosmode |= FILE_ATTRIBUTE_READONLY;
1570 	}
1571 	if (winattrs & GPFS_WINATTR_SPARSE_FILE) {
1572 		dosmode |= FILE_ATTRIBUTE_SPARSE;
1573 	}
1574 	if (winattrs & GPFS_WINATTR_OFFLINE) {
1575 		dosmode |= FILE_ATTRIBUTE_OFFLINE;
1576 	}
1577 
1578 	return dosmode;
1579 }
1580 
vfs_gpfs_dosmode_to_winattrs(uint32_t dosmode)1581 static unsigned int vfs_gpfs_dosmode_to_winattrs(uint32_t dosmode)
1582 {
1583 	unsigned int winattrs = 0;
1584 
1585 	if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
1586 		winattrs |= GPFS_WINATTR_ARCHIVE;
1587 	}
1588 	if (dosmode & FILE_ATTRIBUTE_HIDDEN){
1589 		winattrs |= GPFS_WINATTR_HIDDEN;
1590 	}
1591 	if (dosmode & FILE_ATTRIBUTE_SYSTEM){
1592 		winattrs |= GPFS_WINATTR_SYSTEM;
1593 	}
1594 	if (dosmode & FILE_ATTRIBUTE_READONLY){
1595 		winattrs |= GPFS_WINATTR_READONLY;
1596 	}
1597 	if (dosmode & FILE_ATTRIBUTE_SPARSE) {
1598 		winattrs |= GPFS_WINATTR_SPARSE_FILE;
1599 	}
1600 	if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
1601 		winattrs |= GPFS_WINATTR_OFFLINE;
1602 	}
1603 
1604 	return winattrs;
1605 }
1606 
get_dos_attr_with_capability(struct smb_filename * smb_fname,unsigned int * litemask,struct gpfs_iattr64 * iattr)1607 static int get_dos_attr_with_capability(struct smb_filename *smb_fname,
1608 					unsigned int *litemask,
1609 					struct gpfs_iattr64 *iattr)
1610 {
1611 	int saved_errno = 0;
1612 	int ret;
1613 
1614 	/*
1615 	 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to an
1616 	 * Existing File" FILE_LIST_DIRECTORY on a directory implies
1617 	 * FILE_READ_ATTRIBUTES for directory entries. Being able to stat() a
1618 	 * file implies FILE_LIST_DIRECTORY for the directory containing the
1619 	 * file.
1620 	 */
1621 
1622 	if (!VALID_STAT(smb_fname->st)) {
1623 		/*
1624 		 * Safety net: dos_mode() already checks this, but as we set
1625 		 * DAC_OVERRIDE_CAPABILITY based on this, add an additional
1626 		 * layer of defense.
1627 		 */
1628 		DBG_ERR("Rejecting DAC override, invalid stat [%s]\n",
1629 			smb_fname_str_dbg(smb_fname));
1630 		errno = EACCES;
1631 		return -1;
1632 	}
1633 
1634 	set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1635 
1636 	ret = gpfswrap_stat_x(smb_fname->base_name, litemask,
1637 			      iattr, sizeof(*iattr));
1638 	if (ret == -1) {
1639 		saved_errno = errno;
1640 	}
1641 
1642 	drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1643 
1644 	if (saved_errno != 0) {
1645 		errno = saved_errno;
1646 	}
1647 	return ret;
1648 }
1649 
vfs_gpfs_get_file_id(struct gpfs_iattr64 * iattr,uint64_t * fileid)1650 static NTSTATUS vfs_gpfs_get_file_id(struct gpfs_iattr64 *iattr,
1651 				     uint64_t *fileid)
1652 {
1653 	uint8_t input[sizeof(gpfs_ino64_t) +
1654 		      sizeof(gpfs_gen64_t) +
1655 		      sizeof(gpfs_snapid64_t)];
1656 	uint8_t digest[gnutls_hash_get_len(GNUTLS_DIG_SHA1)];
1657 	int rc;
1658 
1659 	DBG_DEBUG("ia_inode 0x%llx, ia_gen 0x%llx, ia_modsnapid 0x%llx\n",
1660 		  iattr->ia_inode, iattr->ia_gen, iattr->ia_modsnapid);
1661 
1662 	SBVAL(input,
1663 	      0, iattr->ia_inode);
1664 	SBVAL(input,
1665 	      sizeof(gpfs_ino64_t), iattr->ia_gen);
1666 	SBVAL(input,
1667 	      sizeof(gpfs_ino64_t) + sizeof(gpfs_gen64_t), iattr->ia_modsnapid);
1668 
1669 	GNUTLS_FIPS140_SET_LAX_MODE();
1670 	rc = gnutls_hash_fast(GNUTLS_DIG_SHA1, input, sizeof(input), &digest);
1671 	GNUTLS_FIPS140_SET_STRICT_MODE();
1672 
1673 	if (rc != 0) {
1674 		return gnutls_error_to_ntstatus(rc,
1675 						NT_STATUS_HASH_NOT_SUPPORTED);
1676 	}
1677 
1678 	memcpy(fileid, &digest, sizeof(*fileid));
1679 	DBG_DEBUG("file_id 0x%" PRIx64 "\n", *fileid);
1680 
1681 	return NT_STATUS_OK;
1682 }
1683 
gpfs_timestruc64_to_timespec(struct gpfs_timestruc64 g)1684 static struct timespec gpfs_timestruc64_to_timespec(struct gpfs_timestruc64 g)
1685 {
1686 	return (struct timespec) { .tv_sec = g.tv_sec, .tv_nsec = g.tv_nsec };
1687 }
1688 
vfs_gpfs_get_dos_attributes(struct vfs_handle_struct * handle,struct smb_filename * smb_fname,uint32_t * dosmode)1689 static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
1690 					    struct smb_filename *smb_fname,
1691 					    uint32_t *dosmode)
1692 {
1693 	struct gpfs_config_data *config;
1694 	struct gpfs_iattr64 iattr = { };
1695 	unsigned int litemask = 0;
1696 	struct timespec ts;
1697 	uint64_t file_id;
1698 	NTSTATUS status;
1699 	int ret;
1700 
1701 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1702 				struct gpfs_config_data,
1703 				return NT_STATUS_INTERNAL_ERROR);
1704 
1705 	if (!config->winattr) {
1706 		return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
1707 						       smb_fname, dosmode);
1708 	}
1709 
1710 	ret = gpfswrap_stat_x(smb_fname->base_name, &litemask,
1711 			      &iattr, sizeof(iattr));
1712 	if (ret == -1 && errno == ENOSYS) {
1713 		return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle, smb_fname,
1714 						       dosmode);
1715 	}
1716 	if (ret == -1 && errno == EACCES) {
1717 		ret = get_dos_attr_with_capability(smb_fname, &litemask,
1718 						   &iattr);
1719 	}
1720 
1721 	if (ret == -1 && errno == EBADF) {
1722 		/*
1723 		 * Returned for directory listings in gpfs root for
1724 		 * .. entry which steps out of gpfs.
1725 		 */
1726 		DBG_DEBUG("Getting winattrs for %s returned EBADF.\n",
1727 			  smb_fname->base_name);
1728 		return map_nt_error_from_unix(errno);
1729 	} else if (ret == -1) {
1730 		DBG_WARNING("Getting winattrs failed for %s: %s\n",
1731 			    smb_fname->base_name, strerror(errno));
1732 		return map_nt_error_from_unix(errno);
1733 	}
1734 
1735 	status = vfs_gpfs_get_file_id(&iattr, &file_id);
1736 	if (!NT_STATUS_IS_OK(status)) {
1737 		return status;
1738 	}
1739 
1740 	ts = gpfs_timestruc64_to_timespec(iattr.ia_createtime);
1741 
1742 	*dosmode |= vfs_gpfs_winattrs_to_dosmode(iattr.ia_winflags);
1743 	update_stat_ex_create_time(&smb_fname->st, ts);
1744 	update_stat_ex_file_id(&smb_fname->st, file_id);
1745 
1746 	return NT_STATUS_OK;
1747 }
1748 
vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct * handle,struct files_struct * fsp,uint32_t * dosmode)1749 static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle,
1750 					     struct files_struct *fsp,
1751 					     uint32_t *dosmode)
1752 {
1753 	struct gpfs_config_data *config;
1754 	struct gpfs_iattr64 iattr = { };
1755 	unsigned int litemask;
1756 	struct timespec ts;
1757 	uint64_t file_id;
1758 	NTSTATUS status;
1759 	int ret;
1760 
1761 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1762 				struct gpfs_config_data,
1763 				return NT_STATUS_INTERNAL_ERROR);
1764 
1765 	if (!config->winattr) {
1766 		return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1767 	}
1768 
1769 	ret = gpfswrap_fstat_x(fsp->fh->fd, &litemask, &iattr, sizeof(iattr));
1770 	if (ret == -1 && errno == ENOSYS) {
1771 		return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1772 	}
1773 
1774 	if (ret == -1 && errno == EACCES) {
1775 		int saved_errno = 0;
1776 
1777 		/*
1778 		 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
1779 		 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
1780 		 * FILE_READ_ATTRIBUTES for directory entries. Being able to
1781 		 * open a file implies FILE_LIST_DIRECTORY.
1782 		 */
1783 
1784 		set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1785 
1786 		ret = gpfswrap_fstat_x(fsp->fh->fd, &litemask,
1787 				       &iattr, sizeof(iattr));
1788 		if (ret == -1) {
1789 			saved_errno = errno;
1790 		}
1791 
1792 		drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1793 
1794 		if (saved_errno != 0) {
1795 			errno = saved_errno;
1796 		}
1797 	}
1798 
1799 	if (ret == -1) {
1800 		DBG_WARNING("Getting winattrs failed for %s: %s\n",
1801 			    fsp->fsp_name->base_name, strerror(errno));
1802 		return map_nt_error_from_unix(errno);
1803 	}
1804 
1805 	status = vfs_gpfs_get_file_id(&iattr, &file_id);
1806 	if (!NT_STATUS_IS_OK(status)) {
1807 		return status;
1808 	}
1809 
1810 	ts = gpfs_timestruc64_to_timespec(iattr.ia_createtime);
1811 
1812 	*dosmode |= vfs_gpfs_winattrs_to_dosmode(iattr.ia_winflags);
1813 	update_stat_ex_create_time(&fsp->fsp_name->st, ts);
1814 	update_stat_ex_file_id(&fsp->fsp_name->st, file_id);
1815 
1816 	return NT_STATUS_OK;
1817 }
1818 
vfs_gpfs_set_dos_attributes(struct vfs_handle_struct * handle,const struct smb_filename * smb_fname,uint32_t dosmode)1819 static NTSTATUS vfs_gpfs_set_dos_attributes(struct vfs_handle_struct *handle,
1820 					   const struct smb_filename *smb_fname,
1821 					   uint32_t dosmode)
1822 {
1823 	struct gpfs_config_data *config;
1824 	struct gpfs_winattr attrs = { };
1825 	int ret;
1826 
1827 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1828 				struct gpfs_config_data,
1829 				return NT_STATUS_INTERNAL_ERROR);
1830 
1831 	if (!config->winattr) {
1832 		return SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
1833 						       smb_fname, dosmode);
1834 	}
1835 
1836 	attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode);
1837 	ret = gpfswrap_set_winattrs_path(smb_fname->base_name,
1838 					 GPFS_WINATTR_SET_ATTRS, &attrs);
1839 
1840 	if (ret == -1 && errno == ENOSYS) {
1841 		return SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
1842 						       smb_fname, dosmode);
1843 	}
1844 
1845 	if (ret == -1) {
1846 		DBG_WARNING("Setting winattrs failed for %s: %s\n",
1847 			    smb_fname->base_name, strerror(errno));
1848 		return map_nt_error_from_unix(errno);
1849 	}
1850 
1851 	return NT_STATUS_OK;
1852 }
1853 
vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct * handle,struct files_struct * fsp,uint32_t dosmode)1854 static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle,
1855 					     struct files_struct *fsp,
1856 					     uint32_t dosmode)
1857 {
1858 	struct gpfs_config_data *config;
1859 	struct gpfs_winattr attrs = { };
1860 	int ret;
1861 
1862 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1863 				struct gpfs_config_data,
1864 				return NT_STATUS_INTERNAL_ERROR);
1865 
1866 	if (!config->winattr) {
1867 		return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1868 	}
1869 
1870 	attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode);
1871 	ret = gpfswrap_set_winattrs(fsp->fh->fd,
1872 				    GPFS_WINATTR_SET_ATTRS, &attrs);
1873 
1874 	if (ret == -1 && errno == ENOSYS) {
1875 		return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1876 	}
1877 
1878 	if (ret == -1) {
1879 		DBG_WARNING("Setting winattrs failed for %s: %s\n",
1880 			    fsp->fsp_name->base_name, strerror(errno));
1881 		return map_nt_error_from_unix(errno);
1882 	}
1883 
1884 	return NT_STATUS_OK;
1885 }
1886 
stat_with_capability(struct vfs_handle_struct * handle,struct smb_filename * smb_fname,int flag)1887 static int stat_with_capability(struct vfs_handle_struct *handle,
1888 				struct smb_filename *smb_fname, int flag)
1889 {
1890 #if defined(HAVE_FSTATAT)
1891 	int fd = -1;
1892 	bool b;
1893 	char *dir_name;
1894 	const char *rel_name = NULL;
1895 	struct stat st;
1896 	int ret = -1;
1897 
1898 	b = parent_dirname(talloc_tos(), smb_fname->base_name,
1899 			   &dir_name, &rel_name);
1900 	if (!b) {
1901 		errno = ENOMEM;
1902 		return -1;
1903 	}
1904 
1905 	fd = open(dir_name, O_RDONLY, 0);
1906 	TALLOC_FREE(dir_name);
1907 	if (fd == -1) {
1908 		return -1;
1909 	}
1910 
1911 	set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1912 	ret = fstatat(fd, rel_name, &st, flag);
1913 	drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1914 
1915 	close(fd);
1916 
1917 	if (ret == 0) {
1918 		init_stat_ex_from_stat(
1919 			&smb_fname->st, &st,
1920 			lp_fake_directory_create_times(SNUM(handle->conn)));
1921 	}
1922 
1923 	return ret;
1924 #else
1925 	return -1;
1926 #endif
1927 }
1928 
vfs_gpfs_stat(struct vfs_handle_struct * handle,struct smb_filename * smb_fname)1929 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1930 			 struct smb_filename *smb_fname)
1931 {
1932 	int ret;
1933 	struct gpfs_config_data *config;
1934 
1935 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1936 				struct gpfs_config_data,
1937 				return -1);
1938 
1939 	ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1940 	if (ret == -1 && errno == EACCES) {
1941 		DEBUG(10, ("Trying stat with capability for %s\n",
1942 			   smb_fname->base_name));
1943 		ret = stat_with_capability(handle, smb_fname, 0);
1944 	}
1945 	return ret;
1946 }
1947 
vfs_gpfs_lstat(struct vfs_handle_struct * handle,struct smb_filename * smb_fname)1948 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1949 			  struct smb_filename *smb_fname)
1950 {
1951 	int ret;
1952 	struct gpfs_config_data *config;
1953 
1954 	SMB_VFS_HANDLE_GET_DATA(handle, config,
1955 				struct gpfs_config_data,
1956 				return -1);
1957 
1958 	ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1959 	if (ret == -1 && errno == EACCES) {
1960 		DEBUG(10, ("Trying lstat with capability for %s\n",
1961 			   smb_fname->base_name));
1962 		ret = stat_with_capability(handle, smb_fname,
1963 					   AT_SYMLINK_NOFOLLOW);
1964 	}
1965 	return ret;
1966 }
1967 
timespec_to_gpfs_time(struct timespec ts,gpfs_timestruc_t * gt,int idx,int * flags)1968 static void timespec_to_gpfs_time(struct timespec ts, gpfs_timestruc_t *gt,
1969 				  int idx, int *flags)
1970 {
1971 	if (!is_omit_timespec(&ts)) {
1972 		*flags |= 1 << idx;
1973 		gt[idx].tv_sec = ts.tv_sec;
1974 		gt[idx].tv_nsec = ts.tv_nsec;
1975 		DEBUG(10, ("Setting GPFS time %d, flags 0x%x\n", idx, *flags));
1976 	}
1977 }
1978 
smbd_gpfs_set_times_path(char * path,struct smb_file_time * ft)1979 static int smbd_gpfs_set_times_path(char *path, struct smb_file_time *ft)
1980 {
1981 	gpfs_timestruc_t gpfs_times[4];
1982 	int flags = 0;
1983 	int rc;
1984 
1985 	ZERO_ARRAY(gpfs_times);
1986 	timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
1987 	timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
1988 	/* No good mapping from LastChangeTime to ctime, not storing */
1989 	timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
1990 
1991 	if (!flags) {
1992 		DEBUG(10, ("nothing to do, return to avoid EINVAL\n"));
1993 		return 0;
1994 	}
1995 
1996 	rc = gpfswrap_set_times_path(path, flags, gpfs_times);
1997 
1998 	if (rc != 0 && errno != ENOSYS) {
1999 		DEBUG(1,("gpfs_set_times() returned with error %s\n",
2000 			strerror(errno)));
2001 	}
2002 
2003 	return rc;
2004 }
2005 
vfs_gpfs_ntimes(struct vfs_handle_struct * handle,const struct smb_filename * smb_fname,struct smb_file_time * ft)2006 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
2007                         const struct smb_filename *smb_fname,
2008 			struct smb_file_time *ft)
2009 {
2010 
2011         struct gpfs_winattr attrs;
2012         int ret;
2013 	struct gpfs_config_data *config;
2014 
2015 	SMB_VFS_HANDLE_GET_DATA(handle, config,
2016 				struct gpfs_config_data,
2017 				return -1);
2018 
2019 	/* Try to use gpfs_set_times if it is enabled and available */
2020 	if (config->settimes) {
2021 		ret = smbd_gpfs_set_times_path(smb_fname->base_name, ft);
2022 
2023 		if (ret == 0 || (ret == -1 && errno != ENOSYS)) {
2024 			return ret;
2025 		}
2026 	}
2027 
2028 	DEBUG(10,("gpfs_set_times() not available or disabled, "
2029 		  "use ntimes and winattr\n"));
2030 
2031         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
2032         if(ret == -1){
2033 		/* don't complain if access was denied */
2034 		if (errno != EPERM && errno != EACCES) {
2035 			DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed:"
2036 				 "%s", strerror(errno)));
2037 		}
2038                 return -1;
2039         }
2040 
2041         if (is_omit_timespec(&ft->create_time)){
2042                 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
2043                 return 0;
2044         }
2045 
2046 	if (!config->winattr) {
2047 		return 0;
2048 	}
2049 
2050         attrs.winAttrs = 0;
2051         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
2052         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
2053 
2054 	ret = gpfswrap_set_winattrs_path(smb_fname->base_name,
2055 					 GPFS_WINATTR_SET_CREATION_TIME,
2056 					 &attrs);
2057         if(ret == -1 && errno != ENOSYS){
2058                 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
2059 	        return -1;
2060         }
2061         return 0;
2062 
2063 }
2064 
vfs_gpfs_fallocate(struct vfs_handle_struct * handle,struct files_struct * fsp,uint32_t mode,off_t offset,off_t len)2065 static int vfs_gpfs_fallocate(struct vfs_handle_struct *handle,
2066 			      struct files_struct *fsp, uint32_t mode,
2067 			      off_t offset, off_t len)
2068 {
2069 	if (mode == (VFS_FALLOCATE_FL_PUNCH_HOLE|VFS_FALLOCATE_FL_KEEP_SIZE) &&
2070 	    !fsp->is_sparse &&
2071 	    lp_strict_allocate(SNUM(fsp->conn))) {
2072 		/*
2073 		 * This is from a ZERO_DATA request on a non-sparse
2074 		 * file. GPFS does not support FL_KEEP_SIZE and thus
2075 		 * cannot fill the whole again in the subsequent
2076 		 * fallocate(FL_KEEP_SIZE). Deny this FL_PUNCH_HOLE
2077 		 * call to not end up with a hole in a non-sparse
2078 		 * file.
2079 		 */
2080 		errno = ENOTSUP;
2081 		return -1;
2082 	}
2083 
2084 	return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
2085 }
2086 
vfs_gpfs_ftruncate(vfs_handle_struct * handle,files_struct * fsp,off_t len)2087 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
2088 				off_t len)
2089 {
2090 	int result;
2091 	struct gpfs_config_data *config;
2092 
2093 	SMB_VFS_HANDLE_GET_DATA(handle, config,
2094 				struct gpfs_config_data,
2095 				return -1);
2096 
2097 	if (!config->ftruncate) {
2098 		return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
2099 	}
2100 
2101 	result = gpfswrap_ftruncate(fsp->fh->fd, len);
2102 	if ((result == -1) && (errno == ENOSYS)) {
2103 		return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
2104 	}
2105 	return result;
2106 }
2107 
vfs_gpfs_is_offline(struct vfs_handle_struct * handle,const struct smb_filename * fname,SMB_STRUCT_STAT * sbuf)2108 static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
2109 				const struct smb_filename *fname,
2110 				SMB_STRUCT_STAT *sbuf)
2111 {
2112 	struct gpfs_winattr attrs;
2113 	struct gpfs_config_data *config;
2114 	int ret;
2115 
2116 	SMB_VFS_HANDLE_GET_DATA(handle, config,
2117 				struct gpfs_config_data,
2118 				return false);
2119 
2120 	if (!config->winattr) {
2121 		return false;
2122 	}
2123 
2124 	ret = gpfswrap_get_winattrs_path(fname->base_name, &attrs);
2125 	if (ret == -1) {
2126 		return false;
2127 	}
2128 
2129 	if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
2130 		DBG_DEBUG("%s is offline\n", fname->base_name);
2131 		return true;
2132 	}
2133 
2134 	DBG_DEBUG("%s is online\n", fname->base_name);
2135 	return false;
2136 }
2137 
vfs_gpfs_fsp_is_offline(struct vfs_handle_struct * handle,struct files_struct * fsp)2138 static bool vfs_gpfs_fsp_is_offline(struct vfs_handle_struct *handle,
2139 				    struct files_struct *fsp)
2140 {
2141 	struct gpfs_fsp_extension *ext;
2142 
2143 	ext = VFS_FETCH_FSP_EXTENSION(handle, fsp);
2144 	if (ext == NULL) {
2145 		/*
2146 		 * Something bad happened, always ask.
2147 		 */
2148 		return vfs_gpfs_is_offline(handle, fsp->fsp_name,
2149 					   &fsp->fsp_name->st);
2150 	}
2151 
2152 	if (ext->offline) {
2153 		/*
2154 		 * As long as it's offline, ask.
2155 		 */
2156 		ext->offline = vfs_gpfs_is_offline(handle, fsp->fsp_name,
2157 						   &fsp->fsp_name->st);
2158 	}
2159 
2160 	return ext->offline;
2161 }
2162 
vfs_gpfs_aio_force(struct vfs_handle_struct * handle,struct files_struct * fsp)2163 static bool vfs_gpfs_aio_force(struct vfs_handle_struct *handle,
2164 			       struct files_struct *fsp)
2165 {
2166 	return vfs_gpfs_fsp_is_offline(handle, fsp);
2167 }
2168 
vfs_gpfs_sendfile(vfs_handle_struct * handle,int tofd,files_struct * fsp,const DATA_BLOB * hdr,off_t offset,size_t n)2169 static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd,
2170 				 files_struct *fsp, const DATA_BLOB *hdr,
2171 				 off_t offset, size_t n)
2172 {
2173 	if (vfs_gpfs_fsp_is_offline(handle, fsp)) {
2174 		errno = ENOSYS;
2175 		return -1;
2176 	}
2177 	return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
2178 }
2179 
vfs_gpfs_connect(struct vfs_handle_struct * handle,const char * service,const char * user)2180 static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
2181 			    const char *service, const char *user)
2182 {
2183 	struct gpfs_config_data *config;
2184 	int ret;
2185 	bool check_fstype;
2186 
2187 	gpfswrap_lib_init(0);
2188 
2189 	config = talloc_zero(handle->conn, struct gpfs_config_data);
2190 	if (!config) {
2191 		DEBUG(0, ("talloc_zero() failed\n"));
2192 		errno = ENOMEM;
2193 		return -1;
2194 	}
2195 
2196 	ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
2197 	if (ret < 0) {
2198 		TALLOC_FREE(config);
2199 		return ret;
2200 	}
2201 
2202 	check_fstype = lp_parm_bool(SNUM(handle->conn), "gpfs",
2203 				    "check_fstype", true);
2204 
2205 	if (check_fstype && !IS_IPC(handle->conn)) {
2206 		const char *connectpath = handle->conn->connectpath;
2207 		struct statfs buf = { 0 };
2208 
2209 		ret = statfs(connectpath, &buf);
2210 		if (ret != 0) {
2211 			DBG_ERR("statfs failed for share %s at path %s: %s\n",
2212 				service, connectpath, strerror(errno));
2213 			TALLOC_FREE(config);
2214 			return ret;
2215 		}
2216 
2217 		if (buf.f_type != GPFS_SUPER_MAGIC) {
2218 			DBG_ERR("SMB share %s, path %s not in GPFS file system."
2219 				" statfs magic: 0x%jx\n",
2220 				service,
2221 				connectpath,
2222 				(uintmax_t)buf.f_type);
2223 			errno = EINVAL;
2224 			TALLOC_FREE(config);
2225 			return -1;
2226 		}
2227 	}
2228 
2229 	ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
2230 	if (ret < 0) {
2231 		TALLOC_FREE(config);
2232 		return ret;
2233 	}
2234 
2235 	config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
2236 					"sharemodes", true);
2237 
2238 	config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
2239 					"leases", true);
2240 
2241 	config->hsm = lp_parm_bool(SNUM(handle->conn), "gpfs",
2242 				   "hsm", false);
2243 
2244 	config->syncio = lp_parm_bool(SNUM(handle->conn), "gpfs",
2245 				      "syncio", false);
2246 
2247 	config->winattr = lp_parm_bool(SNUM(handle->conn), "gpfs",
2248 				       "winattr", false);
2249 
2250 	config->ftruncate = lp_parm_bool(SNUM(handle->conn), "gpfs",
2251 					 "ftruncate", true);
2252 
2253 	config->getrealfilename = lp_parm_bool(SNUM(handle->conn), "gpfs",
2254 					       "getrealfilename", true);
2255 
2256 	config->dfreequota = lp_parm_bool(SNUM(handle->conn), "gpfs",
2257 					  "dfreequota", false);
2258 
2259 	config->acl = lp_parm_bool(SNUM(handle->conn), "gpfs", "acl", true);
2260 
2261 	config->settimes = lp_parm_bool(SNUM(handle->conn), "gpfs",
2262 					"settimes", true);
2263 	config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs",
2264 				       "recalls", true);
2265 
2266 	SMB_VFS_HANDLE_SET_DATA(handle, config,
2267 				NULL, struct gpfs_config_data,
2268 				return -1);
2269 
2270 	if (config->leases) {
2271 		/*
2272 		 * GPFS lease code is based on kernel oplock code
2273 		 * so make sure it is turned on
2274 		 */
2275 		if (!lp_kernel_oplocks(SNUM(handle->conn))) {
2276 			DEBUG(5, ("Enabling kernel oplocks for "
2277 				  "gpfs:leases to work\n"));
2278 			lp_do_parameter(SNUM(handle->conn), "kernel oplocks",
2279 					"true");
2280 		}
2281 
2282 		/*
2283 		 * as the kernel does not properly support Level II oplocks
2284 		 * and GPFS leases code is based on kernel infrastructure, we
2285 		 * need to turn off Level II oplocks if gpfs:leases is enabled
2286 		 */
2287 		if (lp_level2_oplocks(SNUM(handle->conn))) {
2288 			DEBUG(5, ("gpfs:leases are enabled, disabling "
2289 				  "Level II oplocks\n"));
2290 			lp_do_parameter(SNUM(handle->conn), "level2 oplocks",
2291 					"false");
2292 		}
2293 	}
2294 
2295 	/*
2296 	 * Unless we have an async implementation of get_dos_attributes turn
2297 	 * this off.
2298 	 */
2299 	lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
2300 
2301 	return 0;
2302 }
2303 
get_gpfs_quota(const char * pathname,int type,int id,struct gpfs_quotaInfo * qi)2304 static int get_gpfs_quota(const char *pathname, int type, int id,
2305 			  struct gpfs_quotaInfo *qi)
2306 {
2307 	int ret;
2308 
2309 	ret = gpfswrap_quotactl(discard_const_p(char, pathname),
2310 				GPFS_QCMD(Q_GETQUOTA, type), id, qi);
2311 
2312 	if (ret) {
2313 		if (errno == GPFS_E_NO_QUOTA_INST) {
2314 			DEBUG(10, ("Quotas disabled on GPFS filesystem.\n"));
2315 		} else if (errno != ENOSYS) {
2316 			DEBUG(0, ("Get quota failed, type %d, id, %d, "
2317 				  "errno %d.\n", type, id, errno));
2318 		}
2319 
2320 		return ret;
2321 	}
2322 
2323 	DEBUG(10, ("quota type %d, id %d, blk u:%lld h:%lld s:%lld gt:%u\n",
2324 		   type, id, qi->blockUsage, qi->blockHardLimit,
2325 		   qi->blockSoftLimit, qi->blockGraceTime));
2326 
2327 	return ret;
2328 }
2329 
vfs_gpfs_disk_free_quota(struct gpfs_quotaInfo qi,time_t cur_time,uint64_t * dfree,uint64_t * dsize)2330 static void vfs_gpfs_disk_free_quota(struct gpfs_quotaInfo qi, time_t cur_time,
2331 				     uint64_t *dfree, uint64_t *dsize)
2332 {
2333 	uint64_t usage, limit;
2334 
2335 	/*
2336 	 * The quota reporting is done in units of 1024 byte blocks, but
2337 	 * sys_fsusage uses units of 512 byte blocks, adjust the block number
2338 	 * accordingly. Also filter possibly negative usage counts from gpfs.
2339 	 */
2340 	usage = qi.blockUsage < 0 ? 0 : (uint64_t)qi.blockUsage * 2;
2341 	limit = (uint64_t)qi.blockHardLimit * 2;
2342 
2343 	/*
2344 	 * When the grace time for the exceeded soft block quota has been
2345 	 * exceeded, the soft block quota becomes an additional hard limit.
2346 	 */
2347 	if (qi.blockSoftLimit &&
2348 	    qi.blockGraceTime && cur_time > qi.blockGraceTime) {
2349 		/* report disk as full */
2350 		*dfree = 0;
2351 		*dsize = MIN(*dsize, usage);
2352 	}
2353 
2354 	if (!qi.blockHardLimit)
2355 		return;
2356 
2357 	if (usage >= limit) {
2358 		/* report disk as full */
2359 		*dfree = 0;
2360 		*dsize = MIN(*dsize, usage);
2361 
2362 	} else {
2363 		/* limit has not been reached, determine "free space" */
2364 		*dfree = MIN(*dfree, limit - usage);
2365 		*dsize = MIN(*dsize, limit);
2366 	}
2367 }
2368 
vfs_gpfs_disk_free(vfs_handle_struct * handle,const struct smb_filename * smb_fname,uint64_t * bsize,uint64_t * dfree,uint64_t * dsize)2369 static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle,
2370 				const struct smb_filename *smb_fname,
2371 				uint64_t *bsize,
2372 				uint64_t *dfree,
2373 				uint64_t *dsize)
2374 {
2375 	struct security_unix_token *utok;
2376 	struct gpfs_quotaInfo qi_user = { 0 }, qi_group = { 0 };
2377 	struct gpfs_config_data *config;
2378 	int err;
2379 	time_t cur_time;
2380 
2381 	SMB_VFS_HANDLE_GET_DATA(handle, config, struct gpfs_config_data,
2382 				return (uint64_t)-1);
2383 	if (!config->dfreequota) {
2384 		return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2385 					      bsize, dfree, dsize);
2386 	}
2387 
2388 	err = sys_fsusage(smb_fname->base_name, dfree, dsize);
2389 	if (err) {
2390 		DEBUG (0, ("Could not get fs usage, errno %d\n", errno));
2391 		return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2392 					      bsize, dfree, dsize);
2393 	}
2394 
2395 	/* sys_fsusage returns units of 512 bytes */
2396 	*bsize = 512;
2397 
2398 	DEBUG(10, ("fs dfree %llu, dsize %llu\n",
2399 		   (unsigned long long)*dfree, (unsigned long long)*dsize));
2400 
2401 	utok = handle->conn->session_info->unix_token;
2402 
2403 	err = get_gpfs_quota(smb_fname->base_name,
2404 			GPFS_USRQUOTA, utok->uid, &qi_user);
2405 	if (err) {
2406 		return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2407 					      bsize, dfree, dsize);
2408 	}
2409 
2410 	/*
2411 	 * If new files created under this folder get this folder's
2412 	 * GID, then available space is governed by the quota of the
2413 	 * folder's GID, not the primary group of the creating user.
2414 	 */
2415 	if (VALID_STAT(smb_fname->st) &&
2416 	    S_ISDIR(smb_fname->st.st_ex_mode) &&
2417 	    smb_fname->st.st_ex_mode & S_ISGID) {
2418 		become_root();
2419 		err = get_gpfs_quota(smb_fname->base_name, GPFS_GRPQUOTA,
2420 				     smb_fname->st.st_ex_gid, &qi_group);
2421 		unbecome_root();
2422 
2423 	} else {
2424 		err = get_gpfs_quota(smb_fname->base_name, GPFS_GRPQUOTA,
2425 				     utok->gid, &qi_group);
2426 	}
2427 
2428 	if (err) {
2429 		return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2430 					      bsize, dfree, dsize);
2431 	}
2432 
2433 	cur_time = time(NULL);
2434 
2435 	/* Adjust free space and size according to quota limits. */
2436 	vfs_gpfs_disk_free_quota(qi_user, cur_time, dfree, dsize);
2437 	vfs_gpfs_disk_free_quota(qi_group, cur_time, dfree, dsize);
2438 
2439 	return *dfree / 2;
2440 }
2441 
vfs_gpfs_get_quota(vfs_handle_struct * handle,const struct smb_filename * smb_fname,enum SMB_QUOTA_TYPE qtype,unid_t id,SMB_DISK_QUOTA * dq)2442 static int vfs_gpfs_get_quota(vfs_handle_struct *handle,
2443 				const struct smb_filename *smb_fname,
2444 				enum SMB_QUOTA_TYPE qtype,
2445 				unid_t id,
2446 				SMB_DISK_QUOTA *dq)
2447 {
2448 	switch(qtype) {
2449 		/*
2450 		 * User/group quota are being used for disk-free
2451 		 * determination, which in this module is done directly
2452 		 * by the disk-free function. It's important that this
2453 		 * module does not return wrong quota values by mistake,
2454 		 * which would modify the correct values set by disk-free.
2455 		 * User/group quota are also being used for processing
2456 		 * NT_TRANSACT_GET_USER_QUOTA in smb1 protocol, which is
2457 		 * currently not supported by this module.
2458 		 */
2459 		case SMB_USER_QUOTA_TYPE:
2460 		case SMB_GROUP_QUOTA_TYPE:
2461 			errno = ENOSYS;
2462 			return -1;
2463 		default:
2464 			return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname,
2465 					qtype, id, dq);
2466 	}
2467 }
2468 
vfs_gpfs_capabilities(struct vfs_handle_struct * handle,enum timestamp_set_resolution * p_ts_res)2469 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
2470 				      enum timestamp_set_resolution *p_ts_res)
2471 {
2472 	struct gpfs_config_data *config;
2473 	uint32_t next;
2474 
2475 	next = SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
2476 
2477 	SMB_VFS_HANDLE_GET_DATA(handle, config,
2478 				struct gpfs_config_data,
2479 				return next);
2480 
2481 	if (config->hsm) {
2482 		next |= FILE_SUPPORTS_REMOTE_STORAGE;
2483 	}
2484 	return next;
2485 }
2486 
vfs_gpfs_open(struct vfs_handle_struct * handle,struct smb_filename * smb_fname,files_struct * fsp,int flags,mode_t mode)2487 static int vfs_gpfs_open(struct vfs_handle_struct *handle,
2488 			 struct smb_filename *smb_fname, files_struct *fsp,
2489 			 int flags, mode_t mode)
2490 {
2491 	struct gpfs_config_data *config;
2492 	int ret;
2493 	struct gpfs_fsp_extension *ext;
2494 
2495 	SMB_VFS_HANDLE_GET_DATA(handle, config,
2496 				struct gpfs_config_data,
2497 				return -1);
2498 
2499 	if (config->hsm && !config->recalls &&
2500 	    vfs_gpfs_fsp_is_offline(handle, fsp)) {
2501 		DEBUG(10, ("Refusing access to offline file %s\n",
2502 			   fsp_str_dbg(fsp)));
2503 		errno = EACCES;
2504 		return -1;
2505 	}
2506 
2507 	if (config->syncio) {
2508 		flags |= O_SYNC;
2509 	}
2510 
2511 	ext = VFS_ADD_FSP_EXTENSION(handle, fsp, struct gpfs_fsp_extension,
2512 				    NULL);
2513 	if (ext == NULL) {
2514 		errno = ENOMEM;
2515 		return -1;
2516 	}
2517 
2518 	/*
2519 	 * Assume the file is offline until gpfs tells us it's online.
2520 	 */
2521 	*ext = (struct gpfs_fsp_extension) { .offline = true };
2522 
2523 	ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
2524 	if (ret == -1) {
2525 		VFS_REMOVE_FSP_EXTENSION(handle, fsp);
2526 	}
2527 	return ret;
2528 }
2529 
vfs_gpfs_pread(vfs_handle_struct * handle,files_struct * fsp,void * data,size_t n,off_t offset)2530 static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
2531 			      void *data, size_t n, off_t offset)
2532 {
2533 	ssize_t ret;
2534 	bool was_offline;
2535 
2536 	was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2537 
2538 	ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2539 
2540 	if ((ret != -1) && was_offline) {
2541 		notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
2542 			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
2543 			     fsp->fsp_name->base_name);
2544 	}
2545 
2546 	return ret;
2547 }
2548 
2549 struct vfs_gpfs_pread_state {
2550 	struct files_struct *fsp;
2551 	ssize_t ret;
2552 	bool was_offline;
2553 	struct vfs_aio_state vfs_aio_state;
2554 };
2555 
2556 static void vfs_gpfs_pread_done(struct tevent_req *subreq);
2557 
vfs_gpfs_pread_send(struct vfs_handle_struct * handle,TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct files_struct * fsp,void * data,size_t n,off_t offset)2558 static struct tevent_req *vfs_gpfs_pread_send(struct vfs_handle_struct *handle,
2559 					      TALLOC_CTX *mem_ctx,
2560 					      struct tevent_context *ev,
2561 					      struct files_struct *fsp,
2562 					      void *data, size_t n,
2563 					      off_t offset)
2564 {
2565 	struct tevent_req *req, *subreq;
2566 	struct vfs_gpfs_pread_state *state;
2567 
2568 	req = tevent_req_create(mem_ctx, &state, struct vfs_gpfs_pread_state);
2569 	if (req == NULL) {
2570 		return NULL;
2571 	}
2572 	state->was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2573 	state->fsp = fsp;
2574 	subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
2575 					 n, offset);
2576 	if (tevent_req_nomem(subreq, req)) {
2577 		return tevent_req_post(req, ev);
2578 	}
2579 	tevent_req_set_callback(subreq, vfs_gpfs_pread_done, req);
2580 	return req;
2581 }
2582 
vfs_gpfs_pread_done(struct tevent_req * subreq)2583 static void vfs_gpfs_pread_done(struct tevent_req *subreq)
2584 {
2585 	struct tevent_req *req = tevent_req_callback_data(
2586 		subreq, struct tevent_req);
2587 	struct vfs_gpfs_pread_state *state = tevent_req_data(
2588 		req, struct vfs_gpfs_pread_state);
2589 
2590 	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
2591 	TALLOC_FREE(subreq);
2592 	tevent_req_done(req);
2593 }
2594 
vfs_gpfs_pread_recv(struct tevent_req * req,struct vfs_aio_state * vfs_aio_state)2595 static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req,
2596 				   struct vfs_aio_state *vfs_aio_state)
2597 {
2598 	struct vfs_gpfs_pread_state *state = tevent_req_data(
2599 		req, struct vfs_gpfs_pread_state);
2600 	struct files_struct *fsp = state->fsp;
2601 
2602 	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2603 		return -1;
2604 	}
2605 	*vfs_aio_state = state->vfs_aio_state;
2606 
2607 	if ((state->ret != -1) && state->was_offline) {
2608 		DEBUG(10, ("sending notify\n"));
2609 		notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
2610 			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
2611 			     fsp->fsp_name->base_name);
2612 	}
2613 
2614 	return state->ret;
2615 }
2616 
vfs_gpfs_pwrite(vfs_handle_struct * handle,files_struct * fsp,const void * data,size_t n,off_t offset)2617 static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
2618 			       const void *data, size_t n, off_t offset)
2619 {
2620 	ssize_t ret;
2621 	bool was_offline;
2622 
2623 	was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2624 
2625 	ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2626 
2627 	if ((ret != -1) && was_offline) {
2628 		notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
2629 			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
2630 			     fsp->fsp_name->base_name);
2631 	}
2632 
2633 	return ret;
2634 }
2635 
2636 struct vfs_gpfs_pwrite_state {
2637 	struct files_struct *fsp;
2638 	ssize_t ret;
2639 	bool was_offline;
2640 	struct vfs_aio_state vfs_aio_state;
2641 };
2642 
2643 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq);
2644 
vfs_gpfs_pwrite_send(struct vfs_handle_struct * handle,TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct files_struct * fsp,const void * data,size_t n,off_t offset)2645 static struct tevent_req *vfs_gpfs_pwrite_send(
2646 	struct vfs_handle_struct *handle,
2647 	TALLOC_CTX *mem_ctx,
2648 	struct tevent_context *ev,
2649 	struct files_struct *fsp,
2650 	const void *data, size_t n,
2651 	off_t offset)
2652 {
2653 	struct tevent_req *req, *subreq;
2654 	struct vfs_gpfs_pwrite_state *state;
2655 
2656 	req = tevent_req_create(mem_ctx, &state, struct vfs_gpfs_pwrite_state);
2657 	if (req == NULL) {
2658 		return NULL;
2659 	}
2660 	state->was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2661 	state->fsp = fsp;
2662 	subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
2663 					 n, offset);
2664 	if (tevent_req_nomem(subreq, req)) {
2665 		return tevent_req_post(req, ev);
2666 	}
2667 	tevent_req_set_callback(subreq, vfs_gpfs_pwrite_done, req);
2668 	return req;
2669 }
2670 
vfs_gpfs_pwrite_done(struct tevent_req * subreq)2671 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq)
2672 {
2673 	struct tevent_req *req = tevent_req_callback_data(
2674 		subreq, struct tevent_req);
2675 	struct vfs_gpfs_pwrite_state *state = tevent_req_data(
2676 		req, struct vfs_gpfs_pwrite_state);
2677 
2678 	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
2679 	TALLOC_FREE(subreq);
2680 	tevent_req_done(req);
2681 }
2682 
vfs_gpfs_pwrite_recv(struct tevent_req * req,struct vfs_aio_state * vfs_aio_state)2683 static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req,
2684 				    struct vfs_aio_state *vfs_aio_state)
2685 {
2686 	struct vfs_gpfs_pwrite_state *state = tevent_req_data(
2687 		req, struct vfs_gpfs_pwrite_state);
2688 	struct files_struct *fsp = state->fsp;
2689 
2690 	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2691 		return -1;
2692 	}
2693 	*vfs_aio_state = state->vfs_aio_state;
2694 
2695 	if ((state->ret != -1) && state->was_offline) {
2696 		DEBUG(10, ("sending notify\n"));
2697 		notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
2698 			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
2699 			     fsp->fsp_name->base_name);
2700 	}
2701 
2702 	return state->ret;
2703 }
2704 
2705 
2706 static struct vfs_fn_pointers vfs_gpfs_fns = {
2707 	.connect_fn = vfs_gpfs_connect,
2708 	.disk_free_fn = vfs_gpfs_disk_free,
2709 	.get_quota_fn = vfs_gpfs_get_quota,
2710 	.fs_capabilities_fn = vfs_gpfs_capabilities,
2711 	.kernel_flock_fn = vfs_gpfs_kernel_flock,
2712 	.linux_setlease_fn = vfs_gpfs_setlease,
2713 	.get_real_filename_fn = vfs_gpfs_get_real_filename,
2714 	.get_dos_attributes_fn = vfs_gpfs_get_dos_attributes,
2715 	.get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
2716 	.get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
2717 	.fget_dos_attributes_fn = vfs_gpfs_fget_dos_attributes,
2718 	.set_dos_attributes_fn = vfs_gpfs_set_dos_attributes,
2719 	.fset_dos_attributes_fn = vfs_gpfs_fset_dos_attributes,
2720 	.fget_nt_acl_fn = gpfsacl_fget_nt_acl,
2721 	.get_nt_acl_fn = gpfsacl_get_nt_acl,
2722 	.fset_nt_acl_fn = gpfsacl_fset_nt_acl,
2723 	.sys_acl_get_file_fn = gpfsacl_sys_acl_get_file,
2724 	.sys_acl_get_fd_fn = gpfsacl_sys_acl_get_fd,
2725 	.sys_acl_blob_get_file_fn = gpfsacl_sys_acl_blob_get_file,
2726 	.sys_acl_blob_get_fd_fn = gpfsacl_sys_acl_blob_get_fd,
2727 	.sys_acl_set_file_fn = gpfsacl_sys_acl_set_file,
2728 	.sys_acl_set_fd_fn = gpfsacl_sys_acl_set_fd,
2729 	.sys_acl_delete_def_file_fn = gpfsacl_sys_acl_delete_def_file,
2730 	.chmod_fn = vfs_gpfs_chmod,
2731 	.fchmod_fn = vfs_gpfs_fchmod,
2732 	.close_fn = vfs_gpfs_close,
2733 	.stat_fn = vfs_gpfs_stat,
2734 	.lstat_fn = vfs_gpfs_lstat,
2735 	.ntimes_fn = vfs_gpfs_ntimes,
2736 	.aio_force_fn = vfs_gpfs_aio_force,
2737 	.sendfile_fn = vfs_gpfs_sendfile,
2738 	.fallocate_fn = vfs_gpfs_fallocate,
2739 	.open_fn = vfs_gpfs_open,
2740 	.pread_fn = vfs_gpfs_pread,
2741 	.pread_send_fn = vfs_gpfs_pread_send,
2742 	.pread_recv_fn = vfs_gpfs_pread_recv,
2743 	.pwrite_fn = vfs_gpfs_pwrite,
2744 	.pwrite_send_fn = vfs_gpfs_pwrite_send,
2745 	.pwrite_recv_fn = vfs_gpfs_pwrite_recv,
2746 	.ftruncate_fn = vfs_gpfs_ftruncate
2747 };
2748 
2749 static_decl_vfs;
vfs_gpfs_init(TALLOC_CTX * ctx)2750 NTSTATUS vfs_gpfs_init(TALLOC_CTX *ctx)
2751 {
2752 	int ret;
2753 
2754 	ret = gpfswrap_init();
2755 	if (ret != 0) {
2756 		DEBUG(1, ("Could not initialize GPFS library wrapper\n"));
2757 	}
2758 
2759 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
2760 				&vfs_gpfs_fns);
2761 }
2762