1 /*
2 * Copyright (C) 2016 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 #define HASHSIZE 0x100000
36 #define HASHFN(inode,acltype) (((inode)*0x56BF7623+(acltype))%(HASHSIZE))
37
38 typedef struct acl_entry {
39 uint32_t id;
40 uint16_t perm;
41 } acl_entry;
42
43 typedef struct acl_node {
44 uint32_t inode;
45 uint8_t acltype;
46 uint16_t userperm;
47 uint16_t groupperm;
48 uint16_t otherperm;
49 uint16_t mask;
50 uint16_t namedusers;
51 uint16_t namedgroups;
52 acl_entry *acltab;
53 struct acl_node *next;
54 } acl_node;
55
56 static acl_node** hashtab;
57
posix_acl_delete(uint32_t inode,uint8_t acltype)58 static void posix_acl_delete(uint32_t inode,uint8_t acltype) {
59 uint32_t h;
60 acl_node **acnp,*acn;
61
62 h = HASHFN(inode,acltype);
63 acnp = hashtab+h;
64 while ((acn=*acnp)!=NULL) {
65 if (acn->inode == inode && acn->acltype == acltype) {
66 *acnp = acn->next;
67 if (acn->acltab) {
68 free(acn->acltab);
69 }
70 free(acn);
71 } else {
72 acnp = &(acn->next);
73 }
74 }
75 }
76
posix_acl_create(uint32_t inode,uint8_t acltype)77 static acl_node* posix_acl_create(uint32_t inode,uint8_t acltype) {
78 uint32_t h;
79 acl_node *acn;
80
81 h = HASHFN(inode,acltype);
82 acn = malloc(sizeof(acl_node));
83 passert(acn);
84 acn->inode = inode;
85 acn->acltype = acltype;
86 acn->userperm = 0;
87 acn->groupperm = 0;
88 acn->otherperm = 0;
89 acn->mask = 0;
90 acn->namedusers = 0;
91 acn->namedgroups = 0;
92 acn->acltab = NULL;
93 acn->next = hashtab[h];
94 hashtab[h] = acn;
95 return acn;
96 }
97
posix_acl_find(uint32_t inode,uint8_t acltype)98 static acl_node* posix_acl_find(uint32_t inode,uint8_t acltype) {
99 uint32_t h;
100 acl_node *acn;
101 h = HASHFN(inode,acltype);
102 for (acn=hashtab[h] ; acn!=NULL ; acn=acn->next) {
103 if (acn->inode == inode && acn->acltype == acltype) {
104 return acn;
105 }
106 }
107 return NULL;
108 }
109
posix_acl_getmode(uint32_t inode)110 uint16_t posix_acl_getmode(uint32_t inode) {
111 acl_node *acn;
112
113 acn = posix_acl_find(inode,POSIX_ACL_ACCESS);
114 // (acn->mask==0xFFFF) ???
115 return ((((acn->userperm)&7)<<6) | (((acn->mask)&7)<<3) | ((acn->otherperm)&7));
116 }
117
posix_acl_setmode(uint32_t inode,uint16_t mode)118 void posix_acl_setmode(uint32_t inode,uint16_t mode) {
119 acl_node *acn;
120
121 acn = posix_acl_find(inode,POSIX_ACL_ACCESS);
122 if (acn!=NULL) {
123 acn->userperm &= 0xFFF8;
124 acn->userperm |= (mode>>6)&7;
125 acn->mask &= 0xFFF8;
126 acn->mask |= (mode>>3)&7;
127 acn->otherperm &= 0xFFF8;
128 acn->otherperm |= mode&7;
129 }
130 }
131
posix_acl_perm(uint32_t inode,uint32_t auid,uint32_t agids,uint32_t * agid,uint32_t fuid,uint32_t fgid,uint16_t modemask)132 int posix_acl_perm(uint32_t inode,uint32_t auid,uint32_t agids,uint32_t *agid,uint32_t fuid,uint32_t fgid,uint16_t modemask) {
133 acl_node *acn;
134 int f;
135 uint16_t i;
136 uint32_t j;
137
138 if (auid==0) {
139 return 0xFFFF;
140 }
141 acn = posix_acl_find(inode,POSIX_ACL_ACCESS);
142 if (acn==NULL) {
143 return 0;
144 }
145 if (auid==fuid) {
146 if ((acn->userperm & modemask) == modemask) {
147 return 1;
148 } else {
149 return 0;
150 }
151 } else {
152 for (i=0 ; i<acn->namedusers ; i++) {
153 if (auid==acn->acltab[i].id) {
154 if ((acn->acltab[i].perm & acn->mask & modemask) == modemask) {
155 return 1;
156 } else {
157 return 0;
158 }
159 }
160 }
161 for (j=0 ; j<agids ; j++) {
162 if (agid[j]==fgid) {
163 if ((acn->groupperm & acn->mask & modemask) == modemask) {
164 return 1;
165 }
166 f = 1;
167 }
168 }
169 for (i=acn->namedusers ; i<acn->namedusers+acn->namedgroups ; i++) {
170 for (j=0 ; j<agids ; j++) {
171 if (agid[j]==acn->acltab[i].id) {
172 if ((acn->acltab[i].perm & acn->mask & modemask) == modemask) {
173 return 1;
174 }
175 f = 1;
176 }
177 }
178 }
179 if (f==1) {
180 return 0;
181 }
182 if ((acn->otherperm & modemask) == modemask) {
183 return 1;
184 } else {
185 return 0;
186 }
187 }
188 }
189
posix_acl_copydefaults(uint32_t parent,uint32_t inode,uint8_t directory,uint16_t mode)190 uint8_t posix_acl_copydefaults(uint32_t parent,uint32_t inode,uint8_t directory,uint16_t mode) {
191 uint16_t i,acls;
192 uint8_t ret;
193 acl_node *pacn;
194 acl_node *acn;
195
196 ret = 0;
197 pacn = posix_acl_find(parent,POSIX_ACL_DEFAULT);
198 if (pacn==NULL) {
199 return ret;
200 }
201 acls = pacn->namedusers + pacn->namedgroups;
202 acn = posix_acl_find(inode,POSIX_ACL_ACCESS);
203 if (acn==NULL) {
204 acn = posix_acl_create(inode,POSIX_ACL_ACCESS);
205 ret |= 1;
206 // fs_set_aclflag(inode,0);
207 }
208 acn->userperm &= 0xFFF8;
209 acn->userperm |= (mode>>6)&7;
210 acn->userperm &= pacn->userperm;
211 acn->groupperm = pacn->groupperm;
212 acn->otherperm &= 0xFFF8;
213 acn->otherperm |= mode&7;
214 acn->otherperm &= pacn->otherperm;
215 acn->mask &= 0xFFF8;
216 acn->mask |= (mode>>3)&7;
217 acn->mask &= pacn->mask;
218 if (acn->namedusers+acn->namedgroups!=acls) {
219 if (acn->acltab!=NULL) {
220 free(acn->acltab);
221 }
222 if (acls>0) {
223 acn->acltab = malloc(sizeof(acl_entry)*acls);
224 passert(acn->acltab);
225 } else {
226 acn->acltab = NULL;
227 }
228 }
229 acn->namedusers = pacn->namedusers;
230 acn->namedgroups = pacn->namedgroups;
231 for (i=0 ; i<acls ; i++) {
232 acn->acltab[i].id = pacn->acltab[i].id;
233 acn->acltab[i].perm = pacn->acltab[i].perm;
234 }
235 if (directory) {
236 acn = posix_acl_find(inode,POSIX_ACL_DEFAULT);
237 if (acn==NULL) {
238 acn = posix_acl_create(inode,POSIX_ACL_DEFAULT);
239 ret |= 2;
240 // fs_set_aclflag(inode,1);
241 }
242 acn->userperm = pacn->userperm;
243 acn->groupperm = pacn->groupperm;
244 acn->otherperm = pacn->otherperm;
245 acn->mask = pacn->mask;
246 if (acn->namedusers+acn->namedgroups!=acls) {
247 if (acn->acltab!=NULL) {
248 free(acn->acltab);
249 }
250 if (acls>0) {
251 acn->acltab = malloc(sizeof(acl_entry)*acls);
252 passert(acn->acltab);
253 } else {
254 acn->acltab = NULL;
255 }
256 }
257 acn->namedusers = pacn->namedusers;
258 acn->namedgroups = pacn->namedgroups;
259 for (i=0 ; i<acls ; i++) {
260 acn->acltab[i].id = pacn->acltab[i].id;
261 acn->acltab[i].perm = pacn->acltab[i].perm;
262 }
263 }
264 return ret;
265 }
266
posix_acl_remove(uint32_t inode,uint8_t acltype)267 void posix_acl_remove(uint32_t inode,uint8_t acltype) {
268 posix_acl_delete(inode,acltype);
269 }
270
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)271 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) {
272 uint16_t i,acls;
273 acl_node *acn;
274
275 if (((namedusers | namedgroups) == 0) && userperm<=7 && groupperm<=7 && otherperm<=7 && mask==0xFFFF) {
276 posix_acl_delete(inode,acltype);
277 fs_del_aclflag(inode,acltype);
278 return;
279 }
280
281 acn = posix_acl_find(inode,acltype);
282 if (acn==NULL) {
283 acn = posix_acl_create(inode,acltype);
284 fs_set_aclflag(inode,acltype);
285 }
286
287 acls = namedusers + namedgroups;
288 acn->userperm = userperm;
289 acn->groupperm = groupperm;
290 acn->otherperm = otherperm;
291 acn->mask = mask;
292 if (acn->namedusers+acn->namedgroups!=acls) {
293 if (acn->acltab!=NULL) {
294 free(acn->acltab);
295 }
296 if (acls>0) {
297 acn->acltab = malloc(sizeof(acl_entry)*acls);
298 passert(acn->acltab);
299 } else {
300 acn->acltab = NULL;
301 }
302 }
303 acn->namedusers = namedusers;
304 acn->namedgroups = namedgroups;
305 // syslog(LOG_NOTICE,"acls: %u ; acltab: %p ; aclblob: %p",acls,acn->acltab,aclblob);
306 for (i=0 ; i<acls ; i++) {
307 acn->acltab[i].id = get32bit(&aclblob);
308 acn->acltab[i].perm = get16bit(&aclblob);
309 }
310 }
311
posix_acl_get_blobsize(uint32_t inode,uint8_t acltype,void ** aclnode)312 int32_t posix_acl_get_blobsize(uint32_t inode,uint8_t acltype,void **aclnode) {
313 acl_node *acn;
314 acn = posix_acl_find(inode,acltype);
315
316 *aclnode = (void*)acn;
317 if (acn==NULL) {
318 return -1;
319 } else {
320 return (acn->namedusers+acn->namedgroups)*6;
321 }
322 }
323
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)324 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) {
325 acl_node *acn;
326 uint16_t i,acls;
327
328 acn = (acl_node*)aclnode;
329
330 *userperm = acn->userperm;
331 *groupperm = acn->groupperm;
332 *otherperm = acn->otherperm;
333 *mask = acn->mask;
334 *namedusers = acn->namedusers;
335 *namedgroups = acn->namedgroups;
336 acls = acn->namedusers+acn->namedgroups;
337 for (i=0 ; i<acls ; i++) {
338 put32bit(&aclblob,acn->acltab[i].id);
339 put16bit(&aclblob,acn->acltab[i].perm);
340 }
341 }
342
posix_acl_cleanup(void)343 void posix_acl_cleanup(void) {
344 uint32_t h;
345 acl_node *acn,*nacn;
346
347 for (h=0 ; h<HASHSIZE ; h++) {
348 for (acn=hashtab[h] ; acn ; acn=nacn) {
349 nacn = acn->next;
350 if (acn->acltab) {
351 free(acn->acltab);
352 }
353 free(acn);
354 }
355 hashtab[h] = NULL;
356 }
357 }
358
posix_acl_store(bio * fd)359 uint8_t posix_acl_store(bio *fd) {
360 uint8_t hdrbuff[4+1+2*6];
361 uint8_t aclbuff[6*100];
362 uint8_t *ptr;
363 uint32_t h,accnt,acbcnt;
364 acl_node *acn;
365
366 if (fd==NULL) {
367 return 0x10;
368 }
369 for (h=0 ; h<HASHSIZE ; h++) {
370 for (acn=hashtab[h] ; acn ; acn=acn->next) {
371 ptr = hdrbuff;
372 put32bit(&ptr,acn->inode);
373 put8bit(&ptr,acn->acltype);
374 put16bit(&ptr,acn->userperm);
375 put16bit(&ptr,acn->groupperm);
376 put16bit(&ptr,acn->otherperm);
377 put16bit(&ptr,acn->mask);
378 put16bit(&ptr,acn->namedusers);
379 put16bit(&ptr,acn->namedgroups);
380 if (bio_write(fd,hdrbuff,4+1+2*6)!=(4+1+2*6)) {
381 syslog(LOG_NOTICE,"write error");
382 return 0xFF;
383 }
384 accnt = 0;
385 acbcnt = 0;
386 ptr = aclbuff;
387 while (accnt<acn->namedusers+acn->namedgroups) {
388 if (acbcnt==100) {
389 if (bio_write(fd,aclbuff,6*100)!=(6*100)) {
390 syslog(LOG_NOTICE,"write error");
391 return 0xFF;
392 }
393 acbcnt = 0;
394 ptr = aclbuff;
395 }
396 put32bit(&ptr,acn->acltab[accnt].id);
397 put16bit(&ptr,acn->acltab[accnt].perm);
398 accnt++;
399 acbcnt++;
400 }
401 if (acbcnt>0) {
402 if (bio_write(fd,aclbuff,6*acbcnt)!=(6*acbcnt)) {
403 syslog(LOG_NOTICE,"write error");
404 return 0xFF;
405 }
406 }
407 }
408 }
409 memset(hdrbuff,0,4+1+2*6);
410 if (bio_write(fd,hdrbuff,4+1+2*6)!=(4+1+2*6)) {
411 syslog(LOG_NOTICE,"write error");
412 return 0xFF;
413 }
414 return 0;
415 }
416
posix_acl_load(bio * fd,uint8_t mver,int ignoreflag)417 int posix_acl_load(bio *fd,uint8_t mver,int ignoreflag) {
418 uint8_t hdrbuff[4+1+2*6];
419 uint8_t aclbuff[6*100];
420 const uint8_t *ptr;
421 uint32_t inode;
422 uint8_t acltype;
423 uint16_t userperm;
424 uint16_t groupperm;
425 uint16_t otherperm;
426 uint16_t mask;
427 uint16_t namedusers;
428 uint16_t namedgroups;
429 uint32_t i,acls,acbcnt;
430 uint8_t nl=1;
431 acl_node *acn;
432
433 (void)mver;
434
435 while (1) {
436 if (bio_read(fd,hdrbuff,4+1+2*6)!=(4+1+2*6)) {
437 int err = errno;
438 if (nl) {
439 fputc('\n',stderr);
440 // nl=0;
441 }
442 errno = err;
443 mfs_errlog(LOG_ERR,"loading posix_acl: read error");
444 return -1;
445 }
446 ptr = hdrbuff;
447 inode = get32bit(&ptr);
448 if (inode==0) {
449 return 1;
450 }
451 acltype = get8bit(&ptr);
452 userperm = get16bit(&ptr);
453 groupperm = get16bit(&ptr);
454 otherperm = get16bit(&ptr);
455 mask = get16bit(&ptr);
456 namedusers = get16bit(&ptr);
457 namedgroups = get16bit(&ptr);
458 acls = namedusers + namedgroups;
459 if (acltype!=POSIX_ACL_ACCESS && acltype!=POSIX_ACL_DEFAULT) {
460 if (nl) {
461 fputc('\n',stderr);
462 nl=0;
463 }
464 mfs_syslog(LOG_ERR,"loading posix_acl: wrong acl type");
465 if (ignoreflag) {
466 bio_skip(fd,6*acls);
467 continue;
468 } else {
469 return -1;
470 }
471 }
472 acn = posix_acl_find(inode,acltype);
473 if (acn!=NULL) {
474 if (nl) {
475 fputc('\n',stderr);
476 nl=0;
477 }
478 mfs_syslog(LOG_ERR,"loading posix_acl: repeated acl");
479 if (ignoreflag) {
480 bio_skip(fd,6*acls);
481 continue;
482 } else {
483 return -1;
484 }
485 }
486 acn = posix_acl_create(inode,acltype);
487 fs_set_aclflag(inode,acltype);
488 acn->userperm = userperm;
489 acn->groupperm = groupperm;
490 acn->otherperm = otherperm;
491 acn->mask = mask;
492 acn->namedusers = namedusers;
493 acn->namedgroups = namedgroups;
494 if (acls>0) {
495 acn->acltab = malloc(sizeof(acl_entry)*acls);
496 passert(acn->acltab);
497 } else {
498 acn->acltab = NULL;
499 }
500 acbcnt = 0;
501 for (i=0 ; i<acls ; i++) {
502 if (acbcnt==0) {
503 acbcnt = acls-i;
504 if (acbcnt>100) {
505 acbcnt=100;
506 }
507 if (bio_read(fd,aclbuff,6*acbcnt)!=6*acbcnt) {
508 int err = errno;
509 if (nl) {
510 fputc('\n',stderr);
511 // nl=0;
512 }
513 posix_acl_delete(inode,acltype);
514 errno = err;
515 mfs_errlog(LOG_ERR,"loading posix_acl: read error");
516 return -1;
517 }
518 ptr = aclbuff;
519 }
520 acn->acltab[i].id = get32bit(&ptr);
521 acn->acltab[i].perm = get16bit(&ptr);
522 acbcnt--;
523 }
524 }
525 }
526
posix_acl_init(void)527 int posix_acl_init(void) {
528 uint32_t i;
529 hashtab = malloc(sizeof(acl_node*)*HASHSIZE);
530 passert(hashtab);
531 for (i=0 ; i<HASHSIZE ; i++) {
532 hashtab[i] = NULL;
533 }
534 return 0;
535 }
536