r23779: Change from v2 or later to v3 or later.
[ira/wip.git] / source3 / modules / vfs_aixacl2.c
1 /*
2  * Convert JFS2 NFS4/AIXC acls to NT acls and vice versa.
3  *
4  * Copyright (C) Volker Lendecke, 2006
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22 #include "nfs4_acls.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_VFS
26
27 #define AIXACL2_MODULE_NAME "aixacl2"
28
29 extern struct current_user current_user;
30 extern int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid);
31 extern BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp,
32         uint32 security_info_sent, SEC_DESC *psd);
33
34 extern SMB_ACL_T aixacl_to_smbacl( struct acl *file_acl);
35 extern struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
36
37 typedef union aixjfs2_acl_t {
38         nfs4_acl_int_t jfs2_acl[1];
39         aixc_acl_t aixc_acl[1];
40 }AIXJFS2_ACL_T;
41
42 static int32_t aixacl2_getlen(AIXJFS2_ACL_T *acl, acl_type_t *type)
43 {
44         int32_t len;
45  
46                 if(type->u64 == ACL_NFS4) {
47                         len = acl->jfs2_acl[0].aclLength;
48                 }       
49                 else {
50                         if(type->u64 == ACL_AIXC) {
51                                 len = acl->aixc_acl[0].acl_len;
52                         } else {
53                                 DEBUG(0,("aixacl2_getlen:unknown type:%d\n",type->u64));
54                                 return False;
55                         }       
56                 }               
57                 DEBUG(10,("aixacl2_getlen:%d\n",len));
58         return len;
59 }
60
61 static AIXJFS2_ACL_T *aixjfs2_getacl_alloc(const char *fname, acl_type_t *type)
62 {
63         AIXJFS2_ACL_T *acl;
64         size_t len = 200;
65         mode_t mode;
66         int ret;
67         uint64_t ctl_flag=0;
68         TALLOC_CTX      *mem_ctx;
69
70         mem_ctx = main_loop_talloc_get();
71         acl = (AIXJFS2_ACL_T *)TALLOC_SIZE(mem_ctx, len);
72         if (acl == NULL) {
73                 errno = ENOMEM;
74                 return NULL;
75         }
76
77         if(type->u64 == ACL_ANY) {
78                 ctl_flag = ctl_flag | GET_ACLINFO_ONLY;
79         }
80
81         ret = aclx_get((char *)fname, ctl_flag, type, acl, &len, &mode);
82         if ((ret != 0) && (errno == ENOSPC)) {
83                 len = aixacl2_getlen(acl, type) + sizeof(AIXJFS2_ACL_T);
84                 DEBUG(10,("aixjfs2_getacl_alloc - acl_len:%d\n",len));
85
86                 acl = (AIXJFS2_ACL_T *)TALLOC_SIZE(mem_ctx, len);
87                 if (acl == NULL) {
88                         errno = ENOMEM;
89                         return NULL;
90                 }
91
92                 ret = aclx_get((char *)fname, ctl_flag, type, acl, &len, &mode);
93         }
94         if (ret != 0) {
95                 DEBUG(8, ("aclx_get failed with %s\n", strerror(errno)));
96                 return NULL;
97         }
98
99         return acl;
100 }
101
102 static BOOL aixjfs2_get_nfs4_acl(files_struct *fsp,
103         SMB4ACL_T **ppacl, BOOL *pretryPosix)
104 {
105         int32_t i;
106         
107         AIXJFS2_ACL_T *pacl = NULL;
108         nfs4_acl_int_t *jfs2_acl = NULL;
109         nfs4_ace_int_t *jfs2_ace = NULL;
110         acl_type_t type;
111
112         DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", fsp->fsp_name));
113
114         memset(&type, 0, sizeof(acl_type_t));
115         type.u64 = ACL_NFS4;
116
117         pacl = aixjfs2_getacl_alloc(fsp->fsp_name, &type);
118         if (pacl == NULL) {
119                 DEBUG(9, ("aixjfs2_getacl_alloc failed for %s with %s\n",
120                                 fsp->fsp_name, strerror(errno)));
121                 if (errno==ENOSYS)
122                         *pretryPosix = True;
123                 return False;
124         }
125
126         jfs2_acl = &pacl->jfs2_acl[0];
127         DEBUG(10, ("len: %d, version: %d, nace: %d, type: 0x%x\n",
128                         jfs2_acl->aclLength, jfs2_acl->aclVersion, jfs2_acl->aclEntryN, type.u64));
129
130         *ppacl = smb_create_smb4acl();
131         if (*ppacl==NULL)
132                 return False;
133
134         jfs2_ace = &jfs2_acl->aclEntry[0];
135         for (i=0; i<jfs2_acl->aclEntryN; i++) {
136                 SMB_ACE4PROP_T aceprop;
137
138                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
139                                 "who: %d, aclLen: %d\n", jfs2_ace->aceType, jfs2_ace->flags,
140                                 jfs2_ace->aceFlags, jfs2_ace->aceMask, jfs2_ace->aceWho.id, jfs2_ace->entryLen));
141
142                 aceprop.aceType = jfs2_ace->aceType;
143                 aceprop.aceFlags = jfs2_ace->aceFlags;
144                 aceprop.aceMask = jfs2_ace->aceMask;
145                 aceprop.flags = (jfs2_ace->flags&ACE4_ID_SPECIAL) ? SMB_ACE4_ID_SPECIAL : 0;
146
147                 /* don't care it's real content is only 16 or 32 bit */
148                 aceprop.who.id = jfs2_ace->aceWho.id;
149
150                 if (smb_add_ace4(*ppacl, &aceprop)==NULL)
151                         return False;
152
153                 /* iterate to the next jfs2 ace */
154                 jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2_ace) + jfs2_ace->entryLen);
155         }
156
157         DEBUG(10,("jfs2 get_nt_acl finished successfully\n"));
158
159         return True;
160 }
161
162 static size_t aixjfs2_get_nt_acl_common(files_struct *fsp,
163         uint32 security_info, SEC_DESC **ppdesc)
164 {
165         SMB4ACL_T *pacl = NULL;
166         BOOL    result;
167         BOOL    retryPosix = False;
168
169         *ppdesc = NULL;
170         result = aixjfs2_get_nfs4_acl(fsp, &pacl, &retryPosix);
171         if (retryPosix)
172         {
173                 DEBUG(10, ("retrying with posix acl...\n"));
174                 return get_nt_acl(fsp, security_info, ppdesc);
175         }
176         if (result==False)
177                 return 0;
178
179         return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
180 }
181
182 size_t aixjfs2_fget_nt_acl(vfs_handle_struct *handle,
183         files_struct *fsp, int fd, uint32 security_info,
184         SEC_DESC **ppdesc)
185 {
186         return aixjfs2_get_nt_acl_common(fsp, security_info, ppdesc);
187 }
188
189 size_t aixjfs2_get_nt_acl(vfs_handle_struct *handle,
190         files_struct *fsp, const char *name,
191         uint32 security_info, SEC_DESC **ppdesc)
192 {
193         return aixjfs2_get_nt_acl_common(fsp, security_info, ppdesc);
194 }
195
196 static SMB_ACL_T aixjfs2_get_posix_acl(const char *path, acl_type_t type)
197 {
198         aixc_acl_t *pacl;
199         AIXJFS2_ACL_T *acl;
200         SMB_ACL_T result = NULL;
201         int ret;
202
203         acl = aixjfs2_getacl_alloc(path, &type);
204
205         if (acl == NULL) {
206                 DEBUG(10, ("aixjfs2_getacl failed for %s with %s\n",
207                            path, strerror(errno)));
208                 if (errno == 0) {
209                         errno = EINVAL;
210                 }
211                 goto done;
212         }
213
214         pacl = &acl->aixc_acl[0];
215         DEBUG(10, ("len: %d, mode: %d\n",
216                    pacl->acl_len, pacl->acl_mode));
217
218         result = aixacl_to_smbacl(pacl);
219         if (result == NULL) {
220                 goto done;
221         }
222
223  done:
224         if (errno != 0) {
225                 SAFE_FREE(result);
226         }
227         return result;
228 }
229
230 SMB_ACL_T aixjfs2_sys_acl_get_file(vfs_handle_struct *handle,
231                                     const char *path_p,
232                                     SMB_ACL_TYPE_T type)
233 {
234         acl_type_t aixjfs2_type;
235
236         switch(type) {
237         case SMB_ACL_TYPE_ACCESS:
238                 aixjfs2_type.u64 = ACL_AIXC;
239                 break;
240         case SMB_ACL_TYPE_DEFAULT:
241                 DEBUG(0, ("Got AIX JFS2 unsupported type: %d\n", type));
242                 return NULL;
243         default:
244                 DEBUG(0, ("Got invalid type: %d\n", type));
245                 smb_panic("exiting");
246         }
247
248         return aixjfs2_get_posix_acl(path_p, aixjfs2_type);
249 }
250
251 SMB_ACL_T aixjfs2_sys_acl_get_fd(vfs_handle_struct *handle,
252                                   files_struct *fsp,
253                                   int fd)
254 {
255         acl_type_t aixjfs2_type;
256         aixjfs2_type.u64 = ACL_AIXC;
257
258         return aixjfs2_get_posix_acl(fsp->fsp_name, aixjfs2_type);
259 }
260
261 /*
262  * Test whether we have that aclType support on the given path
263  */
264 static int aixjfs2_query_acl_support(
265         char *filepath,
266         uint64_t aclType,
267         acl_type_t *pacl_type_info
268 )
269 {
270         acl_types_list_t        acl_type_list;
271         size_t  acl_type_list_len = sizeof(acl_types_list_t);
272         uint32_t        i;
273
274         memset(&acl_type_list, 0, sizeof(acl_type_list));
275
276         if (aclx_gettypes(filepath, &acl_type_list, &acl_type_list_len)) {
277                 DEBUG(2, ("aclx_gettypes failed with error %s for %s\n",
278                         strerror(errno), filepath));
279                 return -1;
280         }
281
282         for(i=0; i<acl_type_list.num_entries; i++) {
283                 if (acl_type_list.entries[i].u64==aclType) {
284                         memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
285                         DEBUG(10, ("found %s ACL support for %s\n",
286                                 pacl_type_info->acl_type, filepath));
287                         return 0;
288                 }
289         }
290
291         return 1; /* haven't found that ACL type. */
292 }
293
294 static BOOL aixjfs2_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
295 {
296         SMB4ACE_T       *smbace;
297         TALLOC_CTX      *mem_ctx;
298         nfs4_acl_int_t  *jfs2acl;
299         int32_t entryLen;
300         uint32  aclLen, naces;
301         int     rc;
302         acl_type_t      acltype;
303
304         DEBUG(10, ("jfs2_process_smbacl invoked on %s\n", fsp->fsp_name));
305
306         /* no need to be freed which is alloced with mem_ctx */
307         mem_ctx = main_loop_talloc_get();
308
309         entryLen = sizeof(nfs4_ace_int_t);
310         if (entryLen & 0x03)
311                 entryLen = entryLen + 4 - (entryLen%4);
312
313         naces = smb_get_naces(smbacl);
314         aclLen = ACL_V4_SIZ + naces * entryLen;
315         jfs2acl = (nfs4_acl_int_t *)TALLOC_SIZE(mem_ctx, aclLen);
316         if (jfs2acl==NULL) {
317                 DEBUG(0, ("TALLOC_SIZE failed\n"));
318                 errno = ENOMEM;
319                 return False;
320         }
321
322         jfs2acl->aclLength = ACL_V4_SIZ;
323         jfs2acl->aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
324         jfs2acl->aclEntryN = 0;
325
326         for(smbace = smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace))
327         {
328                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
329                 nfs4_ace_int_t *jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2acl) + jfs2acl->aclLength);
330
331                 memset(jfs2_ace, 0, entryLen);
332                 jfs2_ace->entryLen = entryLen; /* won't store textual "who" */
333                 jfs2_ace->aceType = aceprop->aceType; /* only ACCES|DENY supported by jfs2 */
334                 jfs2_ace->aceFlags = aceprop->aceFlags;
335                 jfs2_ace->aceMask = aceprop->aceMask;
336                 jfs2_ace->flags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_ID_SPECIAL : 0;
337
338                 /* don't care it's real content is only 16 or 32 bit */
339                 jfs2_ace->aceWho.id = aceprop->who.id;
340
341                 /* iterate to the next jfs2 ace */
342                 jfs2acl->aclLength += jfs2_ace->entryLen;
343                 jfs2acl->aclEntryN++;
344         }
345         SMB_ASSERT(jfs2acl->aclEntryN==naces);
346
347         /* Don't query it (again) */
348         memset(&acltype, 0, sizeof(acl_type_t));
349         acltype.u64 = ACL_NFS4;
350
351         /* won't set S_ISUID - the only one JFS2/NFS4 accepts */
352         rc = aclx_put(
353                 fsp->fsp_name,
354                 SET_ACL, /* set only the ACL, not mode bits */
355                 acltype, /* not a pointer !!! */
356                 jfs2acl,
357                 jfs2acl->aclLength,
358                 0 /* don't set here mode bits */
359         );
360         if (rc) {
361                 DEBUG(8, ("aclx_put failed with %s\n", strerror(errno)));
362                 return False;
363         }
364
365         DEBUG(10, ("jfs2_process_smbacl succeeded.\n"));
366         return True;
367 }
368
369 static NTSTATUS aixjfs2_set_nt_acl_common(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
370 {
371         acl_type_t      acl_type_info;
372         NTSTATUS        result = NT_STATUS_ACCESS_DENIED;
373         int     rc;
374
375         rc = aixjfs2_query_acl_support(
376                 fsp->fsp_name,
377                 ACL_NFS4,
378                 &acl_type_info);
379
380         if (rc==0)
381         {
382                 result = smb_set_nt_acl_nfs4(
383                         fsp, security_info_sent, psd,
384                         aixjfs2_process_smbacl);
385         } else if (rc==1) { /* assume POSIX ACL - by default... */
386                 result = set_nt_acl(fsp, security_info_sent, psd);
387         } else
388                 result = map_nt_error_from_unix(errno); /* query failed */
389         
390         return result;
391 }
392
393 NTSTATUS aixjfs2_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
394 {
395         return aixjfs2_set_nt_acl_common(fsp, security_info_sent, psd);
396 }
397
398 NTSTATUS aixjfs2_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd)
399 {
400         return aixjfs2_set_nt_acl_common(fsp, security_info_sent, psd);
401 }
402
403 int aixjfs2_sys_acl_set_file(vfs_handle_struct *handle,
404                               const char *name,
405                               SMB_ACL_TYPE_T type,
406                               SMB_ACL_T theacl)
407 {
408         struct acl      *acl_aixc;
409         acl_type_t      acl_type_info;
410         int     rc;
411
412         DEBUG(10, ("aixjfs2_sys_acl_set_file invoked for %s", name));
413
414         rc = aixjfs2_query_acl_support((char *)name, ACL_AIXC, &acl_type_info);
415         if (rc) {
416                 DEBUG(8, ("jfs2_set_nt_acl: AIXC support not found\n"));
417                 return -1;
418         }
419
420         acl_aixc = aixacl_smb_to_aixacl(type, theacl);
421         if (!acl_aixc)
422                 return -1;
423
424         rc = aclx_put(
425                 (char *)name,
426                 SET_ACL, /* set only the ACL, not mode bits */
427                 acl_type_info,
428                 acl_aixc,
429                 acl_aixc->acl_len,
430                 0
431         );
432         if (rc) {
433                 DEBUG(2, ("aclx_put failed with %s for %s\n",
434                         strerror(errno), name));
435                 return -1;
436         }
437
438         return 0;
439 }
440
441 int aixjfs2_sys_acl_set_fd(vfs_handle_struct *handle,
442                             files_struct *fsp,
443                             int fd, SMB_ACL_T theacl)
444 {
445         struct acl      *acl_aixc;
446         acl_type_t      acl_type_info;
447         int     rc;
448
449         DEBUG(10, ("aixjfs2_sys_acl_set_fd invoked for %s", fsp->fsp_name));
450
451         rc = aixjfs2_query_acl_support(fsp->fsp_name, ACL_AIXC, &acl_type_info);
452         if (rc) {
453                 DEBUG(8, ("jfs2_set_nt_acl: AIXC support not found\n"));
454                 return -1;
455         }
456
457         acl_aixc = aixacl_smb_to_aixacl(SMB_ACL_TYPE_ACCESS, theacl);
458         if (!acl_aixc)
459                 return -1;
460
461         rc = aclx_fput(
462                 fd,
463                 SET_ACL, /* set only the ACL, not mode bits */
464                 acl_type_info,
465                 acl_aixc,
466                 acl_aixc->acl_len,
467                 0
468         );
469         if (rc) {
470                 DEBUG(2, ("aclx_fput failed with %s for %s\n",
471                         strerror(errno), fsp->fsp_name));
472                 return -1;
473         }
474
475         return 0;
476 }
477
478 int aixjfs2_sys_acl_delete_def_file(vfs_handle_struct *handle,
479                                      const char *path)
480 {
481         /* Not available under AIXC ACL */
482         /* Don't report here any error otherwise */
483         /* upper layer will break the normal execution */
484         return 0;
485 }
486
487
488 /* VFS operations structure */
489
490 static vfs_op_tuple aixjfs2_ops[] =
491 {
492         {SMB_VFS_OP(aixjfs2_fget_nt_acl),
493         SMB_VFS_OP_FGET_NT_ACL,
494         SMB_VFS_LAYER_TRANSPARENT},
495
496         {SMB_VFS_OP(aixjfs2_get_nt_acl),
497         SMB_VFS_OP_GET_NT_ACL,
498         SMB_VFS_LAYER_TRANSPARENT},
499
500         {SMB_VFS_OP(aixjfs2_fset_nt_acl),
501         SMB_VFS_OP_FSET_NT_ACL,
502         SMB_VFS_LAYER_TRANSPARENT},
503
504         {SMB_VFS_OP(aixjfs2_set_nt_acl),
505         SMB_VFS_OP_SET_NT_ACL,
506         SMB_VFS_LAYER_TRANSPARENT},
507
508         {SMB_VFS_OP(aixjfs2_sys_acl_get_file),
509         SMB_VFS_OP_SYS_ACL_GET_FILE,
510         SMB_VFS_LAYER_TRANSPARENT},
511
512         {SMB_VFS_OP(aixjfs2_sys_acl_get_fd),
513         SMB_VFS_OP_SYS_ACL_GET_FD,
514         SMB_VFS_LAYER_TRANSPARENT},
515
516         {SMB_VFS_OP(aixjfs2_sys_acl_set_file),
517         SMB_VFS_OP_SYS_ACL_SET_FILE,
518         SMB_VFS_LAYER_TRANSPARENT},
519
520         {SMB_VFS_OP(aixjfs2_sys_acl_set_fd),
521         SMB_VFS_OP_SYS_ACL_SET_FD,
522         SMB_VFS_LAYER_TRANSPARENT},
523
524         {SMB_VFS_OP(aixjfs2_sys_acl_delete_def_file),
525         SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
526         SMB_VFS_LAYER_TRANSPARENT},
527
528         {SMB_VFS_OP(NULL),
529         SMB_VFS_OP_NOOP,
530         SMB_VFS_LAYER_NOOP}
531 };
532
533 NTSTATUS vfs_aixacl2_init(void);
534 NTSTATUS vfs_aixacl2_init(void)
535 {
536         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, AIXACL2_MODULE_NAME,
537                                 aixjfs2_ops);
538 }