75 WS_ASSERT(rq); |
88 WS_ASSERT(rq); |
76 |
89 |
77 VFSContext *ctx = pool_malloc(sn->pool, sizeof(VFSContext)); |
90 VFSContext *ctx = pool_malloc(sn->pool, sizeof(VFSContext)); |
78 ctx->sn = sn; |
91 ctx->sn = sn; |
79 ctx->rq = rq; |
92 ctx->rq = rq; |
80 ctx->vfs = rq->vfs; |
93 ctx->vfs = rq->vfs ? rq->vfs : &sys_vfs; |
81 ctx->user = acllist_getuser(sn, rq, rq->acllist); |
94 ctx->user = acllist_getuser(sn, rq, rq->acllist); |
82 ctx->acllist = rq->acllist; |
95 ctx->acllist = rq->acllist; |
83 ctx->aclreqaccess = rq->aclreqaccess; |
96 ctx->aclreqaccess = rq->aclreqaccess; |
84 ctx->pool = sn->pool; |
97 ctx->pool = sn->pool; |
85 ctx->vfs_errno = 0; |
98 ctx->vfs_errno = 0; |
86 return ctx; |
99 return ctx; |
87 } |
100 } |
88 |
101 |
89 SYS_FILE vfs_open(VFSContext *ctx, char *path, int oflags) { |
102 SYS_FILE vfs_open(VFSContext *ctx, char *path, int oflags) { |
|
103 WS_ASSERT(ctx); |
90 WS_ASSERT(path); |
104 WS_ASSERT(path); |
91 |
105 |
92 Session *sn; |
106 uint32_t access_mask = ctx->aclreqaccess | acl_oflag2mask(oflags); |
93 Request *rq; |
107 |
94 pool_handle_t *pool; |
108 // ctx->aclreqaccess should be the complete access mask |
95 uint32_t access_mask; |
109 uint32_t m = ctx->aclreqaccess; // save original access mask |
96 |
110 ctx->aclreqaccess = access_mask; // set mask for vfs->open call |
97 if(ctx) { |
111 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { |
98 access_mask = ctx->aclreqaccess; |
112 // VFS does not evaluates the ACL itself, so we have to do it here |
99 access_mask |= acl_oflag2mask(oflags); |
113 SysACL sysacl; |
100 if(!ctx->pool) { |
114 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
101 // TODO: log warning |
115 return NULL; |
102 // broken VFSContext |
116 } |
103 } |
117 } |
104 if(ctx->vfs) { |
118 SYS_FILE file = ctx->vfs->open(ctx, path, oflags); |
105 // ctx->aclreqaccess should be the complete access mask |
119 ctx->aclreqaccess = m; // restore original access mask |
106 uint32_t m = ctx->aclreqaccess; // save original access mask |
120 return file; |
107 ctx->aclreqaccess = access_mask; // set mask for vfs->open call |
121 } |
108 SYS_FILE file = ctx->vfs->open(ctx, path, oflags); |
122 |
109 ctx->aclreqaccess = m; // restore original access mask |
123 SYS_FILE vfs_openRO(VFSContext *ctx, char *path) { |
110 return file; |
124 return vfs_open(ctx, path, O_RDONLY); |
111 } else { |
125 } |
112 pool = ctx->pool; |
126 |
113 } |
127 SYS_FILE vfs_openWO(VFSContext *ctx, char *path) { |
|
128 return vfs_open(ctx, path, O_WRONLY | O_CREAT); |
|
129 } |
|
130 |
|
131 SYS_FILE vfs_openRW(VFSContext *ctx, char *path) { |
|
132 return vfs_open(ctx, path, O_RDONLY | O_WRONLY | O_CREAT); |
|
133 } |
|
134 |
|
135 int vfs_stat(VFSContext *ctx, char *path, struct stat *buf) { |
|
136 WS_ASSERT(ctx); |
|
137 WS_ASSERT(path); |
|
138 |
|
139 uint32_t access_mask = ctx->aclreqaccess | ACL_READ_ATTRIBUTES; |
|
140 |
|
141 // ctx->aclreqaccess should be the complete access mask |
|
142 uint32_t m = ctx->aclreqaccess; // save original access mask |
|
143 ctx->aclreqaccess = access_mask; // set mask for vfs->open call |
|
144 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { |
|
145 // VFS does not evaluates the ACL itself, so we have to do it here |
|
146 SysACL sysacl; |
|
147 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
|
148 return -1; |
|
149 } |
|
150 } |
|
151 int ret = ctx->vfs->stat(ctx, path, buf); |
|
152 ctx->aclreqaccess = m; // restore original access mask |
|
153 return ret; |
|
154 } |
|
155 |
|
156 int vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { |
|
157 WS_ASSERT(ctx); |
|
158 WS_ASSERT(fd); |
|
159 WS_ASSERT(buf); |
|
160 |
|
161 return ctx->vfs->fstat(ctx, fd, buf); |
|
162 } |
|
163 |
|
164 void vfs_close(SYS_FILE fd) { |
|
165 WS_ASSERT(fd); |
|
166 |
|
167 fd->io->close(fd); |
|
168 if(fd->ctx) { |
|
169 pool_free(fd->ctx->pool, fd); |
114 } else { |
170 } else { |
115 sn = NULL; |
171 free(fd); |
116 rq = NULL; |
172 } |
117 pool = NULL; |
173 } |
118 access_mask = acl_oflag2mask(oflags); |
174 |
119 } |
175 VFS_DIR vfs_opendir(VFSContext *ctx, char *path) { |
|
176 WS_ASSERT(ctx); |
|
177 WS_ASSERT(path); |
|
178 |
|
179 uint32_t access_mask = ctx->aclreqaccess | ACL_LIST; |
|
180 |
|
181 // ctx->aclreqaccess should be the complete access mask |
|
182 uint32_t m = ctx->aclreqaccess; // save original access mask |
|
183 ctx->aclreqaccess = access_mask; // set mask for vfs->open call |
|
184 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { |
|
185 // VFS does not evaluates the ACL itself, so we have to do it here |
|
186 SysACL sysacl; |
|
187 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
|
188 return NULL; |
|
189 } |
|
190 } |
|
191 VFS_DIR dir = ctx->vfs->opendir(ctx, path); |
|
192 ctx->aclreqaccess = m; // restore original access mask |
|
193 return dir; |
|
194 } |
|
195 |
|
196 int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry) { |
|
197 WS_ASSERT(dir); |
|
198 WS_ASSERT(entry); |
|
199 |
|
200 return dir->io->readdir(dir, entry, 0); |
|
201 } |
|
202 |
|
203 int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry) { |
|
204 WS_ASSERT(dir); |
|
205 WS_ASSERT(entry); |
|
206 |
|
207 return dir->io->readdir(dir, entry, 1); |
|
208 } |
|
209 |
|
210 void vfs_closedir(VFS_DIR dir) { |
|
211 WS_ASSERT(dir); |
|
212 |
|
213 dir->io->close(dir); |
|
214 if(dir->ctx) { |
|
215 VFS_FREE(dir->ctx->pool, dir); |
|
216 } else { |
|
217 free(dir); |
|
218 } |
|
219 } |
|
220 |
|
221 int vfs_mkdir(VFSContext *ctx, char *path) { |
|
222 WS_ASSERT(ctx); |
|
223 WS_ASSERT(path); |
|
224 |
|
225 return vfs_path_op(ctx, path, ctx->vfs->mkdir, ACL_ADD_FILE); |
|
226 } |
|
227 |
|
228 int vfs_unlink(VFSContext *ctx, char *path) { |
|
229 WS_ASSERT(ctx); |
|
230 WS_ASSERT(path); |
|
231 |
|
232 return vfs_path_op(ctx, path, ctx->vfs->unlink, ACL_DELETE); |
|
233 } |
|
234 |
|
235 |
|
236 // private |
|
237 int vfs_path_op(VFSContext *ctx, char *path, vfs_op_f op, uint32_t access) { |
|
238 uint32_t access_mask = ctx->aclreqaccess; |
|
239 access_mask |= access; |
|
240 |
|
241 // ctx->aclreqaccess should be the complete access mask |
|
242 uint32_t m = ctx->aclreqaccess; // save original access mask |
|
243 ctx->aclreqaccess = access_mask; // set mask for vfs function call |
|
244 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { |
|
245 // VFS does not evaluates the ACL itself, so we have to do it here |
|
246 SysACL sysacl; |
|
247 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
|
248 return -1; |
|
249 } |
|
250 } |
|
251 int ret = op(ctx, path); |
|
252 ctx->aclreqaccess = m; // restore original access mask |
|
253 return ret; |
|
254 } |
|
255 |
|
256 /* system vfs implementation */ |
|
257 |
|
258 SYS_FILE sys_vfs_open(VFSContext *ctx, char *path, int oflags) { |
|
259 uint32_t access_mask = ctx->aclreqaccess; |
|
260 pool_handle_t *pool = ctx->pool; |
120 |
261 |
121 // check ACLs |
262 // check ACLs |
122 SysACL sysacl; |
263 SysACL sysacl; |
123 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
264 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
124 return NULL; |
265 return NULL; |
163 file->fd = fd; |
302 file->fd = fd; |
164 file->io = &sys_file_io; |
303 file->io = &sys_file_io; |
165 return file; |
304 return file; |
166 } |
305 } |
167 |
306 |
168 SYS_FILE vfs_openRO(VFSContext *ctx, char *path) { |
307 int sys_vfs_stat(VFSContext *ctx, char *path, struct stat *buf) { |
169 return vfs_open(ctx, path, O_RDONLY); |
308 uint32_t access_mask = ctx->aclreqaccess; |
170 } |
|
171 |
|
172 SYS_FILE vfs_openWO(VFSContext *ctx, char *path) { |
|
173 return vfs_open(ctx, path, O_WRONLY | O_CREAT); |
|
174 } |
|
175 |
|
176 SYS_FILE vfs_openRW(VFSContext *ctx, char *path) { |
|
177 return vfs_open(ctx, path, O_RDONLY | O_WRONLY | O_CREAT); |
|
178 } |
|
179 |
|
180 int vfs_stat(VFSContext *ctx, char *path, struct stat *buf) { |
|
181 Session *sn; |
|
182 Request *rq; |
|
183 uint32_t access_mask; |
|
184 |
|
185 if(ctx) { |
|
186 access_mask = ctx->aclreqaccess; |
|
187 access_mask |= ACL_READ_ATTRIBUTES; |
|
188 if(!ctx->pool) { |
|
189 // TODO: log warning |
|
190 // broken VFSContext |
|
191 } |
|
192 if(ctx->vfs) { |
|
193 // ctx->aclreqaccess should be the complete access mask |
|
194 uint32_t m = ctx->aclreqaccess; // save original access mask |
|
195 ctx->aclreqaccess = access_mask; // set mask for vfs->fstat call |
|
196 int ret = ctx->vfs->stat(ctx, path, buf); |
|
197 ctx->aclreqaccess = m; // restore original access mask |
|
198 return ret; |
|
199 } |
|
200 } else { |
|
201 sn = NULL; |
|
202 rq = NULL; |
|
203 access_mask = ACL_READ_ATTRIBUTES; |
|
204 } |
|
205 |
309 |
206 // check ACLs |
310 // check ACLs |
207 SysACL sysacl; |
311 SysACL sysacl; |
208 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
312 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
209 return -1; |
313 return -1; |
325 sys_set_error_status(ctx); |
382 sys_set_error_status(ctx); |
326 } |
383 } |
327 return NULL; |
384 return NULL; |
328 } |
385 } |
329 |
386 |
330 SysVFSDir *dir_data = pool ? |
387 SysVFSDir *dir_data = VFS_MALLOC(pool, sizeof(SysVFSDir)); |
331 pool_malloc(pool, sizeof(SysVFSDir)) : malloc(sizeof(SysVFSDir)); |
|
332 if(!dir_data) { |
388 if(!dir_data) { |
333 closedir(sys_dir); |
389 closedir(sys_dir); |
334 return NULL; |
390 return NULL; |
335 } |
391 } |
336 long maxfilelen = fpathconf(dir_fd, _PC_NAME_MAX); |
392 long maxfilelen = fpathconf(dir_fd, _PC_NAME_MAX); |
337 size_t entry_len = offsetof(struct dirent, d_name) + maxfilelen + 1; |
393 size_t entry_len = offsetof(struct dirent, d_name) + maxfilelen + 1; |
338 dir_data->cur = pool ? |
394 dir_data->cur = VFS_MALLOC(pool, entry_len); |
339 pool_malloc(pool, entry_len) : malloc(entry_len); |
|
340 if(!dir_data->cur) { |
395 if(!dir_data->cur) { |
341 closedir(sys_dir); |
396 closedir(sys_dir); |
|
397 VFS_FREE(pool, dir_data); |
342 return NULL; |
398 return NULL; |
343 } |
399 } |
344 dir_data->dir = sys_dir; |
400 dir_data->dir = sys_dir; |
345 |
401 |
346 VFSDir *dir = pool ? |
402 VFSDir *dir = VFS_MALLOC(pool, sizeof(VFSDir)); |
347 pool_malloc(pool, sizeof(VFSDir)) : malloc(sizeof(VFSDir)); |
|
348 if(!dir) { |
403 if(!dir) { |
349 closedir(sys_dir); |
404 closedir(sys_dir); |
|
405 VFS_FREE(pool, dir_data->cur); |
|
406 VFS_FREE(pool, dir_data); |
350 return NULL; |
407 return NULL; |
351 } |
408 } |
352 dir->ctx = ctx; |
409 dir->ctx = ctx; |
353 dir->data = dir_data; |
410 dir->data = dir_data; |
354 dir->fd = dir_fd; |
411 dir->fd = dir_fd; |
355 dir->io = &sys_dir_io; |
412 dir->io = &sys_dir_io; |
356 return dir; |
413 return dir; |
357 } |
414 } |
358 |
415 |
359 int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry) { |
416 int sys_vfs_mkdir(VFSContext *ctx, char *path) { |
360 return dir->io->readdir(dir, entry, 0); |
417 return sys_path_op(ctx, path, sys_mkdir); |
361 } |
418 } |
362 |
419 |
363 int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry) { |
420 int sys_vfs_unlink(VFSContext *ctx, char *path) { |
364 return dir->io->readdir(dir, entry, 1); |
421 return sys_path_op(ctx, path, sys_unlink); |
365 } |
422 } |
366 |
423 |
367 void vfs_closedir(VFS_DIR dir) { |
424 |
368 dir->io->close(dir); |
425 int sys_path_op(VFSContext *ctx, char *path, sys_op_f op) { |
369 if(dir->ctx) { |
|
370 pool_free(dir->ctx->pool, dir); |
|
371 } else { |
|
372 free(dir); |
|
373 } |
|
374 } |
|
375 |
|
376 int vfs_mkdir(VFSContext *ctx, char *path) { |
|
377 if(ctx && ctx->vfs) { |
|
378 return vfs_path_op(ctx, path, ctx->vfs->mkdir, ACL_ADD_FILE); |
|
379 } else { |
|
380 return sys_path_op(ctx, path, sys_mkdir, ACL_ADD_FILE); |
|
381 } |
|
382 } |
|
383 |
|
384 int vfs_unlink(VFSContext *ctx, char *path) { |
|
385 if(ctx && ctx->vfs) { |
|
386 return vfs_path_op(ctx, path, ctx->vfs->unlink, ACL_DELETE); |
|
387 } else { |
|
388 return sys_path_op(ctx, path, sys_unlink, ACL_DELETE); |
|
389 } |
|
390 } |
|
391 |
|
392 |
|
393 // private |
|
394 int vfs_path_op(VFSContext *ctx, char *path, vfs_op_f op, uint32_t access) { |
|
395 Session *sn; |
|
396 Request *rq; |
|
397 |
|
398 uint32_t access_mask = ctx->aclreqaccess; |
426 uint32_t access_mask = ctx->aclreqaccess; |
399 access_mask |= access; |
|
400 if(!ctx->pool) { |
|
401 // TODO: log warning |
|
402 // broken VFSContext |
|
403 return -1; |
|
404 } |
|
405 |
|
406 // ctx->aclreqaccess should be the complete access mask |
|
407 uint32_t m = ctx->aclreqaccess; // save original access mask |
|
408 ctx->aclreqaccess = access_mask; // set mask for vfs function call |
|
409 int ret = op(ctx, path); |
|
410 ctx->aclreqaccess = m; // restore original access mask |
|
411 return ret; |
|
412 } |
|
413 |
|
414 int sys_path_op(VFSContext *ctx, char *path, sys_op_f op, uint32_t access) { |
|
415 if(ctx) { |
|
416 access |= ctx->aclreqaccess; |
|
417 } |
|
418 |
427 |
419 // check ACLs |
428 // check ACLs |
420 SysACL sysacl; |
429 SysACL sysacl; |
421 if(sys_acl_check(ctx, access, &sysacl)) { |
430 if(sys_acl_check(ctx, access_mask, &sysacl)) { |
422 return -1; |
431 return -1; |
423 } |
432 } |
424 |
433 |
425 if(sysacl.acl) { |
434 if(sysacl.acl) { |
426 if(!fs_acl_check(&sysacl, ctx->user, path, access)) { |
435 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) { |
427 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); |
436 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); |
428 return -1; |
437 return -1; |
429 } |
438 } |
430 } |
439 } |
431 |
440 |
432 // do path operation |
441 // do path operation |
433 if(op(ctx, path, &sysacl)) { |
442 if(op(ctx, path, &sysacl)) { |
434 // error |
443 // error |
435 if(ctx) { |
444 ctx->vfs_errno = errno; |
436 ctx->vfs_errno = errno; |
445 sys_set_error_status(ctx); |
437 sys_set_error_status(ctx); |
|
438 } |
|
439 return -1; |
446 return -1; |
440 } |
447 } |
441 |
448 |
442 return 0; |
449 return 0; |
443 } |
450 } |