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