1 /*
2 * Copyright (C) 2021 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3 *
4 * This file is part of MooseFS.
5 *
6 * MooseFS 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, version 2 (only).
9 *
10 * MooseFS is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MooseFS; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18 * or visit http://www.gnu.org/licenses/gpl-2.0.html
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <inttypes.h>
28
29 #include "MFSCommunication.h"
30 #include "datapack.h"
31 #include "slogger.h"
32 #include "massert.h"
33 #include "filesystem.h"
34
35 #include "glue.h"
36
37 typedef struct acl_entry {
38 uint32_t id;
39 uint16_t perm;
40 } acl_entry;
41
42 typedef struct acl_node {
43 uint32_t inode;
44 uint8_t acltype;
45 uint16_t userperm;
46 uint16_t groupperm;
47 uint16_t otherperm;
48 uint16_t mask;
49 uint16_t namedusers;
50 uint16_t namedgroups;
51 acl_entry *acltab;
52 struct acl_node *next;
53 } acl_node;
54
55 #define LOHASH_BITS 20
56 #define ENTRY_TYPE acl_node
57 #define GLUE_FN_NAME_PREFIX(Y) GLUE(posix_acl_xxx,Y)
58 #define HASH_ARGS_TYPE_LIST uint32_t inode,uint8_t acltype
59 #define HASH_ARGS_LIST inode,acltype
60 #define GLUE_HASH_TAB_PREFIX(Y) GLUE(pacl,Y)
61
GLUE_FN_NAME_PREFIX(_cmp)62 static inline int GLUE_FN_NAME_PREFIX(_cmp)(ENTRY_TYPE *e,HASH_ARGS_TYPE_LIST) {
63 return (e->inode==inode && e->acltype==acltype);
64 }
65
GLUE_FN_NAME_PREFIX(_hash)66 static inline uint32_t GLUE_FN_NAME_PREFIX(_hash)(HASH_ARGS_TYPE_LIST) {
67 return inode*0x56BF7623+acltype;
68 }
69
GLUE_FN_NAME_PREFIX(_ehash)70 static inline uint32_t GLUE_FN_NAME_PREFIX(_ehash)(ENTRY_TYPE *e) {
71 return GLUE_FN_NAME_PREFIX(_hash)(e->inode,e->acltype);
72 }
73
74 #include "hash_begin.h"
75
posix_acl_create(uint32_t inode,uint8_t acltype)76 static acl_node* posix_acl_create(uint32_t inode,uint8_t acltype) {
77 acl_node *acn;
78
79 acn = malloc(sizeof(acl_node));
80 passert(acn);
81 acn->inode = inode;
82 acn->acltype = acltype;
83 acn->userperm = 0;
84 acn->groupperm = 0;
85 acn->otherperm = 0;
86 acn->mask = 0;
87 acn->namedusers = 0;
88 acn->namedgroups = 0;
89 acn->acltab = NULL;
90 GLUE_FN_NAME_PREFIX(_add)(acn);
91 return acn;
92 }
93
posix_acl_getmode(uint32_t inode)94 uint16_t posix_acl_getmode(uint32_t inode) {
95 acl_node *acn;
96
97 acn = GLUE_FN_NAME_PREFIX(_find)(inode,POSIX_ACL_ACCESS);
98 // (acn->mask==0xFFFF) ???
99 return ((acn->userperm & 7) << 6) | ((acn->mask & 7) << 3) | (acn->otherperm & 7);
100 }
101
posix_acl_setmode(uint32_t inode,uint16_t mode)102 void posix_acl_setmode(uint32_t inode,uint16_t mode) {
103 acl_node *acn;
104
105 acn = GLUE_FN_NAME_PREFIX(_find)(inode,POSIX_ACL_ACCESS);
106 if (acn!=NULL) {
107 acn->userperm &= 0xFFF8;
108 acn->userperm |= (mode>>6)&7;
109 acn->mask &= 0xFFF8;
110 acn->mask |= (mode>>3)&7;
111 acn->otherperm &= 0xFFF8;
112 acn->otherperm |= mode&7;
113 }
114 }
115
posix_acl_accmode(uint32_t inode,uint32_t auid,uint32_t agids,uint32_t * agid,uint32_t fuid,uint32_t fgid)116 uint8_t posix_acl_accmode(uint32_t inode,uint32_t auid,uint32_t agids,uint32_t *agid,uint32_t fuid,uint32_t fgid) {
117 static uint8_t modetoaccmode[8] = MODE_TO_ACCMODE;
118 acl_node *acn;
119 int f;
120 uint16_t i;
121 uint32_t j;
122 uint8_t modemask;
123
124 if (auid==0) {
125 return modetoaccmode[7];
126 }
127 acn = GLUE_FN_NAME_PREFIX(_find)(inode,POSIX_ACL_ACCESS);
128 if (acn==NULL) {
129 return modetoaccmode[0];
130 }
131 if (auid==fuid) {
132 return modetoaccmode[acn->userperm & 0x7];
133 } else {
134 for (i=0 ; i<acn->namedusers ; i++) {
135 if (auid==acn->acltab[i].id) {
136 return modetoaccmode[acn->acltab[i].perm & acn->mask & 0x7];
137 }
138 }
139 f = 0;
140 modemask = 0;
141 for (j=0 ; j<agids ; j++) {
142 if (agid[j]==fgid) {
143 modemask |= modetoaccmode[acn->groupperm & acn->mask & 0x7];
144 f = 1;
145 }
146 }
147 for (i=acn->namedusers ; i<acn->namedusers+acn->namedgroups ; i++) {
148 for (j=0 ; j<agids ; j++) {
149 if (agid[j]==acn->acltab[i].id) {
150 modemask |= modetoaccmode[acn->acltab[i].perm & acn->mask & 0x7];
151 f = 1;
152 }
153 }
154 }
155 if (f==1) {
156 return modemask;
157 }
158 return modetoaccmode[acn->otherperm & 0x7];
159 }
160 }
161
posix_acl_copydefaults(uint32_t parent,uint32_t inode,uint8_t directory,uint16_t * mode)162 uint8_t posix_acl_copydefaults(uint32_t parent,uint32_t inode,uint8_t directory,uint16_t *mode) {
163 uint16_t i,acls;
164 uint8_t ret;
165 acl_node *pacn;
166 acl_node *acn;
167
168 ret = 0;
169 pacn = GLUE_FN_NAME_PREFIX(_find)(parent,POSIX_ACL_DEFAULT);
170 if (pacn==NULL) {
171 return ret;
172 }
173 acls = pacn->namedusers + pacn->namedgroups;
174 if (acls==0 && pacn->userperm<=7 && pacn->groupperm<=7 && pacn->otherperm<=7 && pacn->mask==0xFFFF) { // simple ACL as DEFAULT - just modify mode
175 *mode &= 0xFE00 | (pacn->userperm << 6) | (pacn->groupperm << 3) | pacn->otherperm;
176 } else {
177 acn = GLUE_FN_NAME_PREFIX(_find)(inode,POSIX_ACL_ACCESS);
178 if (acn==NULL) {
179 acn = posix_acl_create(inode,POSIX_ACL_ACCESS);
180 ret |= 1;
181 }
182 acn->userperm &= 0xFFF8;
183 acn->userperm |= ((*mode)>>6)&7;
184 acn->userperm &= pacn->userperm;
185 acn->groupperm = pacn->groupperm;
186 acn->otherperm &= 0xFFF8;
187 acn->otherperm |= (*mode)&7;
188 acn->otherperm &= pacn->otherperm;
189 acn->mask &= 0xFFF8;
190 acn->mask |= ((*mode)>>3)&7;
191 acn->mask &= pacn->mask;
192 *mode = ((*mode) & 0xFE00) | ((acn->userperm&7) << 6) | ((acn->groupperm&7) << 3) | (acn->otherperm&7); // groupperm not mask here !!!
193 if (acn->namedusers+acn->namedgroups!=acls) {
194 if (acn->acltab!=NULL) {
195 free(acn->acltab);
196 }
197 if (acls>0) {
198 acn->acltab = malloc(sizeof(acl_entry)*acls);
199 passert(acn->acltab);
200 } else {
201 acn->acltab = NULL;
202 }
203 }
204 acn->namedusers = pacn->namedusers;
205 acn->namedgroups = pacn->namedgroups;
206 for (i=0 ; i<acls ; i++) {
207 acn->acltab[i].id = pacn->acltab[i].id;
208 acn->acltab[i].perm = pacn->acltab[i].perm;
209 }
210 }
211 if (directory) {
212 acn = GLUE_FN_NAME_PREFIX(_find)(inode,POSIX_ACL_DEFAULT);
213 if (acn==NULL) {
214 acn = posix_acl_create(inode,POSIX_ACL_DEFAULT);
215 ret |= 2;
216 }
217 acn->userperm = pacn->userperm;
218 acn->groupperm = pacn->groupperm;
219 acn->otherperm = pacn->otherperm;
220 acn->mask = pacn->mask;
221 if (acn->namedusers+acn->namedgroups!=acls) {
222 if (acn->acltab!=NULL) {
223 free(acn->acltab);
224 }
225 if (acls>0) {
226 acn->acltab = malloc(sizeof(acl_entry)*acls);
227 passert(acn->acltab);
228 } else {
229 acn->acltab = NULL;
230 }
231 }
232 acn->namedusers = pacn->namedusers;
233 acn->namedgroups = pacn->namedgroups;
234 for (i=0 ; i<acls ; i++) {
235 acn->acltab[i].id = pacn->acltab[i].id;
236 acn->acltab[i].perm = pacn->acltab[i].perm;
237 }
238 }
239 return ret;
240 }
241
posix_acl_remove(uint32_t inode,uint8_t acltype)242 void posix_acl_remove(uint32_t inode,uint8_t acltype) {
243 acl_node *acn;
244 acn = GLUE_FN_NAME_PREFIX(_find)(inode,acltype);
245 if (acn) {
246 GLUE_FN_NAME_PREFIX(_delete)(acn);
247 if (acn->acltab) {
248 free(acn->acltab);
249 }
250 free(acn);
251 }
252 }
253
posix_acl_set(uint32_t inode,uint8_t acltype,uint16_t userperm,uint16_t groupperm,uint16_t otherperm,uint16_t mask,uint16_t namedusers,uint16_t namedgroups,const uint8_t * aclblob)254 void posix_acl_set(uint32_t inode,uint8_t acltype,uint16_t userperm,uint16_t groupperm,uint16_t otherperm,uint16_t mask,uint16_t namedusers,uint16_t namedgroups,const uint8_t *aclblob) {
255 uint16_t i,acls;
256 acl_node *acn;
257
258 if (acltype==POSIX_ACL_ACCESS && ((namedusers | namedgroups) == 0) && userperm<=7 && groupperm<=7 && otherperm<=7 && mask==0xFFFF) {
259 posix_acl_remove(inode,acltype);
260 fs_del_aclflag(inode,acltype);
261 return;
262 }
263
264 acn = GLUE_FN_NAME_PREFIX(_find)(inode,acltype);
265 if (acn==NULL) {
266 acn = posix_acl_create(inode,acltype);
267 fs_set_aclflag(inode,acltype);
268 }
269
270 acls = namedusers + namedgroups;
271 acn->userperm = userperm;
272 acn->groupperm = groupperm;
273 acn->otherperm = otherperm;
274 acn->mask = mask;
275 if (acn->namedusers+acn->namedgroups!=acls) {
276 if (acn->acltab!=NULL) {
277 free(acn->acltab);
278 }
279 if (acls>0) {
280 acn->acltab = malloc(sizeof(acl_entry)*acls);
281 passert(acn->acltab);
282 } else {
283 acn->acltab = NULL;
284 }
285 }
286 acn->namedusers = namedusers;
287 acn->namedgroups = namedgroups;
288 // syslog(LOG_NOTICE,"acls: %u ; acltab: %p ; aclblob: %p",acls,acn->acltab,aclblob);
289 for (i=0 ; i<acls ; i++) {
290 acn->acltab[i].id = get32bit(&aclblob);
291 acn->acltab[i].perm = get16bit(&aclblob);
292 }
293 }
294
posix_acl_get_blobsize(uint32_t inode,uint8_t acltype,void ** aclnode)295 int32_t posix_acl_get_blobsize(uint32_t inode,uint8_t acltype,void **aclnode) {
296 acl_node *acn;
297 acn = GLUE_FN_NAME_PREFIX(_find)(inode,acltype);
298
299 *aclnode = (void*)acn;
300 if (acn==NULL) {
301 return -1;
302 } else {
303 return (acn->namedusers+acn->namedgroups)*6;
304 }
305 }
306
posix_acl_get_data(void * aclnode,uint16_t * userperm,uint16_t * groupperm,uint16_t * otherperm,uint16_t * mask,uint16_t * namedusers,uint16_t * namedgroups,uint8_t * aclblob)307 void posix_acl_get_data(void *aclnode,uint16_t *userperm,uint16_t *groupperm,uint16_t *otherperm,uint16_t *mask,uint16_t *namedusers,uint16_t *namedgroups,uint8_t *aclblob) {
308 acl_node *acn;
309 uint16_t i,acls;
310
311 acn = (acl_node*)aclnode;
312
313 *userperm = acn->userperm;
314 *groupperm = acn->groupperm;
315 *otherperm = acn->otherperm;
316 *mask = acn->mask;
317 *namedusers = acn->namedusers;
318 *namedgroups = acn->namedgroups;
319 acls = acn->namedusers+acn->namedgroups;
320 for (i=0 ; i<acls ; i++) {
321 put32bit(&aclblob,acn->acltab[i].id);
322 put16bit(&aclblob,acn->acltab[i].perm);
323 }
324 }
325
posix_acl_copy(uint32_t srcinode,uint32_t dstinode,uint8_t acltype)326 uint8_t posix_acl_copy(uint32_t srcinode,uint32_t dstinode,uint8_t acltype) {
327 uint32_t acls;
328 acl_node *sacn,*dacn;
329
330 sacn = GLUE_FN_NAME_PREFIX(_find)(srcinode,acltype);
331 dacn = GLUE_FN_NAME_PREFIX(_find)(dstinode,acltype);
332 if (dacn==NULL) {
333 dacn = malloc(sizeof(acl_node));
334 passert(dacn);
335 dacn->inode = dstinode;
336 dacn->acltype = acltype;
337 GLUE_FN_NAME_PREFIX(_add)(dacn);
338 } else {
339 if (dacn->acltab!=NULL) {
340 free(dacn->acltab);
341 }
342 }
343 dacn->userperm = sacn->userperm;
344 dacn->groupperm = sacn->groupperm;
345 dacn->otherperm = sacn->otherperm;
346 dacn->mask = sacn->mask;
347 dacn->namedusers = sacn->namedusers;
348 dacn->namedgroups = sacn->namedgroups;
349 acls = sacn->namedusers + sacn->namedgroups;
350 if (acls>0) {
351 dacn->acltab = malloc(sizeof(acl_entry)*acls);
352 passert(dacn->acltab);
353 memcpy(dacn->acltab,sacn->acltab,sizeof(acl_entry)*acls);
354 } else {
355 dacn->acltab = NULL;
356 }
357 return 1;
358 }
359
posix_acl_cleanup(void)360 void posix_acl_cleanup(void) {
361 uint32_t i,j;
362 acl_node *acn,*nacn;
363
364 for (i=0 ; i<HASHTAB_HISIZE ; i++) {
365 if (GLUE_HASH_TAB_PREFIX(hashtab)[i]!=NULL) {
366 for (j=0 ; j<HASHTAB_LOSIZE ; j++) {
367 for (acn=GLUE_HASH_TAB_PREFIX(hashtab)[i][j] ; acn!=NULL ; acn=nacn) {
368 nacn = acn->next;
369 if (acn->acltab) {
370 free(acn->acltab);
371 }
372 free(acn);
373 }
374 GLUE_HASH_TAB_PREFIX(hashtab)[i][j] = NULL;
375 }
376 }
377 }
378 GLUE_FN_NAME_PREFIX(_hash_cleanup)();
379 }
380
posix_acl_store(bio * fd)381 uint8_t posix_acl_store(bio *fd) {
382 uint8_t hdrbuff[4+1+2*6];
383 uint8_t aclbuff[6*100];
384 uint8_t *ptr;
385 uint32_t i,j,accnt,acbcnt;
386 acl_node *acn;
387
388 if (fd==NULL) {
389 return 0x11;
390 }
391
392 for (i=0 ; i<HASHTAB_HISIZE ; i++) {
393 if (GLUE_HASH_TAB_PREFIX(hashtab)[i]!=NULL) {
394 for (j=0 ; j<HASHTAB_LOSIZE ; j++) {
395 for (acn=GLUE_HASH_TAB_PREFIX(hashtab)[i][j] ; acn!=NULL ; acn=acn->next) {
396 ptr = hdrbuff;
397 put32bit(&ptr,acn->inode);
398 put8bit(&ptr,acn->acltype);
399 put16bit(&ptr,acn->userperm);
400 put16bit(&ptr,acn->groupperm);
401 put16bit(&ptr,acn->otherperm);
402 put16bit(&ptr,acn->mask);
403 put16bit(&ptr,acn->namedusers);
404 put16bit(&ptr,acn->namedgroups);
405 if (bio_write(fd,hdrbuff,4+1+2*6)!=(4+1+2*6)) {
406 syslog(LOG_NOTICE,"write error");
407 return 0xFF;
408 }
409 accnt = 0;
410 acbcnt = 0;
411 ptr = aclbuff;
412 while (accnt<acn->namedusers+acn->namedgroups) {
413 if (acbcnt==100) {
414 if (bio_write(fd,aclbuff,6*100)!=(6*100)) {
415 syslog(LOG_NOTICE,"write error");
416 return 0xFF;
417 }
418 acbcnt = 0;
419 ptr = aclbuff;
420 }
421 put32bit(&ptr,acn->acltab[accnt].id);
422 put16bit(&ptr,acn->acltab[accnt].perm);
423 accnt++;
424 acbcnt++;
425 }
426 if (acbcnt>0) {
427 if (bio_write(fd,aclbuff,6*acbcnt)!=(6*acbcnt)) {
428 syslog(LOG_NOTICE,"write error");
429 return 0xFF;
430 }
431 }
432 }
433 }
434 }
435 }
436 memset(hdrbuff,0,4+1+2*6);
437 if (bio_write(fd,hdrbuff,4+1+2*6)!=(4+1+2*6)) {
438 syslog(LOG_NOTICE,"write error");
439 return 0xFF;
440 }
441 return 0;
442 }
443
posix_acl_load(bio * fd,uint8_t mver,int ignoreflag)444 int posix_acl_load(bio *fd,uint8_t mver,int ignoreflag) {
445 uint8_t hdrbuff[4+1+2*6];
446 uint8_t aclbuff[6*100];
447 const uint8_t *ptr;
448 uint32_t inode;
449 uint8_t acltype;
450 uint16_t userperm;
451 uint16_t groupperm;
452 uint16_t otherperm;
453 uint16_t mask;
454 uint16_t namedusers;
455 uint16_t namedgroups;
456 uint32_t i,acls,acbcnt;
457 uint8_t nl=1;
458 acl_node *acn;
459
460 while (1) {
461 if (bio_read(fd,hdrbuff,4+1+2*6)!=(4+1+2*6)) {
462 int err = errno;
463 if (nl) {
464 fputc('\n',stderr);
465 // nl=0;
466 }
467 errno = err;
468 mfs_errlog(LOG_ERR,"loading posix_acl: read error");
469 return -1;
470 }
471 ptr = hdrbuff;
472 inode = get32bit(&ptr);
473 if (inode==0) {
474 return 1;
475 }
476 acltype = get8bit(&ptr);
477 userperm = get16bit(&ptr);
478 groupperm = get16bit(&ptr);
479 otherperm = get16bit(&ptr);
480 mask = get16bit(&ptr);
481 namedusers = get16bit(&ptr);
482 namedgroups = get16bit(&ptr);
483 acls = namedusers + namedgroups;
484 if (fs_check_inode(inode)==0) { // silently skip acl's for non-existent inodes
485 bio_skip(fd,6*acls);
486 continue;
487 }
488 if (acltype!=POSIX_ACL_ACCESS && acltype!=POSIX_ACL_DEFAULT) {
489 if (nl) {
490 fputc('\n',stderr);
491 nl=0;
492 }
493 mfs_syslog(LOG_ERR,"loading posix_acl: wrong acl type");
494 if (ignoreflag) {
495 bio_skip(fd,6*acls);
496 continue;
497 } else {
498 return -1;
499 }
500 }
501 acn = GLUE_FN_NAME_PREFIX(_find)(inode,acltype);
502 if (acn!=NULL) {
503 if (nl) {
504 fputc('\n',stderr);
505 nl=0;
506 }
507 mfs_syslog(LOG_ERR,"loading posix_acl: repeated acl");
508 if (ignoreflag) {
509 bio_skip(fd,6*acls);
510 continue;
511 } else {
512 return -1;
513 }
514 }
515 acn = posix_acl_create(inode,acltype);
516 fs_set_aclflag(inode,acltype);
517 if (mver==0x10 && mask==0) {
518 uint16_t mode;
519 mode = fs_get_mode(inode);
520 userperm &= 0xFFF8;
521 userperm |= (mode>>6)&7;
522 mask = 7;
523 otherperm &= 0xFFF8;
524 otherperm |= mode&7;
525 mfs_arg_syslog(LOG_WARNING,"emergency set ACL mask for inode %"PRIu32" to 'rwx'",inode);
526 }
527 acn->userperm = userperm;
528 acn->groupperm = groupperm;
529 acn->otherperm = otherperm;
530 acn->mask = mask;
531 acn->namedusers = namedusers;
532 acn->namedgroups = namedgroups;
533 if (acls>0) {
534 acn->acltab = malloc(sizeof(acl_entry)*acls);
535 passert(acn->acltab);
536 } else {
537 acn->acltab = NULL;
538 }
539 acbcnt = 0;
540 for (i=0 ; i<acls ; i++) {
541 if (acbcnt==0) {
542 acbcnt = acls-i;
543 if (acbcnt>100) {
544 acbcnt=100;
545 }
546 if (bio_read(fd,aclbuff,6*acbcnt)!=6*acbcnt) {
547 int err = errno;
548 if (nl) {
549 fputc('\n',stderr);
550 // nl=0;
551 }
552 GLUE_FN_NAME_PREFIX(_delete)(acn);
553 if (acn->acltab!=NULL) {
554 free(acn->acltab);
555 }
556 free(acn);
557 errno = err;
558 mfs_errlog(LOG_ERR,"loading posix_acl: read error");
559 return -1;
560 }
561 ptr = aclbuff;
562 }
563 acn->acltab[i].id = get32bit(&ptr);
564 acn->acltab[i].perm = get16bit(&ptr);
565 acbcnt--;
566 }
567 }
568 }
569
posix_acl_init(void)570 int posix_acl_init(void) {
571 GLUE_FN_NAME_PREFIX(_hash_init)();
572 return 0;
573 }
574
575 #include "hash_end.h"
576
577 #undef LOHASH_BITS
578 #undef ENTRY_TYPE
579 #undef GLUE_FN_NAME_PREFIX
580 #undef HASH_ARGS_TYPE_LIST
581 #undef HASH_ARGS_LIST
582 #undef GLUE_HASH_TAB_PREFIX
583