• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source3/modules/
1/*
2   Unix SMB/CIFS implementation.
3   Wrap gpfs calls in vfs functions.
4
5   Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
6
7   Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
8                            and Gomati Mohanan <gomati.mohanan@in.ibm.com>
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 3 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "includes.h"
25
26#undef DBGC_CLASS
27#define DBGC_CLASS DBGC_VFS
28
29#include <gpfs_gpl.h>
30#include "nfs4_acls.h"
31#include "vfs_gpfs.h"
32
33static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
34				 uint32 share_mode, uint32 access_mask)
35{
36
37	START_PROFILE(syscall_kernel_flock);
38
39	kernel_flock(fsp->fh->fd, share_mode, access_mask);
40
41	if (!set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
42
43		return -1;
44
45	}
46
47	END_PROFILE(syscall_kernel_flock);
48
49	return 0;
50}
51
52static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
53{
54	if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
55		set_gpfs_sharemode(fsp, 0, 0);
56	}
57
58	return SMB_VFS_NEXT_CLOSE(handle, fsp);
59}
60
61static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp,
62			     int leasetype)
63{
64	int ret;
65
66	START_PROFILE(syscall_linux_setlease);
67
68	if ( linux_set_lease_sighandler(fsp->fh->fd) == -1)
69		return -1;
70
71	ret = set_gpfs_lease(fsp->fh->fd,leasetype);
72
73	if ( ret < 0 ) {
74		/* This must have come from GPFS not being available */
75		/* or some other error, hence call the default */
76		ret = linux_setlease(fsp->fh->fd, leasetype);
77	}
78
79	END_PROFILE(syscall_linux_setlease);
80
81	return ret;
82}
83
84static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
85				      const char *path,
86				      const char *name,
87				      TALLOC_CTX *mem_ctx,
88				      char **found_name)
89{
90	int result;
91	char *full_path;
92	char real_pathname[PATH_MAX+1];
93	int buflen;
94
95	full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
96	if (full_path == NULL) {
97		errno = ENOMEM;
98		return -1;
99	}
100
101	buflen = sizeof(real_pathname) - 1;
102
103	result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
104						 &buflen);
105
106	TALLOC_FREE(full_path);
107
108	if ((result == -1) && (errno == ENOSYS)) {
109		return SMB_VFS_NEXT_GET_REAL_FILENAME(
110			handle, path, name, mem_ctx, found_name);
111	}
112
113	if (result == -1) {
114		DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
115			   strerror(errno)));
116		return -1;
117	}
118
119	/*
120	 * GPFS does not necessarily null-terminate the returned path
121	 * but instead returns the buffer length in buflen.
122	 */
123
124	if (buflen < sizeof(real_pathname)) {
125		real_pathname[buflen] = '\0';
126	} else {
127		real_pathname[sizeof(real_pathname)-1] = '\0';
128	}
129
130	DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
131		   path, name, real_pathname));
132
133	name = strrchr_m(real_pathname, '/');
134	if (name == NULL) {
135		errno = ENOENT;
136		return -1;
137	}
138
139	*found_name = talloc_strdup(mem_ctx, name+1);
140	if (*found_name == NULL) {
141		errno = ENOMEM;
142		return -1;
143	}
144
145	return 0;
146}
147
148static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
149{
150	int	i;
151	if (gacl==NULL)
152	{
153		DEBUG(0, ("gpfs acl is NULL\n"));
154		return;
155	}
156
157	DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
158		gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
159	for(i=0; i<gacl->acl_nace; i++)
160	{
161		struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
162		DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
163			i, gace->aceType, gace->aceFlags, gace->aceMask,
164			gace->aceIFlags, gace->aceWho));
165	}
166}
167
168static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
169{
170	struct gpfs_acl *acl;
171	size_t len = 200;
172	int ret;
173	TALLOC_CTX *mem_ctx = talloc_tos();
174
175	acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
176	if (acl == NULL) {
177		errno = ENOMEM;
178		return NULL;
179	}
180
181	acl->acl_len = len;
182	acl->acl_level = 0;
183	acl->acl_version = 0;
184	acl->acl_type = type;
185
186	ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
187	if ((ret != 0) && (errno == ENOSPC)) {
188		struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
189			mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
190		if (new_acl == NULL) {
191			errno = ENOMEM;
192			return NULL;
193		}
194
195		new_acl->acl_len = acl->acl_len;
196		new_acl->acl_level = acl->acl_level;
197		new_acl->acl_version = acl->acl_version;
198		new_acl->acl_type = acl->acl_type;
199		acl = new_acl;
200
201		ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
202	}
203	if (ret != 0)
204	{
205		DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
206		return NULL;
207	}
208
209	return acl;
210}
211
212/* Tries to get nfs4 acls and returns SMB ACL allocated.
213 * On failure returns 1 if it got non-NFSv4 ACL to prompt
214 * retry with POSIX ACL checks.
215 * On failure returns -1 if there is system (GPFS) error, check errno.
216 * Returns 0 on success
217 */
218static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
219{
220	int i;
221	struct gpfs_acl *gacl = NULL;
222	DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
223
224	/* First get the real acl length */
225	gacl = gpfs_getacl_alloc(fname, 0);
226	if (gacl == NULL) {
227		DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
228			   fname, strerror(errno)));
229		return -1;
230	}
231
232	if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
233		DEBUG(10, ("Got non-nfsv4 acl\n"));
234		/* Retry with POSIX ACLs check */
235		return 1;
236	}
237
238	*ppacl = smb_create_smb4acl();
239
240	DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
241		   gacl->acl_len, gacl->acl_level, gacl->acl_version,
242		   gacl->acl_nace));
243
244	for (i=0; i<gacl->acl_nace; i++) {
245		struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
246		SMB_ACE4PROP_T smbace;
247		DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
248			   "who: %d\n", gace->aceType, gace->aceIFlags,
249			   gace->aceFlags, gace->aceMask, gace->aceWho));
250
251		ZERO_STRUCT(smbace);
252		if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
253			smbace.flags |= SMB_ACE4_ID_SPECIAL;
254			switch (gace->aceWho) {
255			case ACE4_SPECIAL_OWNER:
256				smbace.who.special_id = SMB_ACE4_WHO_OWNER;
257				break;
258			case ACE4_SPECIAL_GROUP:
259				smbace.who.special_id = SMB_ACE4_WHO_GROUP;
260				break;
261			case ACE4_SPECIAL_EVERYONE:
262				smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
263				break;
264			default:
265				DEBUG(8, ("invalid special gpfs id %d "
266					  "ignored\n", gace->aceWho));
267				continue; /* don't add it */
268			}
269		} else {
270			if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
271				smbace.who.gid = gace->aceWho;
272			else
273				smbace.who.uid = gace->aceWho;
274		}
275
276		/* remove redundent deny entries */
277		if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
278			struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
279			if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
280			    prev->aceFlags == gace->aceFlags &&
281			    prev->aceIFlags == gace->aceIFlags &&
282			    (gace->aceMask & prev->aceMask) == 0 &&
283			    gace->aceWho == prev->aceWho) {
284				/* its redundent - skip it */
285				continue;
286			}
287		}
288
289		smbace.aceType = gace->aceType;
290		smbace.aceFlags = gace->aceFlags;
291		smbace.aceMask = gace->aceMask;
292		smb_add_ace4(*ppacl, &smbace);
293	}
294
295	return 0;
296}
297
298static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
299	files_struct *fsp, uint32 security_info,
300	SEC_DESC **ppdesc)
301{
302	SMB4ACL_T *pacl = NULL;
303	int	result;
304
305	*ppdesc = NULL;
306	result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
307
308	if (result == 0)
309		return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
310
311	if (result > 0) {
312		DEBUG(10, ("retrying with posix acl...\n"));
313		return posix_fget_nt_acl(fsp, security_info, ppdesc);
314	}
315
316	/* GPFS ACL was not read, something wrong happened, error code is set in errno */
317	return map_nt_error_from_unix(errno);
318}
319
320static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
321	const char *name,
322	uint32 security_info, SEC_DESC **ppdesc)
323{
324	SMB4ACL_T *pacl = NULL;
325	int	result;
326
327	*ppdesc = NULL;
328	result = gpfs_get_nfs4_acl(name, &pacl);
329
330	if (result == 0)
331		return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
332
333	if (result > 0) {
334		DEBUG(10, ("retrying with posix acl...\n"));
335		return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
336	}
337
338	/* GPFS ACL was not read, something wrong happened, error code is set in errno */
339	return map_nt_error_from_unix(errno);
340}
341
342static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
343{
344	int ret;
345	gpfs_aclLen_t gacl_len;
346	SMB4ACE_T	*smbace;
347	struct gpfs_acl *gacl;
348	TALLOC_CTX *mem_ctx  = talloc_tos();
349
350	gacl_len = sizeof(struct gpfs_acl) +
351		(smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
352
353	gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
354	if (gacl == NULL) {
355		DEBUG(0, ("talloc failed\n"));
356		errno = ENOMEM;
357		return False;
358	}
359
360	gacl->acl_len = gacl_len;
361	gacl->acl_level = 0;
362	gacl->acl_version = GPFS_ACL_VERSION_NFS4;
363	gacl->acl_type = GPFS_ACL_TYPE_NFS4;
364	gacl->acl_nace = 0; /* change later... */
365
366	for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
367		struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
368		SMB_ACE4PROP_T	*aceprop = smb_get_ace4(smbace);
369
370		gace->aceType = aceprop->aceType;
371		gace->aceFlags = aceprop->aceFlags;
372		gace->aceMask = aceprop->aceMask;
373
374		/*
375		 * GPFS can't distinguish between WRITE and APPEND on
376		 * files, so one being set without the other is an
377		 * error. Sorry for the many ()'s :-)
378		 */
379
380		if (!fsp->is_directory
381		    &&
382		    ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
383		      && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
384		     ||
385		     (((gace->aceMask & ACE4_MASK_WRITE) != 0)
386		      && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
387		    &&
388		    lp_parm_bool(fsp->conn->params->service, "gpfs",
389				 "merge_writeappend", True)) {
390			DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
391				  "WRITE^APPEND, setting WRITE|APPEND\n",
392				  fsp_str_dbg(fsp)));
393			gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
394		}
395
396		gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
397
398		if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
399		{
400			switch(aceprop->who.special_id)
401			{
402			case SMB_ACE4_WHO_EVERYONE:
403				gace->aceWho = ACE4_SPECIAL_EVERYONE;
404				break;
405			case SMB_ACE4_WHO_OWNER:
406				gace->aceWho = ACE4_SPECIAL_OWNER;
407				break;
408			case SMB_ACE4_WHO_GROUP:
409				gace->aceWho = ACE4_SPECIAL_GROUP;
410				break;
411			default:
412				DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
413				continue; /* don't add it !!! */
414			}
415		} else {
416			/* just only for the type safety... */
417			if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
418				gace->aceWho = aceprop->who.gid;
419			else
420				gace->aceWho = aceprop->who.uid;
421		}
422
423		gacl->acl_nace++;
424	}
425
426	ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
427			       GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
428	if (ret != 0) {
429		DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
430		gpfs_dumpacl(8, gacl);
431		return False;
432	}
433
434	DEBUG(10, ("gpfs_putacl succeeded\n"));
435	return True;
436}
437
438static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
439{
440	struct gpfs_acl *acl;
441	NTSTATUS result = NT_STATUS_ACCESS_DENIED;
442
443	acl = gpfs_getacl_alloc(fsp->fsp_name->base_name, 0);
444	if (acl == NULL)
445		return result;
446
447	if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
448	{
449		if (lp_parm_bool(fsp->conn->params->service, "gpfs",
450				 "refuse_dacl_protected", false)
451		    && (psd->type&SEC_DESC_DACL_PROTECTED)) {
452			DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
453			return NT_STATUS_NOT_SUPPORTED;
454		}
455
456		result = smb_set_nt_acl_nfs4(
457			fsp, security_info_sent, psd,
458			gpfsacl_process_smbacl);
459	} else { /* assume POSIX ACL - by default... */
460		result = set_nt_acl(fsp, security_info_sent, psd);
461	}
462
463	return result;
464}
465
466static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
467{
468	return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
469}
470
471static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
472{
473	SMB_ACL_T result;
474	int i;
475
476	result = sys_acl_init(pacl->acl_nace);
477	if (result == NULL) {
478		errno = ENOMEM;
479		return NULL;
480	}
481
482	result->count = pacl->acl_nace;
483
484	for (i=0; i<pacl->acl_nace; i++) {
485		struct smb_acl_entry *ace = &result->acl[i];
486		const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
487
488		DEBUG(10, ("Converting type %d id %lu perm %x\n",
489			   (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
490			   (int)g_ace->ace_perm));
491
492		switch (g_ace->ace_type) {
493		case GPFS_ACL_USER:
494			ace->a_type = SMB_ACL_USER;
495			ace->uid = (uid_t)g_ace->ace_who;
496			break;
497		case GPFS_ACL_USER_OBJ:
498			ace->a_type = SMB_ACL_USER_OBJ;
499			break;
500		case GPFS_ACL_GROUP:
501			ace->a_type = SMB_ACL_GROUP;
502			ace->gid = (gid_t)g_ace->ace_who;
503			break;
504		case GPFS_ACL_GROUP_OBJ:
505 			ace->a_type = SMB_ACL_GROUP_OBJ;
506			break;
507		case GPFS_ACL_OTHER:
508			ace->a_type = SMB_ACL_OTHER;
509			break;
510		case GPFS_ACL_MASK:
511			ace->a_type = SMB_ACL_MASK;
512			break;
513		default:
514			DEBUG(10, ("Got invalid ace_type: %d\n",
515				   g_ace->ace_type));
516			errno = EINVAL;
517			SAFE_FREE(result);
518			return NULL;
519		}
520
521		ace->a_perm = 0;
522		ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
523			SMB_ACL_READ : 0;
524		ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
525			SMB_ACL_WRITE : 0;
526		ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
527			SMB_ACL_EXECUTE : 0;
528
529		DEBUGADD(10, ("Converted to %d perm %x\n",
530			      ace->a_type, ace->a_perm));
531	}
532
533	return result;
534}
535
536static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
537{
538	struct gpfs_acl *pacl;
539	SMB_ACL_T result = NULL;
540
541	pacl = gpfs_getacl_alloc(path, type);
542
543	if (pacl == NULL) {
544		DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
545			   path, strerror(errno)));
546		if (errno == 0) {
547			errno = EINVAL;
548		}
549		goto done;
550	}
551
552	if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
553		DEBUG(10, ("Got acl version %d, expected %d\n",
554			   pacl->acl_version, GPFS_ACL_VERSION_POSIX));
555		errno = EINVAL;
556		goto done;
557	}
558
559	DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
560		   pacl->acl_len, pacl->acl_level, pacl->acl_version,
561		   pacl->acl_nace));
562
563	result = gpfs2smb_acl(pacl);
564	if (result == NULL) {
565		goto done;
566	}
567
568 done:
569
570	if (errno != 0) {
571		SAFE_FREE(result);
572	}
573	return result;
574}
575
576static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
577					  const char *path_p,
578					  SMB_ACL_TYPE_T type)
579{
580	gpfs_aclType_t gpfs_type;
581
582	switch(type) {
583	case SMB_ACL_TYPE_ACCESS:
584		gpfs_type = GPFS_ACL_TYPE_ACCESS;
585		break;
586	case SMB_ACL_TYPE_DEFAULT:
587		gpfs_type = GPFS_ACL_TYPE_DEFAULT;
588		break;
589	default:
590		DEBUG(0, ("Got invalid type: %d\n", type));
591		smb_panic("exiting");
592	}
593
594	return gpfsacl_get_posix_acl(path_p, gpfs_type);
595}
596
597static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
598					files_struct *fsp)
599{
600	return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
601				     GPFS_ACL_TYPE_ACCESS);
602}
603
604static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
605				     SMB_ACL_TYPE_T type)
606{
607	gpfs_aclLen_t len;
608	struct gpfs_acl *result;
609	int i;
610	union gpfs_ace_union
611	{
612		gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
613		gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
614	};
615
616	DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
617
618	len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
619		(pacl->count)*sizeof(gpfs_ace_v1_t);
620
621	result = (struct gpfs_acl *)SMB_MALLOC(len);
622	if (result == NULL) {
623		errno = ENOMEM;
624		return result;
625	}
626
627	result->acl_len = len;
628	result->acl_level = 0;
629	result->acl_version = GPFS_ACL_VERSION_POSIX;
630	result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
631		GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
632	result->acl_nace = pacl->count;
633
634	for (i=0; i<pacl->count; i++) {
635		const struct smb_acl_entry *ace = &pacl->acl[i];
636		struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
637
638		DEBUG(10, ("Converting type %d perm %x\n",
639			   (int)ace->a_type, (int)ace->a_perm));
640
641		g_ace->ace_perm = 0;
642
643		switch(ace->a_type) {
644		case SMB_ACL_USER:
645			g_ace->ace_type = GPFS_ACL_USER;
646			g_ace->ace_who = (gpfs_uid_t)ace->uid;
647			break;
648		case SMB_ACL_USER_OBJ:
649			g_ace->ace_type = GPFS_ACL_USER_OBJ;
650			g_ace->ace_perm |= ACL_PERM_CONTROL;
651			g_ace->ace_who = 0;
652			break;
653		case SMB_ACL_GROUP:
654			g_ace->ace_type = GPFS_ACL_GROUP;
655			g_ace->ace_who = (gpfs_uid_t)ace->gid;
656			break;
657		case SMB_ACL_GROUP_OBJ:
658			g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
659			g_ace->ace_who = 0;
660			break;
661		case SMB_ACL_MASK:
662			g_ace->ace_type = GPFS_ACL_MASK;
663			g_ace->ace_perm = 0x8f;
664			g_ace->ace_who = 0;
665			break;
666		case SMB_ACL_OTHER:
667			g_ace->ace_type = GPFS_ACL_OTHER;
668			g_ace->ace_who = 0;
669			break;
670		default:
671			DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
672			errno = EINVAL;
673			SAFE_FREE(result);
674			return NULL;
675		}
676
677		g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
678			ACL_PERM_READ : 0;
679		g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
680			ACL_PERM_WRITE : 0;
681		g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
682			ACL_PERM_EXECUTE : 0;
683
684		DEBUGADD(10, ("Converted to %d id %d perm %x\n",
685			      g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
686	}
687
688	return result;
689}
690
691static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
692				    const char *name,
693				    SMB_ACL_TYPE_T type,
694				    SMB_ACL_T theacl)
695{
696	struct gpfs_acl *gpfs_acl;
697	int result;
698
699	gpfs_acl = smb2gpfs_acl(theacl, type);
700	if (gpfs_acl == NULL) {
701		return -1;
702	}
703
704	result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
705
706	SAFE_FREE(gpfs_acl);
707	return result;
708}
709
710static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
711				  files_struct *fsp,
712				  SMB_ACL_T theacl)
713{
714	return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
715					SMB_ACL_TYPE_ACCESS, theacl);
716}
717
718static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
719					   const char *path)
720{
721	errno = ENOTSUP;
722	return -1;
723}
724
725/*
726 * Assumed: mode bits are shiftable and standard
727 * Output: the new aceMask field for an smb nfs4 ace
728 */
729static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
730{
731	const uint32 posix_nfs4map[3] = {
732                SMB_ACE4_EXECUTE, /* execute */
733		SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
734                SMB_ACE4_READ_DATA /* read */
735	};
736	int     i;
737	uint32_t        posix_mask = 0x01;
738	uint32_t        posix_bit;
739	uint32_t        nfs4_bits;
740
741	for(i=0; i<3; i++) {
742		nfs4_bits = posix_nfs4map[i];
743		posix_bit = rwx & posix_mask;
744
745		if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
746			if (posix_bit)
747				aceMask |= nfs4_bits;
748			else
749				aceMask &= ~nfs4_bits;
750		} else {
751			/* add deny bits when suitable */
752			if (!posix_bit)
753				aceMask |= nfs4_bits;
754			else
755				aceMask &= ~nfs4_bits;
756		} /* other ace types are unexpected */
757
758		posix_mask <<= 1;
759	}
760
761	return aceMask;
762}
763
764static int gpfsacl_emu_chmod(const char *path, mode_t mode)
765{
766	SMB4ACL_T *pacl = NULL;
767	int     result;
768	bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
769	int     i;
770	files_struct    fake_fsp; /* TODO: rationalize parametrization */
771	SMB4ACE_T       *smbace;
772	NTSTATUS status;
773
774	DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
775
776	result = gpfs_get_nfs4_acl(path, &pacl);
777	if (result)
778		return result;
779
780	if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
781		DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
782	}
783
784	for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
785		SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
786		uint32_t        specid = ace->who.special_id;
787
788		if (ace->flags&SMB_ACE4_ID_SPECIAL &&
789		    ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
790		    specid <= SMB_ACE4_WHO_EVERYONE) {
791
792			uint32_t newMask;
793
794			if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
795				haveAllowEntry[specid] = True;
796
797			/* mode >> 6 for @owner, mode >> 3 for @group,
798			 * mode >> 0 for @everyone */
799			newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
800						      mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
801			if (ace->aceMask!=newMask) {
802				DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
803					   path, ace->aceMask, newMask, specid));
804			}
805			ace->aceMask = newMask;
806		}
807	}
808
809	/* make sure we have at least ALLOW entries
810	 * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
811	 * - if necessary
812	 */
813	for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
814		SMB_ACE4PROP_T  ace;
815
816		if (haveAllowEntry[i]==True)
817			continue;
818
819		ZERO_STRUCT(ace);
820		ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
821		ace.flags |= SMB_ACE4_ID_SPECIAL;
822		ace.who.special_id = i;
823
824		if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
825			ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
826
827		ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
828						  mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
829
830		/* don't add unnecessary aces */
831		if (!ace.aceMask)
832			continue;
833
834		/* we add it to the END - as windows expects allow aces */
835		smb_add_ace4(pacl, &ace);
836		DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
837			   path, mode, i, ace.aceMask));
838	}
839
840	/* don't add complementary DENY ACEs here */
841	ZERO_STRUCT(fake_fsp);
842	status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
843					    &fake_fsp.fsp_name);
844	if (!NT_STATUS_IS_OK(status)) {
845		errno = map_errno_from_nt_status(status);
846		return -1;
847	}
848	/* put the acl */
849	if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) {
850		TALLOC_FREE(fake_fsp.fsp_name);
851		return -1;
852	}
853
854	TALLOC_FREE(fake_fsp.fsp_name);
855	return 0; /* ok for [f]chmod */
856}
857
858static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
859{
860	struct smb_filename *smb_fname_cpath;
861	int rc;
862	NTSTATUS status;
863
864	status = create_synthetic_smb_fname(
865		talloc_tos(), path, NULL, NULL, &smb_fname_cpath);
866
867	if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
868		return -1;
869	}
870
871	/* avoid chmod() if possible, to preserve acls */
872	if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
873		return 0;
874	}
875
876	rc = gpfsacl_emu_chmod(path, mode);
877	if (rc == 1)
878		return SMB_VFS_NEXT_CHMOD(handle, path, mode);
879	return rc;
880}
881
882static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
883{
884		 SMB_STRUCT_STAT st;
885		 int rc;
886
887		 if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
888			 return -1;
889		 }
890
891		 /* avoid chmod() if possible, to preserve acls */
892		 if ((st.st_ex_mode & ~S_IFMT) == mode) {
893			 return 0;
894		 }
895
896		 rc = gpfsacl_emu_chmod(fsp->fsp_name->base_name, mode);
897		 if (rc == 1)
898			 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
899		 return rc;
900}
901
902static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
903                           const char *name, const void *value, size_t size,  int flags){
904        const char *attrstr = value;
905        unsigned int dosmode=0;
906        struct gpfs_winattr attrs;
907        int ret = 0;
908
909        DEBUG(10, ("gpfs_set_xattr: %s \n",path));
910
911        /* Only handle DOS Attributes */
912        if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
913		DEBUG(1, ("gpfs_set_xattr:name is %s\n",name));
914		return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
915        }
916
917        if (size < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
918                                sscanf(attrstr, "%x", &dosmode) != 1) {
919                        DEBUG(1,("gpfs_set_xattr: Trying to set badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
920                return False;
921        }
922
923        attrs.winAttrs = 0;
924        /*Just map RD_ONLY, ARCHIVE, SYSTEM and HIDDEN. Ignore the others*/
925        if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
926                attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
927        }
928        if (dosmode & FILE_ATTRIBUTE_HIDDEN){
929                        attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
930                }
931        if (dosmode & FILE_ATTRIBUTE_SYSTEM){
932                        attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
933                }
934        if (dosmode & FILE_ATTRIBUTE_READONLY){
935                        attrs.winAttrs |= GPFS_WINATTR_READONLY;
936        }
937
938
939        ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
940				GPFS_WINATTR_SET_ATTRS, &attrs);
941        if ( ret == -1){
942		if (errno == ENOSYS) {
943			return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
944						     size, flags);
945		}
946
947                DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
948                return -1;
949        }
950
951        DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
952        return 0;
953}
954
955static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
956                              const char *name, void *value, size_t size){
957        char *attrstr = value;
958        unsigned int dosmode = 0;
959        struct gpfs_winattr attrs;
960        int ret = 0;
961
962        DEBUG(10, ("gpfs_get_xattr: %s \n",path));
963
964        /* Only handle DOS Attributes */
965        if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
966                DEBUG(1, ("gpfs_get_xattr:name is %s\n",name));
967                return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
968        }
969
970        ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
971        if ( ret == -1){
972		if (errno == ENOSYS) {
973			return SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
974						     size);
975		}
976
977                DEBUG(1, ("gpfs_get_xattr: Get GPFS attributes failed: %d\n",ret));
978                return -1;
979        }
980
981        DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
982
983        /*Just map RD_ONLY, ARCHIVE, SYSTEM and HIDDEN. Ignore the others*/
984        if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
985                dosmode |= FILE_ATTRIBUTE_ARCHIVE;
986        }
987        if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
988                dosmode |= FILE_ATTRIBUTE_HIDDEN;
989        }
990        if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
991                dosmode |= FILE_ATTRIBUTE_SYSTEM;
992        }
993        if (attrs.winAttrs & GPFS_WINATTR_READONLY){
994                dosmode |= FILE_ATTRIBUTE_READONLY;
995        }
996
997        snprintf(attrstr, size, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
998        DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
999        return size;
1000}
1001
1002static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1003			 struct smb_filename *smb_fname)
1004{
1005	struct gpfs_winattr attrs;
1006	char *fname = NULL;
1007	NTSTATUS status;
1008	int ret;
1009
1010	ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1011	if (ret == -1) {
1012		return -1;
1013	}
1014	status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1015	if (!NT_STATUS_IS_OK(status)) {
1016		errno = map_errno_from_nt_status(status);
1017		return -1;
1018	}
1019	ret = get_gpfs_winattrs(CONST_DISCARD(char *, fname), &attrs);
1020	TALLOC_FREE(fname);
1021	if (ret == 0) {
1022		smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1023		smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1024	}
1025	return 0;
1026}
1027
1028static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1029			  struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1030{
1031	struct gpfs_winattr attrs;
1032	int ret;
1033
1034	ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1035	if (ret == -1) {
1036		return -1;
1037	}
1038	if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1039		return 0;
1040	}
1041	ret = smbd_fget_gpfs_winattrs(fsp->fh->fd, &attrs);
1042	if (ret == 0) {
1043		sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1044		sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1045	}
1046	return 0;
1047}
1048
1049static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1050			  struct smb_filename *smb_fname)
1051{
1052	struct gpfs_winattr attrs;
1053	char *path = NULL;
1054	NTSTATUS status;
1055	int ret;
1056
1057	ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1058	if (ret == -1) {
1059		return -1;
1060	}
1061	status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1062	if (!NT_STATUS_IS_OK(status)) {
1063		errno = map_errno_from_nt_status(status);
1064		return -1;
1065	}
1066	ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1067	TALLOC_FREE(path);
1068	if (ret == 0) {
1069		smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1070		smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1071	}
1072	return 0;
1073}
1074
1075static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1076                        const struct smb_filename *smb_fname,
1077			struct smb_file_time *ft)
1078{
1079
1080        struct gpfs_winattr attrs;
1081        int ret;
1082        char *path = NULL;
1083        NTSTATUS status;
1084
1085        ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1086        if(ret == -1){
1087                DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed\n"));
1088                return -1;
1089        }
1090
1091        if(null_timespec(ft->create_time)){
1092                DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1093                return 0;
1094        }
1095
1096        status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1097        if (!NT_STATUS_IS_OK(status)) {
1098                errno = map_errno_from_nt_status(status);
1099                return -1;
1100        }
1101
1102        attrs.winAttrs = 0;
1103        attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1104        attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1105
1106        ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
1107                                GPFS_WINATTR_SET_CREATION_TIME, &attrs);
1108        if(ret == -1 && errno != ENOSYS){
1109                DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1110	        return -1;
1111        }
1112        return 0;
1113
1114}
1115
1116static struct vfs_fn_pointers vfs_gpfs_fns = {
1117	.kernel_flock = vfs_gpfs_kernel_flock,
1118        .linux_setlease = vfs_gpfs_setlease,
1119        .get_real_filename = vfs_gpfs_get_real_filename,
1120        .fget_nt_acl = gpfsacl_fget_nt_acl,
1121        .get_nt_acl = gpfsacl_get_nt_acl,
1122        .fset_nt_acl = gpfsacl_fset_nt_acl,
1123        .sys_acl_get_file = gpfsacl_sys_acl_get_file,
1124        .sys_acl_get_fd = gpfsacl_sys_acl_get_fd,
1125        .sys_acl_set_file = gpfsacl_sys_acl_set_file,
1126        .sys_acl_set_fd = gpfsacl_sys_acl_set_fd,
1127        .sys_acl_delete_def_file = gpfsacl_sys_acl_delete_def_file,
1128        .chmod = vfs_gpfs_chmod,
1129        .fchmod = vfs_gpfs_fchmod,
1130        .close_fn = vfs_gpfs_close,
1131        .setxattr = gpfs_set_xattr,
1132        .getxattr = gpfs_get_xattr,
1133        .stat = vfs_gpfs_stat,
1134        .fstat = vfs_gpfs_fstat,
1135        .lstat = vfs_gpfs_lstat,
1136	.ntimes = vfs_gpfs_ntimes,
1137};
1138
1139NTSTATUS vfs_gpfs_init(void);
1140NTSTATUS vfs_gpfs_init(void)
1141{
1142	init_gpfs();
1143
1144	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
1145				&vfs_gpfs_fns);
1146}
1147