1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 #include "wzd_all.h"
28
29 #ifndef WZD_USE_PCH
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37
38 #endif /* WZD_USE_PCH */
39
40 /** \file wzd_file.c
41 * \brief Files and directories functions
42 *
43 * Permissions are stored in a file present in each directory on the server.
44 * This allows portable function, and features like symbolic links on
45 * systems which does not have links (like windows).
46 *
47 * \addtogroup libwzd_core
48 * @{
49 */
50
51 #ifdef WIN32
52 #include <winsock2.h>
53 #include <io.h>
54 #include <direct.h> /* _mkdir */
55 #include <sys/locking.h> /* _locking */
56 #define _WIN32_WINNT 0x500
57 #include <windows.h>
58 #include <tchar.h>
59 #include <winioctl.h>
60
61 // Since MS apparently removed this struct (and its documentation) from
62 // the W2k SDK, but still refer to it in 'winioctl.h' for the specific
63 // IOCTLs, I decided to rename it and make it available.
64 // I've made some modifications to this one for easier access.
65 //
66 // Structure for FSCTL_SET_REPARSE_POINT, FSCTL_GET_REPARSE_POINT, and
67 // FSCTL_DELETE_REPARSE_POINT.
68 // This version of the reparse data buffer is only for Microsoft tags.
69
70 typedef struct
71 {
72 DWORD ReparseTag;
73 WORD ReparseDataLength;
74 WORD Reserved;
75
76 // IO_REPARSE_TAG_MOUNT_POINT specifics follow
77 WORD SubstituteNameOffset;
78 WORD SubstituteNameLength;
79 WORD PrintNameOffset;
80 WORD PrintNameLength;
81 WCHAR PathBuffer[1];
82
83 // Some helper functions
84 // bool Init(LPCSTR szJunctionPoint);
85 // bool Init(LPCWSTR wszJunctionPoint);
86 // int BytesForIoControl() const;
87 } TMN_REPARSE_DATA_BUFFER;
88
89 #define TMN_REPARSE_DATA_BUFFER_HEADER_SIZE \
90 FIELD_OFFSET(TMN_REPARSE_DATA_BUFFER, SubstituteNameOffset)
91
92
93 // These have the wrong values in pre-W2k SDKs, why I redefine them here.
94 #if !defined(FSCTL_SET_REPARSE_POINT) || \
95 (FSCTL_SET_REPARSE_POINT != 0x900a4)
96 #undef FSCTL_SET_REPARSE_POINT
97 #define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS)
98 #endif
99
100 #if !defined(FSCTL_DELETE_REPARSE_POINT) || \
101 (FSCTL_DELETE_REPARSE_POINT != 0x900ac)
102 #undef FSCTL_DELETE_REPARSE_POINT
103 #define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_ANY_ACCESS)
104 #endif
105
106
107
108
109 #else
110 #include <unistd.h>
111
112 #include <sys/types.h>
113 #include <sys/socket.h>
114 #include <netinet/in.h>
115 #include <arpa/inet.h>
116
117 #include <dirent.h>
118 #endif
119
120 #ifndef HAVE_STRTOK_R
121 # include "libwzd-base/wzd_strtok_r.h"
122 #endif
123
124 #include <fcntl.h> /* O_RDONLY */
125
126 #include "wzd_structs.h"
127
128 #include "wzd_libmain.h"
129 #include "wzd_log.h"
130 #include "wzd_misc.h"
131 #include "wzd_file.h"
132 #include "wzd_fs.h"
133 #include "wzd_group.h"
134 #include "wzd_cache.h"
135 #include "wzd_perm.h"
136 #include "wzd_user.h"
137 #include "wzd_vfs.h"
138
139
140
141 /*#define _HAS_MMAP*/
142
143 #ifdef _HAS_MMAP
144 #include <sys/mman.h>
145 #endif
146
147
148 #include "wzd_debug.h"
149
150
151 #define BUFFER_LEN 4096
152
153 /************ PRIVATE FUNCTIONS **************/
154
155 /** \brief Get default permission for user
156 * \param[in] wanted_right action to be evaluated
157 * \param[in] user user definition
158 *
159 * \todo XXX this function is badly named, userperms is no more a default action, but more a permissions mask
160 *
161 * Default permissions are set by the userperms field of the user.
162 * \return 0 if user is allowed to perform action
163 */
_default_perm(unsigned long wanted_right,wzd_user_t * user)164 static int _default_perm(unsigned long wanted_right, wzd_user_t * user)
165 {
166 return (( wanted_right & user->userperms ) == 0);
167 }
168
169 /** Free file list recursively
170 * \note locks SET_MUTEX_FILE_T
171 */
free_file_recursive(struct wzd_file_t * file)172 void free_file_recursive(struct wzd_file_t * file)
173 {
174 struct wzd_file_t * next_file;
175 wzd_acl_line_t *acl_current,*acl_next;
176
177 if (!file) return;
178 WZD_MUTEX_LOCK(SET_MUTEX_FILE_T);
179 do {
180 next_file = file->next_file;
181 acl_current = file->acl;
182 if (acl_current) {
183 do {
184 acl_next = acl_current->next_acl;
185 wzd_free(acl_current);
186 acl_current = acl_next;
187 } while (acl_current);
188 }
189 if (file->data) free(file->data);
190 wzd_free (file);
191 file = next_file;
192 } while (file);
193 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
194 }
195
196 /** \brief Find file \a name in file list
197 * \param[in] name file name
198 * \param[in] first file list head
199 * \return
200 * - file if found
201 * - NULL if not found
202 */
find_file(const char * name,struct wzd_file_t * first)203 static struct wzd_file_t * find_file(const char *name, struct wzd_file_t *first)
204 {
205 struct wzd_file_t *current=first;
206
207 WZD_MUTEX_LOCK(SET_MUTEX_FILE_T);
208 while (current) {
209 if (strcmp(name,current->filename)==0) {
210 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
211 return current;
212 }
213 current = current->next_file;
214 }
215 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
216 return NULL;
217 }
218
219 /** \brief Remove file from linked list
220 * \param[in] name file name
221 * \param[in,out] file list head
222 * \return
223 * - the removed item if found (which must be freed using free_file_recursive()
224 * - NULL if not found
225 */
remove_file(const char * name,struct wzd_file_t ** first)226 static struct wzd_file_t * remove_file(const char *name, struct wzd_file_t **first)
227 {
228 struct wzd_file_t *current=*first,*prev,*removed;
229
230 if (!current) return NULL;
231
232 WZD_MUTEX_LOCK(SET_MUTEX_FILE_T);
233 /* first to be removed ? */
234 if (strcmp(name,current->filename)==0) {
235 removed = current;
236 *first = removed->next_file;
237 removed->next_file = NULL;
238 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
239 return removed;
240 }
241
242 prev = current;
243 current = current->next_file;
244
245 while (current) {
246 if (strcmp(name,current->filename)==0) {
247 removed = current;
248 prev->next_file = current->next_file;
249 current->next_file = NULL;
250 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
251 return removed;
252 }
253 prev = current;
254 current = current->next_file;
255 } /* while current */
256 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
257 return NULL;
258 }
259
260 /** \brief Insert a new file structure in list, sorted by name
261 * \param[in] entry file definition
262 * \param[in,out] tab pointer to file list
263 */
file_insert_sorted(struct wzd_file_t * entry,struct wzd_file_t ** tab)264 void file_insert_sorted(struct wzd_file_t *entry, struct wzd_file_t **tab)
265 {
266 struct wzd_file_t *it = *tab;
267 struct wzd_file_t *itp = NULL;
268
269 if ( ! *tab ) {
270 *tab = entry;
271 return;
272 }
273
274 WZD_MUTEX_LOCK(SET_MUTEX_FILE_T);
275 while (it) {
276 if (strcmp(entry->filename,it->filename)>0)
277 {
278 itp = it;
279 it = it->next_file;
280 continue;
281 }
282
283 /* we insert here */
284
285 /* head insertion */
286 if (itp == NULL) {
287 entry->next_file = *tab;
288 *tab = entry;
289 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
290 return;
291 }
292
293 /* middle-insertion */
294 entry->next_file = it;
295 itp->next_file = entry;
296
297 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
298 return;
299 }
300
301 /* tail insertion */
302 /* itp can't be NULL here, the first case would have trapped it */
303 itp->next_file = entry;
304
305 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
306 return;
307 }
308
309 /** \brief Return ACL corresonding to \a username for \a file
310 * \param[in] username User name
311 * \param[in] file file structure
312 * \return The ACL structure, or NULL
313 */
find_acl(const char * username,struct wzd_file_t * file)314 static wzd_acl_line_t * find_acl(const char * username, struct wzd_file_t * file)
315 {
316 wzd_acl_line_t *current = file->acl;
317
318 WZD_MUTEX_LOCK(SET_MUTEX_ACL_T);
319 while (current) {
320 if (strcmp(username,current->user)==0) {
321 WZD_MUTEX_UNLOCK(SET_MUTEX_ACL_T);
322 return current;
323 }
324 current = current->next_acl;
325 }
326 WZD_MUTEX_UNLOCK(SET_MUTEX_ACL_T);
327 return NULL;
328 }
329
330 /** \brief Create a structure for file \a name, set owner and group, and append it to list \a first
331 * \param[in] name file name
332 * \param[in] owner file owner
333 * \param[in] group file group
334 * \param[in,out] first file list
335 * \return a pointer to the new file structure
336 */
add_new_file(const char * name,const char * owner,const char * group,struct wzd_file_t ** first)337 static struct wzd_file_t * add_new_file(const char *name, const char *owner, const char *group, struct wzd_file_t **first)
338 {
339 struct wzd_file_t *current, *new_file;
340
341 WZD_MUTEX_LOCK(SET_MUTEX_FILE_T);
342 new_file = wzd_malloc(sizeof(struct wzd_file_t));
343 strncpy(new_file->filename,name,256);
344 memset(new_file->owner,0,256);
345 if (owner) strncpy(new_file->owner,owner,256);
346 memset(new_file->group,0,256);
347 if (group) strncpy(new_file->group,group,256);
348 new_file->acl = NULL;
349 new_file->permissions = mainConfig->umask; /* TODO XXX FIXME hardcoded */
350 new_file->kind = FILE_NOTSET;
351 new_file->data = NULL;
352 new_file->next_file = NULL;
353 if (*first == NULL) {
354 *first = new_file;
355 } else {
356 current = *first;
357 while (current->next_file)
358 current = current->next_file;
359 current->next_file = new_file;
360 }
361 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
362 return new_file;
363 }
364
365 /** Copy file structure and members
366 * \param[in] file_cur file structure
367 * \return a newly allocated file structure copied from \a file_cur, or NULL
368 * \note one field is changed: next_file is set to NULL to avoid side effects.
369 */
file_deep_copy(struct wzd_file_t * file_cur)370 struct wzd_file_t * file_deep_copy(struct wzd_file_t *file_cur)
371 {
372 struct wzd_file_t * new_file=NULL;
373 wzd_acl_line_t * acl_current, * acl_new, *acl_next;
374
375 if (!file_cur) return NULL;
376
377 WZD_MUTEX_LOCK(SET_MUTEX_FILE_T);
378 new_file = wzd_malloc(sizeof(struct wzd_file_t));
379 memcpy(new_file, file_cur, sizeof(struct wzd_file_t));
380 if (file_cur->data)
381 new_file->data = strdup( (char*)file_cur->data ); /** \todo we do not know size */
382
383 if (file_cur->acl) {
384 acl_new = malloc(sizeof(wzd_acl_line_t));
385 memcpy(acl_new, file_cur->acl, sizeof(wzd_acl_line_t));
386 acl_new->next_acl = NULL;
387 new_file->acl = acl_new;
388 acl_current = file_cur->acl->next_acl;
389 while (acl_current) {
390 acl_next = malloc(sizeof(wzd_acl_line_t));
391 memcpy(acl_next, file_cur->acl, sizeof(wzd_acl_line_t));
392 acl_next->next_acl = NULL;
393 acl_new->next_acl = acl_next;
394 acl_new = acl_next;
395 acl_current = acl_current->next_acl;
396 }
397 }
398
399 /* exception: we set next_file to NULL to avoid side effects */
400 new_file->next_file = NULL;
401
402 WZD_MUTEX_UNLOCK(SET_MUTEX_FILE_T);
403 return new_file;
404 }
405
406 /** \brief Add new ACL for a file,user
407 * \param[in] filename file name
408 * \param[in] user
409 * \param[in] rights permission line
410 * \param[in,out] file file structure
411 * \todo return value on error
412 * \todo rename function to use common name standards
413 */
addAcl(const char * filename,const char * user,const char * rights,struct wzd_file_t * file)414 static void addAcl(const char *filename, const char *user, const char *rights, struct wzd_file_t * file)
415 {
416 wzd_acl_line_t * acl_current, * acl_new;
417
418 WZD_MUTEX_LOCK(SET_MUTEX_ACL_T);
419
420 acl_new = wzd_malloc(sizeof(wzd_acl_line_t));
421 strncpy(acl_new->user,user,256);
422 strncpy(acl_new->perms,rights,3);
423
424 /* head insertion */
425 acl_current = file->acl;
426 if (!acl_current) { /* simple case, first insertion */
427 file->acl = acl_new;
428 acl_new->next_acl = NULL;
429 WZD_MUTEX_UNLOCK(SET_MUTEX_ACL_T);
430 return;
431 }
432
433 while (acl_current) {
434 if (strcmp(acl_current->user,user)==0) { /* found ! */
435 strncpy(acl_current->perms,rights,3); /* replace old perms */
436 wzd_free (acl_new);
437 WZD_MUTEX_UNLOCK(SET_MUTEX_ACL_T);
438 return;
439 }
440 acl_current = acl_current->next_acl;
441 }
442
443 /* new acl for this file */
444 acl_new->next_acl = file->acl;
445 file->acl = acl_new;
446 WZD_MUTEX_UNLOCK(SET_MUTEX_ACL_T);
447 }
448
449 /** Read permission file and decode it
450 * \param[in] permfile full path to permission file
451 * \param[out] pTabFiles address of linked list (which will be allocated) containing file permissions
452 * \return 0 if ok
453 * \todo should be "atomic"
454 */
readPermFile(const char * permfile,struct wzd_file_t ** pTabFiles)455 int readPermFile(const char *permfile, struct wzd_file_t **pTabFiles)
456 {
457 wzd_cache_t * fp;
458 char line_buffer[BUFFER_LEN];
459 struct wzd_file_t *current_file, *ptr_file;
460 char * token1, *token2, *token3, *token4, *token5, *token6;
461 char *ptr;
462
463 if ( !pTabFiles ) return E_PARAM_NULL;
464
465 current_file = *pTabFiles;
466
467 WZD_MUTEX_LOCK(SET_MUTEX_DIRINFO);
468 fp = wzd_cache_open(permfile,O_RDONLY,0644);
469 if (!fp) {
470 wzd_cache_close(fp);
471 WZD_MUTEX_UNLOCK(SET_MUTEX_DIRINFO);
472 return E_FILE_NOEXIST;
473 }
474
475 ptr = (char*)current_file;
476 current_file = NULL;
477 while ( wzd_cache_gets(fp,line_buffer,BUFFER_LEN-1) )
478 {
479 token1 = strtok_r(line_buffer," \t\r\n",&ptr);
480 if (!token1) continue; /* malformed line */
481 token2 = read_token(NULL, &ptr); /* we can have spaces here */
482 if (!token2) continue; /* malformed line */
483 token3 = read_token(NULL, &ptr); /* we can have spaces here */
484 if (!token3) continue; /* malformed line */
485 token4 = strtok_r(NULL," \t\r\n",&ptr);
486 if (!token4) continue; /* malformed line */
487 /* find file in list */
488 ptr_file = find_file(token2,*pTabFiles);
489 if (!ptr_file) {
490 ptr_file = add_new_file(token2,0,0,pTabFiles);
491 }
492 if (strcmp(token1,"owner")==0) {
493 token5 = strtok_r(NULL," \t\r\n",&ptr);
494 /* if (!token5) continue;*/ /* malformed line */
495 strncpy(ptr_file->owner,token3,256);
496 strncpy(ptr_file->group,token4,256);
497 if (token5) {
498 unsigned long ul;
499 ul = strtoul(token5,&ptr,8);
500 if (ptr==token5) continue;
501 ptr_file->permissions = ul;
502 } else { /* default user/group permission */
503 ptr_file->permissions = mainConfig->umask; /** \todo FIXME hardcoded */
504 }
505 }
506 else if (strcmp(token1,"perm")==0) {
507 addAcl(token2,token3,token4,ptr_file);
508 }
509 else if (strcmp(token1,"link")==0) {
510 /** \todo FIXME handle links: set type to link, set destination, set owner/perms */
511 token5 = strtok_r(NULL," \t\r\n",&ptr);
512 if (!token5) continue; /* malformed line */
513 token6 = strtok_r(NULL," \t\r\n",&ptr);
514
515 ptr_file->kind = FILE_LNK;
516 ptr_file->data = wzd_strdup(token3);
517 strncpy(ptr_file->owner,token4,256);
518 strncpy(ptr_file->group,token5,256);
519 if (token6) {
520 unsigned long ul;
521 ul = strtoul(token6,&ptr,8);
522 if (ptr==token6) continue;
523 ptr_file->permissions = ul;
524 } else { /* default user/group permission */
525 ptr_file->permissions = mainConfig->umask; /** \todo FIXME hardcoded */
526 }
527 }
528 }
529
530 wzd_cache_close(fp);
531 WZD_MUTEX_UNLOCK(SET_MUTEX_DIRINFO);
532
533 return E_OK;
534 }
535
536 /** \brief Write permission file
537 * \param[in] permfile permission file full path
538 * \param[in] pTabFiles address of linked list of permissions
539 * \return 0 if ok
540 */
writePermFile(const char * permfile,struct wzd_file_t ** pTabFiles)541 int writePermFile(const char *permfile, struct wzd_file_t **pTabFiles)
542 {
543 char buffer[BUFFER_LEN];
544 FILE *fp;
545 struct wzd_file_t * file_cur;
546 wzd_acl_line_t * acl_cur;
547 short has_spaces;
548
549 file_cur = *pTabFiles;
550
551 if ( !file_cur ) {
552 /* delete permission file */
553 return unlink(permfile);
554 }
555
556 WZD_MUTEX_LOCK(SET_MUTEX_DIRINFO);
557
558 fp = fopen(permfile,"w"); /* overwrite any existing file */
559 if (!fp) {
560 WZD_MUTEX_UNLOCK(SET_MUTEX_DIRINFO);
561 return -1;
562 }
563
564 /* if file_cur->filename contains spaces, we MUST quote it when writing name */
565 while (file_cur) {
566 if (file_cur->kind == FILE_LNK) {
567 if (strchr( (char*)file_cur->data, ' ')) {
568 snprintf(buffer,sizeof(buffer),"link\t%s\t'%s'\t%s\t%s\t%lo\n",
569 file_cur->filename,(char*)file_cur->data,file_cur->owner,file_cur->group,file_cur->permissions);
570 } else {
571 snprintf(buffer,sizeof(buffer),"link\t%s\t%s\t%s\t%s\t%lo\n",
572 file_cur->filename,(char*)file_cur->data,file_cur->owner,file_cur->group,file_cur->permissions);
573 }
574 (void)fwrite(buffer,strlen(buffer),1,fp);
575 } else { /* not a link */
576 has_spaces = (strchr( (char*)file_cur->filename, ' ') != NULL);
577 /* first write owner if available */
578 if (strlen(file_cur->owner)>0 || strlen(file_cur->group)>0) {
579 if (has_spaces)
580 snprintf(buffer,sizeof(buffer),"owner\t'%s'\t%s\t%s\t%lo\n",
581 file_cur->filename,file_cur->owner,file_cur->group,file_cur->permissions);
582 else
583 snprintf(buffer,sizeof(buffer),"owner\t%s\t%s\t%s\t%lo\n",
584 file_cur->filename,file_cur->owner,file_cur->group,file_cur->permissions);
585 (void)fwrite(buffer,strlen(buffer),1,fp);
586 }
587 acl_cur = file_cur->acl;
588 while (acl_cur) {
589 if (has_spaces)
590 snprintf(buffer,sizeof(buffer),"perm\t'%s'\t%s\t%c%c%c\n",
591 file_cur->filename,acl_cur->user,acl_cur->perms[0],acl_cur->perms[1],acl_cur->perms[2]);
592 else
593 snprintf(buffer,sizeof(buffer),"perm\t%s\t%s\t%c%c%c\n",
594 file_cur->filename,acl_cur->user,acl_cur->perms[0],acl_cur->perms[1],acl_cur->perms[2]);
595 (void)fwrite(buffer,strlen(buffer),1,fp);
596 acl_cur = acl_cur->next_acl;
597 }
598 } /* not a link */
599 file_cur = file_cur->next_file;
600 } /* ! while */
601
602 fclose(fp);
603
604 /* force cache update */
605 wzd_cache_update(permfile);
606
607 WZD_MUTEX_UNLOCK(SET_MUTEX_DIRINFO);
608
609 return 0;
610 }
611
612 /** Check if user has a specific permission, given a file and the directory containing it
613 * \param[in] dir directory where \a file is stored. it MUST be / terminated
614 * \param[in] wanted_file file name
615 * \param[in] wanted_right permission to evaluate
616 * \param[in] user
617 * \return
618 * - 0 if user is authorized to perform action
619 * - 1 if user is not authorized
620 * - -1 on error
621 */
_checkFileForPerm(const char * dir,const char * wanted_file,unsigned long wanted_right,wzd_user_t * user)622 int _checkFileForPerm(const char *dir, const char * wanted_file, unsigned long wanted_right, wzd_user_t * user)
623 {
624 char perm_filename[WZD_MAX_PATH+1];
625 size_t length, neededlength;
626 struct wzd_file_t * file_list=NULL, * file_cur;
627 wzd_acl_line_t * acl_cur;
628 int ret;
629 int is_dir;
630
631 /* find the dir containing the perms file */
632 strncpy(perm_filename,dir,WZD_MAX_PATH);
633 neededlength = strlen(HARD_PERMFILE);
634 length = strlen(perm_filename);
635 /* check if !overflow */
636 if ( length+neededlength >= WZD_MAX_PATH )
637 return -1;
638
639 /* siteop always hav all permissions */
640 if (user->flags && strchr(user->flags,FLAG_SITEOP))
641 return 0;
642
643 strncpy(perm_filename+length,HARD_PERMFILE,neededlength);
644
645 /*
646 out_err(LEVEL_HIGH,"%s:%d\n",__FILE__,__LINE__);
647 out_err(LEVEL_HIGH,"dir %s filename %s wanted file %s\n",dir,perm_filename,wanted_file);
648 */
649
650 ret = readPermFile(perm_filename,&file_list);
651 if (ret) { /* no permissions file */
652 return _default_perm(wanted_right,user);
653 }
654
655 file_cur = find_file(wanted_file,file_list);
656
657 if (file_cur) { /* wanted_file is in list */
658 /* now find corresponding acl */
659 acl_cur = find_acl(user->username,file_cur);
660
661 is_dir = ( strcmp(wanted_file,".")==0 );
662
663 if (!acl_cur) { /* ! in acl list */
664 /* TODO check if user is owner or group of file, and use perms */
665 {
666 unsigned int i;
667 wzd_group_t * group;
668 /* out_err(LEVEL_HIGH,"owner %s\n",file_cur->owner);*/
669 /* out_err(LEVEL_HIGH,"group %s\n",file_cur->group);*/
670 /* out_err(LEVEL_HIGH,"group %lo\n",file_cur->permissions);*/
671 if (strcmp(user->username,file_cur->owner)==0) {
672 /* NOTE all results are inverted (!=) because we return 0 on success ! */
673 switch (wanted_right) {
674 case RIGHT_LIST:
675 case RIGHT_RETR:
676 ret = (file_cur->permissions & 0400);
677 break;
678 case RIGHT_STOR:
679 case RIGHT_MKDIR:
680 case RIGHT_RMDIR:
681 case RIGHT_RNFR:
682 ret = (file_cur->permissions & 0200);
683 break;
684 case RIGHT_CWD:
685 ret = (file_cur->permissions & 0100);
686 break;
687 default:
688 ret = 0;
689 }
690 /* out_err(LEVEL_HIGH,"user is file owner : %d !\n",ret);*/
691 free_file_recursive(file_list);
692 file_list = NULL;
693 return !ret;
694 }
695 for (i=0; i<user->group_num; i++) {
696 group = GetGroupByID(user->groups[i]);
697 if (group && strcmp(group->groupname,file_cur->group)==0) {
698 /* NOTE all results are inverted (!=) because we return 0 on success ! */
699 switch (wanted_right) {
700 case RIGHT_LIST:
701 case RIGHT_RETR:
702 ret = (file_cur->permissions & 0040);
703 break;
704 case RIGHT_STOR:
705 case RIGHT_MKDIR:
706 case RIGHT_RMDIR:
707 case RIGHT_RNFR:
708 ret = (file_cur->permissions & 0020);
709 break;
710 case RIGHT_CWD:
711 ret = (file_cur->permissions & 0010);
712 break;
713 default:
714 ret = 0;
715 }
716 /* out_err(LEVEL_HIGH,"user is in group : %d !\n",ret);*/
717 free_file_recursive(file_list);
718 file_list = NULL;
719 return !ret;
720 }
721 }
722 }
723
724 /* NOTE all results are inverted (!=) because we return 0 on success ! */
725 switch (wanted_right) {
726 case RIGHT_LIST:
727 case RIGHT_RETR:
728 ret = (file_cur->permissions & 0004);
729 break;
730 case RIGHT_STOR:
731 case RIGHT_MKDIR:
732 case RIGHT_RMDIR:
733 case RIGHT_RNFR:
734 ret = (file_cur->permissions & 0002);
735 break;
736 case RIGHT_CWD:
737 ret = (file_cur->permissions & 0001);
738 break;
739 default:
740 ret = 0;
741 }
742 /* out_err(LEVEL_HIGH,"user is in others : %d !\n",ret);*/
743 free_file_recursive(file_list);
744 file_list = NULL;
745 return !ret;
746
747 }
748
749 /* NOTE all results are inverted (!=) because we return 0 on success ! */
750 switch (wanted_right) {
751 case RIGHT_RETR:
752 ret = (acl_cur->perms[0]!='r');
753 break;
754 case RIGHT_STOR:
755 ret = (acl_cur->perms[1]!='w');
756 break;
757 case RIGHT_CWD:
758 if (is_dir) ret = (acl_cur->perms[2]!='x');
759 else ret = -1;
760 break;
761 case RIGHT_LIST:
762 if (is_dir) ret = (acl_cur->perms[0]!='r');
763 else ret = -1;
764 break;
765 case RIGHT_RNFR:
766 ret = (acl_cur->perms[1]!='w');
767 break;
768 default:
769 ret = -1; /* stupid right asked */
770 break;
771 }
772 free_file_recursive(file_list);
773 file_list = NULL;
774 return ret; /* stupid right asked */
775 } else { /* ! in file_list */
776 /* FIXME XXX search in parent dirs ???????? - group perms XXX FIXME */
777 free_file_recursive(file_list);
778 file_list = NULL;
779 return _default_perm(wanted_right,user);
780 } /* ! in acl */
781
782 }
783
784 /** MUST NOT be / terminated (except /) */
_checkPerm(const char * filename,unsigned long wanted_right,wzd_user_t * user)785 int _checkPerm(const char *filename, unsigned long wanted_right, wzd_user_t * user)
786 {
787 char dir[WZD_MAX_PATH+1];
788 char stripped_filename[WZD_MAX_PATH+1];
789 char *ptr;
790 fs_filestat_t s;
791
792 if (!filename || filename[0] == '\0')
793 return -1;
794
795 #ifdef WZD_DBG_PERMS
796 out_err(LEVEL_HIGH,"_checkPerm(%s,%ld,%s)\n",filename,wanted_right,user->username);
797 #endif
798
799 strncpy(dir,filename,WZD_MAX_PATH);
800
801 if (user->flags && strchr(user->flags,FLAG_ANONYMOUS))
802 {
803 switch (wanted_right) {
804 case RIGHT_STOR:
805 case RIGHT_MKDIR:
806 case RIGHT_RMDIR:
807 case RIGHT_RNFR:
808 return -1;
809 }
810 }
811
812 if (fs_file_stat(filename,&s)==-1) {
813 if (wanted_right != RIGHT_STOR && wanted_right != RIGHT_MKDIR)
814 return -1; /* inexistant ? */
815 ptr = strrchr(dir,'/');
816 #ifdef WIN32
817 if ( (ptr-dir)==2 && dir[1]==':' )
818 ptr++;
819 #endif
820 if (ptr) {
821 strcpy(stripped_filename,ptr+1);
822 if (ptr == &dir[0]) *(ptr+1) = '\0';
823 else *ptr = 0;
824 }
825 /* we need to check in parent dir for the same right */
826 if (_checkPerm(dir,wanted_right,user)) return -1; /* we do not have the right to modify parent dir */
827 } else {
828 if (S_ISDIR(s.mode)) { /* isdir */
829 strcpy(stripped_filename,".");
830 } else { /* ! isdir */
831 ptr = strrchr(dir,'/');
832 if (ptr) {
833 strcpy(stripped_filename,ptr+1);
834 if (ptr == &dir[0]) *(ptr+1) = '\0';
835 else *ptr = 0;
836 }
837 } /* ! isdir */
838 } /* stat == -1 */
839
840 if (dir[strlen(dir)-1] != '/') {
841 strcat(dir,"/");
842 }
843
844 /** \bug we need to find a way to know if file is in 'visible' path of user.
845 * We can't do that without a function to convert syspath to ftppath
846 */
847 #if 0 /* checkpath_new already checks that */
848 /* check if file is in user's root path */
849 if (strncmp(dir,user->rootpath,strlen(user->rootpath))!=0)
850 {
851 /* if the file is in a global vfs, it does not need to be in user's rootpath */
852 /** \bug it can be a symlink ! */
853 wzd_vfs_t * vfs = mainConfig->vfs;
854 while(vfs) {
855 if (strncmp(dir,vfs->physical_dir,strlen(vfs->physical_dir))==0)
856 return _checkFileForPerm(dir,stripped_filename,wanted_right,user);
857 vfs = vfs->next_vfs;
858 }
859 /* if dir is not a vfs, we can have a vfile */
860 vfs = mainConfig->vfs;
861 while(vfs) {
862 if (DIRCMP(filename,vfs->physical_dir)==0)
863 return _checkFileForPerm(dir,stripped_filename,wanted_right,user);
864 vfs = vfs->next_vfs;
865 }
866 return 1;
867 }
868 #endif
869
870 return _checkFileForPerm(dir,stripped_filename,wanted_right,user);
871 }
872
873 /** MUST NOT be / terminated (except /) */
_setPerm(const char * filename,const char * granted_user,const char * owner,const char * group,const char * rights,unsigned long perms,wzd_context_t * context)874 int _setPerm(const char *filename, const char *granted_user, const char *owner, const char *group, const char * rights, unsigned long perms, wzd_context_t * context)
875 {
876 char dir[WZD_MAX_PATH+1];
877 char stripped_filename[WZD_MAX_PATH+1];
878 char perm_filename[WZD_MAX_PATH+1];
879 char *ptr;
880 fs_filestat_t s;
881 size_t length, neededlength;
882 struct wzd_file_t * file_list=NULL, * file_cur;
883 int ret;
884
885 if (!filename || filename[0] == '\0')
886 return -1;
887
888 strncpy(dir,filename,WZD_MAX_PATH);
889
890 if (fs_file_stat(filename,&s)==-1) return -1; /* inexistant ? */
891 if (S_ISDIR(s.mode)) { /* isdir */
892 strcpy(stripped_filename,".");
893 } else { /* ! isdir */
894 ptr = strrchr(dir,'/');
895 if (ptr) {
896 strcpy(stripped_filename,ptr+1);
897 *ptr = 0;
898 }
899 } /* ! isdir */
900
901 if (dir[strlen(dir)-1] != '/') {
902 strcat(dir,"/");
903 }
904
905 /* find the dir containing the perms file */
906 strncpy(perm_filename,dir,WZD_MAX_PATH);
907 neededlength = strlen(HARD_PERMFILE);
908 length = strlen(perm_filename);
909 /* check if !overflow */
910 if ( length+neededlength >= WZD_MAX_PATH )
911 return -1;
912
913 strncpy(perm_filename+length,HARD_PERMFILE,neededlength);
914
915
916 #ifdef WZD_DBG_PERMS
917 out_err(LEVEL_FLOOD,"_setPerm: dir %s filename %s wanted file %s\n",dir,perm_filename,stripped_filename);
918 #endif
919
920 WZD_MUTEX_LOCK(SET_MUTEX_PERMISSION);
921
922 ret = readPermFile(perm_filename,&file_list);
923 if (ret) { /* no permissions file */
924 file_cur = add_new_file(stripped_filename,0,0,&file_list);
925 } else { /* permission file */
926 file_cur = find_file(stripped_filename,file_list);
927 if (!file_cur) { /* perm file exists, but does not contains acl concerning filename */
928 file_cur = add_new_file(stripped_filename,0,0,&file_list);
929 }
930 }
931
932 /* set the owner/group */
933 if (owner || group)
934 {
935 if (owner) strncpy(file_cur->owner,owner,256);
936 if (file_cur->owner[0] == '\0')
937 strcpy(file_cur->owner,"nobody");
938 if (group) strncpy(file_cur->group,group,256);
939 if (file_cur->group[0] == '\0')
940 strcpy(file_cur->group,"nogroup");
941 }
942
943 /* add the new acl */
944 /* remember addAcl REPLACE existing acl on user is already existing */
945 if (rights)
946 addAcl(stripped_filename,granted_user,rights,file_cur);
947 if (perms != (unsigned long)-1)
948 {
949 file_cur->permissions = perms;
950 }
951
952 /* finally writes perm file on disk */
953 ret = writePermFile(perm_filename,&file_list);
954
955 free_file_recursive(file_list);
956 file_list = NULL;
957
958 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
959 return 0;
960 }
961
962 /** MUST NOT be / terminated (except /) */
_movePerm(const char * oldfilename,const char * newfilename,const char * owner,const char * group,wzd_context_t * context)963 int _movePerm(const char *oldfilename, const char *newfilename, const char *owner, const char *group, wzd_context_t * context)
964 {
965 char dir[BUFFER_LEN];
966 char src_stripped_filename[BUFFER_LEN];
967 char src_perm_filename[BUFFER_LEN];
968 char dst_stripped_filename[BUFFER_LEN];
969 char dst_perm_filename[BUFFER_LEN];
970 char *ptr;
971 fs_filestat_t s,s2;
972 size_t length, neededlength;
973 struct wzd_file_t * src_file_list=NULL, *dst_file_list=NULL,* file_cur, *file_dst;
974 wzd_acl_line_t * acl;
975 int ret;
976
977 if (!oldfilename || oldfilename[0] == '\0') return -1;
978 if (!newfilename || newfilename[0] == '\0') return -1;
979
980 /* find src perm file name */
981 strncpy(dir,oldfilename,BUFFER_LEN);
982
983 if (fs_file_stat(dir,&s)==-1) return -1; /* inexistant ? */
984 if (S_ISDIR(s.mode)) { /* isdir */
985 /* TODO XXX FIXME Check validity of this assertion ! */
986 /* permissions of directory are self contained ! */
987 return 0;
988 strcpy(src_stripped_filename,".");
989 } else { /* ! isdir */
990 ptr = strrchr(dir,'/');
991 if (ptr) {
992 strcpy(src_stripped_filename,ptr+1);
993 *ptr = 0;
994 }
995 } /* ! isdir */
996
997 if (dir[strlen(dir)-1] != '/') {
998 strcat(dir,"/");
999 }
1000
1001 /* find the dir containing the perms file */
1002 strncpy(src_perm_filename,dir,BUFFER_LEN);
1003 neededlength = strlen(HARD_PERMFILE);
1004 length = strlen(src_perm_filename);
1005 /* check if !overflow */
1006 if ( length+neededlength > 4095 )
1007 return -1;
1008
1009 strncpy(src_perm_filename+length,HARD_PERMFILE,neededlength);
1010
1011 /* find dst perm file name */
1012 strncpy(dir,newfilename,BUFFER_LEN);
1013
1014 /* if dst file is a dir and exists, we can't make the operation */
1015 if (fs_file_stat(dir,&s2)==0) { /* file exists ? */
1016 if (S_ISDIR(s2.mode)) { /* isdir */
1017 return -1;
1018 }
1019 }
1020
1021
1022 if (S_ISDIR(s.mode)) { /* isdir */
1023 strcpy(dst_stripped_filename,".");
1024 } else { /* ! isdir */
1025 ptr = strrchr(dir,'/');
1026 if (ptr) {
1027 strcpy(dst_stripped_filename,ptr+1);
1028 *ptr = 0;
1029 }
1030 } /* ! isdir */
1031
1032 if (dir[strlen(dir)-1] != '/') {
1033 strcat(dir,"/");
1034 }
1035
1036 /* find the dir containing the perms file */
1037 strncpy(dst_perm_filename,dir,BUFFER_LEN);
1038 neededlength = strlen(HARD_PERMFILE);
1039 length = strlen(dst_perm_filename);
1040 /* check if !overflow */
1041 if ( length+neededlength > 4095 )
1042 return -1;
1043
1044 strncpy(dst_perm_filename+length,HARD_PERMFILE,neededlength);
1045
1046 #ifdef WZD_DBG_PERMS
1047 out_err(LEVEL_FLOOD,"%s:%d\n",__FILE__,__LINE__);
1048 out_err(LEVEL_FLOOD,"dir %s filename %s wanted file %s\n",dir,src_perm_filename,src_stripped_filename);
1049 out_err(LEVEL_FLOOD,"dir %s filename %s wanted file %s\n",dir,dst_perm_filename,dst_stripped_filename);
1050 #endif
1051
1052 WZD_MUTEX_LOCK(SET_MUTEX_PERMISSION);
1053
1054 ret = readPermFile(src_perm_filename,&src_file_list);
1055 if (ret) { /* no permissions file */
1056 file_dst = NULL;
1057 } else { /* permission file */
1058 file_dst = remove_file(src_stripped_filename,&src_file_list);
1059 } /* permission file */
1060
1061 /* finally writes perm file on disk */
1062 ret = writePermFile(src_perm_filename,&src_file_list);
1063 free_file_recursive(src_file_list);
1064 src_file_list = NULL;
1065
1066 ret = readPermFile(dst_perm_filename,&dst_file_list);
1067
1068 if (!file_dst) { /* src_file had no acl, so we have to remove acl on dst_file if present, and set owner/group */
1069 file_cur = remove_file(dst_stripped_filename,&dst_file_list);
1070 free_file_recursive(file_cur);
1071 } else {
1072
1073 if (ret) { /* no permissions file */
1074 file_cur = add_new_file(dst_stripped_filename,file_dst->owner,file_dst->group,&dst_file_list);
1075 } else { /* permission file */
1076 file_cur = find_file(dst_stripped_filename,dst_file_list);
1077 if (!file_cur) { /* perm file exists, but does not contains acl concerning filename */
1078 file_cur = add_new_file(dst_stripped_filename,file_dst->owner,file_dst->group,&dst_file_list);
1079 } else {
1080 if (owner) strncpy(file_cur->owner,file_dst->owner,256);
1081 if (group) strncpy(file_cur->group,file_dst->group,256);
1082 }
1083 }
1084
1085 /* replace the new acl */
1086 acl = file_cur->acl;
1087 file_cur->acl = file_dst->acl;
1088 file_dst->acl = acl;
1089
1090 free_file_recursive(file_dst);
1091
1092 } /* if file_dst */
1093
1094 /* finally writes perm file on disk */
1095 ret = writePermFile(dst_perm_filename,&dst_file_list);
1096
1097 free_file_recursive(dst_file_list);
1098 dst_file_list = NULL;
1099
1100 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1101 return 0;
1102 }
1103
1104 #ifdef _MSC_VER
1105
_rdb_init(TMN_REPARSE_DATA_BUFFER * rdb,LPCWSTR wszJunctionPoint)1106 int _rdb_init(TMN_REPARSE_DATA_BUFFER * rdb, LPCWSTR wszJunctionPoint)
1107 {
1108 size_t nDestMountPointBytes;
1109
1110 if (!wszJunctionPoint || !*wszJunctionPoint) {
1111 return -1;
1112 }
1113
1114 nDestMountPointBytes = lstrlenW(wszJunctionPoint) * 2;
1115
1116 rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1117 rdb->ReparseDataLength = nDestMountPointBytes + 12;
1118 rdb->Reserved = 0;
1119 rdb->SubstituteNameOffset = 0;
1120 rdb->SubstituteNameLength = nDestMountPointBytes;
1121 rdb->PrintNameOffset = nDestMountPointBytes + 2;
1122 rdb->PrintNameLength = 0;
1123 lstrcpyW(rdb->PathBuffer, wszJunctionPoint);
1124
1125 return 0;
1126 }
1127
1128 /* returns 0 if ok */
RDB_INIT(TMN_REPARSE_DATA_BUFFER * rdb,LPCSTR szJunctionPoint)1129 int RDB_INIT(TMN_REPARSE_DATA_BUFFER * rdb, LPCSTR szJunctionPoint)
1130 {
1131 wchar_t wszDestMountPoint[512];
1132 size_t cchDest;
1133
1134 if (!szJunctionPoint || !*szJunctionPoint) {
1135 return -1;
1136 }
1137
1138 cchDest = lstrlenA(szJunctionPoint) + 1;
1139 if (cchDest > 512) {
1140 return -1;
1141 }
1142
1143 if (!MultiByteToWideChar(CP_THREAD_ACP,
1144 MB_PRECOMPOSED,
1145 szJunctionPoint,
1146 cchDest,
1147 wszDestMountPoint,
1148 cchDest))
1149 {
1150 return -1;
1151 }
1152
1153 return _rdb_init(rdb,wszDestMountPoint);
1154 }
1155
BytesForIoControl(const TMN_REPARSE_DATA_BUFFER * rdb)1156 int BytesForIoControl(const TMN_REPARSE_DATA_BUFFER *rdb)
1157 {
1158 return rdb->ReparseDataLength + TMN_REPARSE_DATA_BUFFER_HEADER_SIZE;
1159 }
1160
Reparse_Dir_HANDLE(LPCTSTR szDir,int bWriteable)1161 HANDLE Reparse_Dir_HANDLE(LPCTSTR szDir, int bWriteable)
1162 {
1163 return CreateFile( szDir,
1164 GENERIC_READ | (bWriteable ? GENERIC_WRITE : 0),
1165 0,
1166 0,
1167 OPEN_EXISTING,
1168 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
1169 0);
1170 }
1171
1172 /* returns 0 if failed, non-zero if success */
SetReparsePoint(HANDLE m_hDir,const TMN_REPARSE_DATA_BUFFER * rdb)1173 int SetReparsePoint(HANDLE m_hDir, const TMN_REPARSE_DATA_BUFFER* rdb)
1174 {
1175 DWORD dwBytes;
1176 return DeviceIoControl(m_hDir,
1177 FSCTL_SET_REPARSE_POINT,
1178 (LPVOID)rdb,
1179 BytesForIoControl(rdb),
1180 NULL,
1181 0,
1182 &dwBytes,
1183 0);
1184 }
1185
DeleteReparsePoint(HANDLE m_hDir)1186 int DeleteReparsePoint(HANDLE m_hDir)
1187 {
1188 REPARSE_GUID_DATA_BUFFER rgdb = { 0 };
1189 DWORD dwBytes;
1190 rgdb.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1191 return DeviceIoControl(m_hDir,
1192 FSCTL_DELETE_REPARSE_POINT,
1193 &rgdb,
1194 REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
1195 NULL,
1196 0,
1197 &dwBytes,
1198 0);
1199 }
1200
CreateJunctionPoint(LPCTSTR szMountDir,LPCTSTR szDestDirArg)1201 int CreateJunctionPoint(LPCTSTR szMountDir, LPCTSTR szDestDirArg)
1202 {
1203 TCHAR szDestDir[1024];
1204 char szBuff[MAXIMUM_REPARSE_DATA_BUFFER_SIZE] = { 0 };
1205 TMN_REPARSE_DATA_BUFFER * rdb;
1206 TCHAR szFullDir[1024];
1207 LPTSTR pFilePart;
1208
1209 if (!szMountDir || !szDestDirArg || !szMountDir[0] || !szDestDirArg[0]) {
1210 return -1;
1211 }
1212
1213 if (szDestDirArg[0] == '\\' && szDestDirArg[1] == '?') {
1214 lstrcpy(szDestDir, szDestDirArg);
1215 } else {
1216 lstrcpy(szDestDir, TEXT("\\??\\"));
1217 if (!GetFullPathName(szDestDirArg, 1024, szFullDir, &pFilePart) ||
1218 GetFileAttributes(szFullDir) == -1)
1219 {
1220 return -1;
1221 }
1222 lstrcat(szDestDir, szFullDir);
1223 }
1224
1225 if (!GetFullPathName(szMountDir, 1024, szFullDir, &pFilePart) )
1226 {
1227 return -1;
1228 }
1229 szMountDir = szFullDir;
1230
1231 // create link if not existing
1232 CreateDirectory(szMountDir, NULL);
1233
1234 rdb = (TMN_REPARSE_DATA_BUFFER*)szBuff;
1235
1236 RDB_INIT(rdb,szDestDir);
1237
1238 {
1239 HANDLE handle;
1240 handle = Reparse_Dir_HANDLE(szMountDir, 1 /* true */);
1241 if (handle == INVALID_HANDLE_VALUE) { CloseHandle(handle); RemoveDirectory(szMountDir); return -1; }
1242 if (!SetReparsePoint(handle,rdb)) { CloseHandle(handle); RemoveDirectory(szMountDir); return -1; }
1243 CloseHandle(handle);
1244 }
1245
1246
1247 return 0;
1248 }
1249
RemoveJunctionPoint(LPCTSTR szDir)1250 int RemoveJunctionPoint(LPCTSTR szDir)
1251 {
1252 TCHAR szFullDir[1024];
1253 LPTSTR pFilePart;
1254
1255 if (!szDir || !szDir[0]) {
1256 return -1;
1257 }
1258
1259 if (!GetFullPathName(szDir, 1024, szFullDir, &pFilePart) )
1260 {
1261 return -1;
1262 }
1263 szDir = szFullDir;
1264
1265 {
1266 HANDLE handle;
1267 handle = Reparse_Dir_HANDLE(szDir, 1 /* true */);
1268 if (handle == INVALID_HANDLE_VALUE) { CloseHandle(handle); return -1; }
1269 if (!DeleteReparsePoint(handle)) { CloseHandle(handle); return -1; }
1270 CloseHandle(handle);
1271 RemoveDirectory(szDir);
1272 }
1273
1274
1275 return 0;
1276 }
1277
1278
1279
1280
1281 #endif
1282
softlink_create(const char * target,const char * linkname)1283 int softlink_create(const char *target, const char *linkname)
1284 {
1285 char perm_filename[WZD_MAX_PATH];
1286 char stripped_filename[WZD_MAX_PATH];
1287 char *ptr;
1288 struct wzd_file_t * perm_list=NULL, * file_cur;
1289 int ret;
1290 fs_filestat_t s;
1291
1292 if (fs_file_stat(target,&s)) { /* target does not exist ?! */
1293 out_err(LEVEL_FLOOD, "symlink: source does not exist (%s)\n", target);
1294 return -1;
1295 }
1296 if (fs_file_stat(linkname,&s) != -1) { /* linkname already exist ?! */
1297 out_err(LEVEL_FLOOD, "symlink: destination already exists (%s)\n", linkname);
1298 return -1;
1299 }
1300
1301 /* get permission file */
1302 strncpy(perm_filename,linkname,WZD_MAX_PATH);
1303 REMOVE_TRAILING_SLASH(perm_filename);
1304
1305 ptr = strrchr(perm_filename,'/');
1306 if (!ptr) return -1;
1307 {
1308 /* check that dir exist */
1309 if (ptr != perm_filename
1310 #ifdef WIN32
1311 && ptr[-1] != ':'
1312 #endif
1313 )
1314 {
1315 *ptr = '\0';
1316 if (fs_file_stat(perm_filename,&s)) {
1317 out_err(LEVEL_FLOOD, "symlink: destination directory does not exist (%s)\n", perm_filename);
1318 return -1;
1319 }
1320 *ptr = '/';
1321 }
1322 }
1323 ptr++; /* position is just after last / */
1324 strncpy(stripped_filename, ptr, WZD_MAX_PATH);
1325 strncpy(ptr, HARD_PERMFILE, WZD_MAX_PATH - (ptr-perm_filename));
1326
1327 WZD_MUTEX_LOCK(SET_MUTEX_PERMISSION);
1328 /* read perm file */
1329 ret = readPermFile(perm_filename,&perm_list);
1330
1331 /* create new entry */
1332 if (ret) { /* no permission file */
1333 file_cur = add_new_file(stripped_filename, 0, 0, &perm_list);
1334 } else {
1335 file_cur = find_file(stripped_filename, perm_list);
1336 if (file_cur) {
1337 /* error, an entry already exists with the same name */
1338 out_err(LEVEL_FLOOD, "symlink: link already exists here (%s)\n", perm_filename);
1339 free_file_recursive(perm_list);
1340 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1341 return EEXIST;
1342 }
1343 file_cur = add_new_file(stripped_filename, 0, 0, &perm_list);
1344 }
1345
1346 file_cur->kind = FILE_LNK;
1347 file_cur->data = strdup(target);
1348 REMOVE_TRAILING_SLASH( (char*) file_cur->data );
1349
1350 /** \todo set owner/group of symlink ? */
1351 strncpy(file_cur->owner,"nobody",256);
1352 strncpy(file_cur->group,"nogroup",256);
1353
1354 /* write modified permission file on disk */
1355 ret = writePermFile(perm_filename, &perm_list);
1356
1357 free_file_recursive(perm_list);
1358 perm_list = NULL;
1359 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1360
1361 return 0;
1362 }
1363
softlink_remove(const char * linkname)1364 int softlink_remove(const char *linkname)
1365 {
1366 char perm_filename[WZD_MAX_PATH];
1367 char stripped_filename[WZD_MAX_PATH];
1368 char *ptr;
1369 size_t length;
1370 struct wzd_file_t * perm_list=NULL, * file_cur;
1371 int ret;
1372
1373 /* get permission file */
1374 if (!linkname) return -1;
1375
1376 strncpy(perm_filename,linkname,WZD_MAX_PATH);
1377 length = strlen(perm_filename);
1378 if (length > 1 && perm_filename[length-1] == '/') perm_filename[--length] = '\0';
1379
1380 ptr = strrchr(perm_filename,'/');
1381 if (!ptr) return -1;
1382 ptr++; /* position is just after last / */
1383 strncpy(stripped_filename, ptr, WZD_MAX_PATH);
1384 strncpy(ptr, HARD_PERMFILE, WZD_MAX_PATH - (ptr-perm_filename));
1385
1386 WZD_MUTEX_LOCK(SET_MUTEX_PERMISSION);
1387 /* read perm file */
1388 ret = readPermFile(perm_filename,&perm_list);
1389
1390 /* remove entry */
1391 if (!ret) {
1392 file_cur = find_file(stripped_filename, perm_list);
1393 if ( !file_cur || file_cur->kind != FILE_LNK )
1394 {
1395 free_file_recursive(perm_list);
1396 out_err(LEVEL_FLOOD, "symlink: trying to remove something that is not a link (%s)\n", linkname);
1397 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1398 return -1;
1399 }
1400
1401 file_cur = remove_file(stripped_filename, &perm_list);
1402
1403 /* write modified permission file on disk */
1404 ret = writePermFile(perm_filename, &perm_list);
1405
1406 free_file_recursive(file_cur);
1407 free_file_recursive(perm_list);
1408 }
1409
1410 perm_list = NULL;
1411 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1412
1413 return 0;
1414 }
1415
1416
1417 /************ PUBLIC FUNCTIONS ***************/
1418
file_open(const char * filename,int mode,unsigned long wanted_right,wzd_context_t * context)1419 int file_open(const char *filename, int mode, unsigned long wanted_right, wzd_context_t * context)
1420 {
1421 int fd;
1422 int ret;
1423 wzd_user_t * user;
1424 short is_locked;
1425
1426 user = GetUserByID(context->userid);
1427
1428 if (mode & O_WRONLY)
1429 ret = _checkPerm(filename,RIGHT_STOR,user);
1430 else
1431 ret = _checkPerm(filename,RIGHT_RETR,user);
1432 if (ret)
1433 return -1;
1434
1435 /* is a directory ? */
1436 {
1437 fs_filestat_t s;
1438 if (fs_file_stat(filename,&s) == 0) {
1439 if (S_ISDIR(s.mode)) return -1;
1440 }
1441 }
1442
1443 #ifdef WIN32
1444 mode |= _O_BINARY;
1445 #endif
1446
1447 fd = fs_open(filename,mode,0666);
1448 if (fd == -1) {
1449 out_log(LEVEL_INFO,"Can't open %s,errno %d : %s\n",filename,errno,strerror(errno));
1450 return -1;
1451 }
1452
1453 is_locked = file_islocked(fd,F_WRLCK);
1454
1455 if (is_locked == -1) {
1456 out_log(LEVEL_NORMAL,"Could not get lock info\n");
1457 }
1458 else {
1459 if ( mode & O_WRONLY ) {
1460 if (is_locked) {
1461 close(fd);
1462 /* out_err(LEVEL_HIGH,"Can't open %s in write mode, locked !\n",filename);*/
1463 return -1;
1464 }
1465 file_lock(fd,F_WRLCK);
1466 }
1467 else {
1468 if (is_locked) {
1469 /* out_err(LEVEL_HIGH,"%s is locked, trying to read\n",filename);*/
1470 if ( CFG_GET_OPTION(mainConfig,CFG_OPT_DENY_ACCESS_FILES_UPLOADED) ) {
1471 close(fd);
1472 return -1;
1473 }
1474 }
1475 }
1476 }
1477
1478 return fd;
1479 }
1480
file_close(int fd,wzd_context_t * context)1481 void file_close(int fd, wzd_context_t * context)
1482 {
1483 close(fd);
1484 }
1485
file_seek(fd_t fd,fs_off_t offset,int whence)1486 fs_off_t file_seek(fd_t fd, fs_off_t offset, int whence)
1487 {
1488 return fs_lseek(fd,offset,whence);
1489 }
1490
1491 /** NOTE:
1492 * one of username/groupname can be NULL
1493 * context is usefull to check if the user can chown to other users
1494 */
file_chown(const char * filename,const char * username,const char * groupname,wzd_context_t * context)1495 int file_chown(const char *filename, const char *username, const char *groupname, wzd_context_t * context)
1496 {
1497 return _setPerm(filename,0,username,groupname,0,(unsigned long)-1,context);
1498 }
1499
file_mkdir(const char * dirname,unsigned int mode,wzd_context_t * context)1500 int file_mkdir(const char *dirname, unsigned int mode, wzd_context_t * context)
1501 {
1502 int ret;
1503 int err;
1504 wzd_user_t * user;
1505
1506 user = GetUserByID(context->userid);
1507
1508 ret = _checkPerm(dirname,RIGHT_MKDIR,user);
1509 if (ret) return E_NOPERM;
1510 ret = fs_mkdir(dirname,0755,&err);
1511
1512 return (ret) ? E_COMMAND_FAILED : E_OK;
1513 }
1514
1515 /** @brief remove directory.
1516 *
1517 * dirname must be an absolute path
1518 */
file_rmdir(const char * dirname,wzd_context_t * context)1519 int file_rmdir(const char *dirname, wzd_context_t * context)
1520 {
1521 int ret;
1522 wzd_user_t * user;
1523 fs_filestat_t s;
1524 fs_dir_t * dir;
1525 fs_fileinfo_t * finfo;
1526
1527 user = GetUserByID(context->userid);
1528
1529 ret = _checkPerm(dirname,RIGHT_RMDIR,user);
1530 if (ret) return -1;
1531
1532 /* is a directory ? */
1533 if (fs_file_stat(dirname,&s)) return -1;
1534 if (!S_ISDIR(s.mode)) return -1;
1535
1536 /* is dir empty ? */
1537 {
1538 char path_perm[2048];
1539 const char *filename;
1540
1541 if ( fs_dir_open(dirname,&dir) ) return 0;
1542
1543 while ( !fs_dir_read(dir,&finfo) ) {
1544 filename = fs_fileinfo_getname(finfo);
1545
1546 if (strcmp(filename,".")==0 ||
1547 strcmp(filename,"..")==0 ||
1548 strcmp(filename,HARD_PERMFILE)==0) /* XXX hide perm file ! */
1549 continue;
1550 fs_dir_close(dir);
1551 return 1; /* dir not empty */
1552 }
1553
1554 fs_dir_close(dir);
1555
1556 /* remove permission file */
1557 strcpy(path_perm,dirname); /* path is already ended by / */
1558 if (path_perm[strlen(path_perm)-1] != '/')
1559 strcat(path_perm,"/");
1560 (void)strlcat(path_perm,HARD_PERMFILE,sizeof(path_perm));
1561 unlink(path_perm);
1562 }
1563
1564 #ifdef DEBUG
1565 out_err(LEVEL_HIGH,"Removing directory '%s'\n",dirname);
1566 #endif
1567
1568 #ifndef __CYGWIN__
1569 {
1570 fs_filestat_t s;
1571 fs_file_lstat(dirname,&s);
1572 if (S_ISLNK(s.mode))
1573 return unlink(dirname);
1574 }
1575 #endif
1576 return rmdir(dirname);
1577
1578 }
1579
1580 /** \brief Change the name or location of a file
1581 *
1582 * old_filename and new_filename must be ABSOLUTE paths
1583 */
file_rename(const char * old_filename,const char * new_filename,wzd_context_t * context)1584 int file_rename(const char *old_filename, const char *new_filename, wzd_context_t * context)
1585 {
1586 char path[2048];
1587 char * ptr;
1588 int ret;
1589 wzd_user_t * user;
1590
1591 user = GetUserByID(context->userid);
1592
1593 strncpy(path,new_filename,2048);
1594 ptr = strrchr(path,'/');
1595 if (!ptr) return 1;
1596 *ptr = '\0';
1597 ret = _checkPerm(old_filename,RIGHT_RNFR,user);
1598 ret = ret || _checkPerm(path,RIGHT_STOR,user);
1599 if (ret)
1600 return 1;
1601
1602 /* change file name in perm file !! */
1603 ret = _movePerm(old_filename,new_filename,0,0,context);
1604
1605 ret = safe_rename(old_filename,new_filename);
1606 if (ret==-1) {
1607 #ifdef DEBUG
1608 out_err(LEVEL_HIGH,"rename error %d (%s)\n", errno, strerror(errno));
1609 #endif
1610 return 1;
1611 }
1612
1613 return 0;
1614 }
1615
file_remove(const char * filename,wzd_context_t * context)1616 int file_remove(const char *filename, wzd_context_t * context)
1617 {
1618 char perm_filename[BUFFER_LEN];
1619 char stripped_filename[BUFFER_LEN];
1620 char * ptr;
1621 int ret;
1622 wzd_user_t * user;
1623 struct wzd_file_t * file_list=NULL, * file_cur;
1624 size_t neededlength, length;
1625
1626 /* find the dir containing the perms file */
1627 strncpy(perm_filename,filename,BUFFER_LEN);
1628 ptr = strrchr(perm_filename,'/');
1629 if (!ptr || *(ptr+1)=='\0') return -1;
1630 strcpy(stripped_filename,ptr+1);
1631 if (ptr != perm_filename) *(ptr+1)='\0';
1632 neededlength = strlen(HARD_PERMFILE);
1633 length = strlen(perm_filename);
1634 /* check if !overflow */
1635 if ( length+neededlength > 4095 )
1636 return -1;
1637
1638 strncpy(perm_filename+length,HARD_PERMFILE,neededlength);
1639 perm_filename[length+neededlength]='\0';
1640
1641 user = GetUserByID(context->userid);
1642
1643 /* ret = _checkPerm(filename,RIGHT_STOR ,user);*/
1644 /* to delete, defaults permissions are: owner and siteop can delete file */
1645 if (user->flags && strchr(user->flags,FLAG_SITEOP))
1646 ret = 0; /* siteop -> ok */
1647 else
1648 {
1649 ret = 1;
1650 file_cur = file_stat(filename, context);
1651
1652 /* if file_cur is NULL it means that we have no entry for that file
1653 * it happens when deleting a symlink, when destination does not
1654 * exist
1655 */
1656 if (file_cur) {
1657 if (strcmp(user->username, file_cur->owner)==0) ret = 0; /* owner */
1658
1659 free_file_recursive(file_cur);
1660 file_cur = NULL;
1661 }
1662
1663 /* The delete permission is special: by default, all users can run the DELE
1664 * command, but only owner of the file or siteops can delete files.
1665 * If the "delete" permission is set, it will allow non-owners to delete the file.
1666 */
1667 {
1668 wzd_command_t * command;
1669 wzd_string_t * str = STR("delete");
1670
1671 command = commands_find(mainConfig->commands_list, str);
1672 str_deallocate(str);
1673 if (commands_check_permission(command, context) == 0) ret = 0;
1674 }
1675
1676 }
1677
1678 if (ret)
1679 return 1;
1680
1681 WZD_MUTEX_LOCK(SET_MUTEX_PERMISSION);
1682 /* remove name in perm file !! */
1683 ret = readPermFile(perm_filename,&file_list);
1684 if (!ret) {
1685 file_cur = remove_file(stripped_filename, &file_list);
1686 ret = writePermFile(perm_filename,&file_list);
1687 free_file_recursive(file_cur);
1688 free_file_recursive(file_list);
1689 }
1690 ret = unlink(filename);
1691 if (ret==-1) {
1692 #ifdef DEBUG
1693 out_err(LEVEL_HIGH,"remove error %d (%s)\n", errno, strerror(errno));
1694 #endif
1695 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1696 return 1;
1697 }
1698 WZD_MUTEX_UNLOCK(SET_MUTEX_PERMISSION);
1699
1700 return 0;
1701 }
1702
file_getowner(const char * filename,wzd_context_t * context)1703 wzd_user_t * file_getowner(const char *filename, wzd_context_t * context)
1704 {
1705 char perm_filename[BUFFER_LEN];
1706 char stripped_filename[BUFFER_LEN];
1707 char * ptr;
1708 int ret;
1709 struct wzd_file_t * file_list=NULL, * file_cur;
1710 size_t neededlength, length;
1711 fs_filestat_t s;
1712
1713 if (fs_file_stat(filename,&s))
1714 return NULL;
1715
1716 /* find the dir containing the perms file */
1717 strncpy(perm_filename,filename,BUFFER_LEN);
1718 ptr = strrchr(perm_filename,'/');
1719 if (!ptr || *(ptr+1)=='\0') return NULL;
1720
1721 if (S_ISDIR(s.mode)) { /* isdir */
1722 strcpy(stripped_filename,".");
1723 } else { /* ! isdir */
1724 ptr = strrchr(perm_filename,'/');
1725 if (ptr) {
1726 strcpy(stripped_filename,ptr+1);
1727 *ptr = 0;
1728 }
1729 } /* ! isdir */
1730
1731
1732 /* strcpy(stripped_filename,ptr+1);*/
1733 /* if (ptr != perm_filename) *(ptr+1)='\0';*/
1734
1735 neededlength = strlen(HARD_PERMFILE)+1;
1736 length = strlen(perm_filename);
1737 /* check if !overflow */
1738 if ( length+neededlength > 4095 )
1739 return NULL;
1740
1741 if (perm_filename[length-1] != '/' ) {
1742 ++length;
1743 perm_filename[length-1] = '/';
1744 }
1745 strncpy(perm_filename+length,HARD_PERMFILE,neededlength);
1746
1747 /* remove name in perm file !! */
1748 ret = readPermFile(perm_filename,&file_list);
1749 if (!ret) {
1750 /* we have a permission file */
1751 file_cur = file_list;
1752 while (file_cur)
1753 {
1754 if (strcmp(stripped_filename,file_cur->filename)==0) {
1755 if (file_cur->owner[0]!='\0')
1756 {
1757 wzd_user_t * user;
1758 user = GetUserByName(file_cur->owner);
1759 free_file_recursive(file_list);
1760 return user;
1761 }
1762 else
1763 {
1764 free_file_recursive(file_list);
1765 return GetUserByName("nobody");
1766 }
1767 }
1768 file_cur = file_cur->next_file;
1769 }
1770 free_file_recursive(file_list);
1771 }
1772
1773 return GetUserByName("nobody");
1774 }
1775
1776 /** Permissions are returned as a hex value composed of permissions ORed like
1777 * RIGHT_LIST | RIGHT_CWD
1778 */
file_getperms(struct wzd_file_t * file,wzd_context_t * context)1779 unsigned long file_getperms(struct wzd_file_t * file, wzd_context_t * context)
1780 {
1781 unsigned long perms = 0;
1782 wzd_user_t * user;
1783 wzd_acl_line_t * acl_cur;
1784 wzd_group_t * group;
1785
1786 WZD_ASSERT(context != NULL);
1787
1788 user = GetUserByID(context->userid);
1789 if (!user) return RIGHT_NONE;
1790
1791 if (!file) return _default_perm(0xffffffff,user);
1792
1793 /* now find corresponding acl */
1794 acl_cur = find_acl(user->username,file);
1795
1796 if (acl_cur) {
1797 if (acl_cur->perms[0]=='r') perms |= RIGHT_RETR;
1798 if (acl_cur->perms[1]=='w') perms |= RIGHT_STOR | RIGHT_RNFR;
1799 if (file->kind == FILE_DIR && acl_cur->perms[2]=='x') perms |= RIGHT_CWD;
1800 } else { /* no acl, check 'permissions field */
1801 /* owner ? */
1802 if (strcmp(user->username,file->owner)==0) {
1803 if (file->permissions & 0400) perms |= RIGHT_RETR;
1804 if (file->permissions & 0200) perms |= RIGHT_STOR | RIGHT_RNFR;
1805 if (file->kind == FILE_DIR && file->permissions & 0100) perms |= RIGHT_CWD;
1806 } else {
1807 /* same group ? */
1808 unsigned int i;
1809 unsigned short found=0;
1810
1811 for (i=0; i<user->group_num; i++) {
1812 group = GetGroupByID(user->groups[i]);
1813 if (group && strcmp(group->groupname,file->group)==0) {
1814 found++;
1815 if (file->permissions & 0040) perms |= RIGHT_RETR;
1816 if (file->permissions & 0020) perms |= RIGHT_STOR | RIGHT_RNFR;
1817 if (file->kind == FILE_DIR && file->permissions & 0010) perms |= RIGHT_CWD;
1818 }
1819 }
1820
1821 if (!found) { /* "others" permissions apply */
1822 if (file->permissions & 0004) perms |= RIGHT_RETR;
1823 if (file->permissions & 0002) perms |= RIGHT_STOR | RIGHT_RNFR;
1824 if (file->kind == FILE_DIR && file->permissions & 0001) perms |= RIGHT_CWD;
1825 }
1826 }
1827 }
1828
1829 /* is a directory ? */
1830 if (file->kind == FILE_DIR) {
1831 if (perms & RIGHT_RETR) perms |= RIGHT_LIST;
1832 if (perms & RIGHT_STOR) perms |= RIGHT_MKDIR;
1833 }
1834
1835 /** \todo RIGHT_DELE is never checked */
1836
1837 return perms;
1838 }
1839
1840
1841 /** This function return information about the specified file. You do not need any
1842 * special right on the file, but you need search rights on any directory on the
1843 * path to the file.
1844 *
1845 * If filename is a symbolic link, the destination is stat-ed, not the link itself.
1846 *
1847 * Caller MUST free memory using \ref free_file_recursive
1848 *
1849 * \return struct, or NULL if nothing known, -1 if error or non-existant
1850 */
file_stat(const char * filename,wzd_context_t * context)1851 struct wzd_file_t * file_stat(const char *filename, wzd_context_t * context)
1852 {
1853 char perm_filename[WZD_MAX_PATH+1];
1854 char stripped_filename[WZD_MAX_PATH+1];
1855 char * ptr;
1856 struct wzd_file_t * file_list=NULL, * file_cur, *file;
1857 size_t neededlength, length;
1858 fs_filestat_t s;
1859 int nx=0;
1860
1861 /** \bug no no no, it can be a symlink or a vfs ! */
1862 /* if (fs_stat(filename,&s))
1863 return NULL;*/
1864
1865 /* check for VFS */
1866 {
1867 wzd_vfs_t * vfs = mainConfig->vfs;
1868 char * buffer_vfs;
1869
1870 while (vfs) {
1871 buffer_vfs = vfs_replace_cookies(vfs->virtual_dir,context);
1872 if (!buffer_vfs) {
1873 out_log(LEVEL_CRITICAL,"vfs_replace_cookies returned NULL for %s\n",vfs->virtual_dir);
1874 vfs = vfs->next_vfs;
1875 continue;
1876 }
1877
1878 if (DIRCMP(buffer_vfs,filename)==0) {
1879 /* ok, we have a candidate */
1880 file = file_stat(vfs->physical_dir,context);
1881 wzd_free(buffer_vfs);
1882 return file;
1883 }
1884
1885 wzd_free(buffer_vfs);
1886 vfs = vfs->next_vfs;
1887 }
1888
1889 }
1890
1891 file = NULL;
1892
1893 /* find the dir containing the perms file */
1894 wzd_strncpy(perm_filename,filename,WZD_MAX_PATH);
1895 length = strlen(perm_filename);
1896 if (length >1 && perm_filename[length-1]=='/')
1897 perm_filename[--length] = '\0';
1898 ptr = strrchr(perm_filename,'/');
1899 if (ptr == NULL) return NULL;
1900
1901 if (!fs_file_lstat(filename,&s)) {
1902 if (S_ISDIR(s.mode)) { /* isdir */
1903 strcpy(stripped_filename,".");
1904 } else { /* ! isdir */
1905 ptr = strrchr(perm_filename,'/');
1906 if (ptr) {
1907 strcpy(stripped_filename,ptr+1);
1908 *ptr = 0;
1909 }
1910 }
1911 } else { /* ! exists */
1912 nx = 1;
1913 ptr = strrchr(perm_filename,'/');
1914 if (ptr) {
1915 strcpy(stripped_filename,ptr+1);
1916 *ptr = 0;
1917 if (fs_file_lstat(perm_filename,&s)) {
1918 out_err(LEVEL_FLOOD, "symlink: destination directory does not exist (%s)\n", perm_filename);
1919 return NULL;
1920 }
1921 }
1922 } /* ! exists */
1923
1924
1925 /* strcpy(stripped_filename,ptr+1);*/
1926 /* if (ptr != perm_filename) *(ptr+1)='\0';*/
1927
1928 neededlength = strlen(HARD_PERMFILE)+1;
1929 length = strlen(perm_filename);
1930 /* check if !overflow */
1931 if ( length+neededlength >= WZD_MAX_PATH )
1932 return NULL;
1933
1934 if (perm_filename[length-1] != '/' ) {
1935 ++length;
1936 perm_filename[length-1] = '/';
1937 }
1938 wzd_strncpy(perm_filename+length,HARD_PERMFILE,neededlength);
1939
1940 if ( ! readPermFile(perm_filename,&file_list) ) {
1941 /* we have a permission file */
1942 file_cur = find_file(stripped_filename, file_list);
1943 if (file_cur)
1944 file = file_deep_copy(file_cur);
1945 free_file_recursive(file_list);
1946 }
1947
1948 if (!file && nx) return NULL;
1949
1950 if (file == NULL) { /* create minimal struct */
1951 /** \bug XXX FIXME we should not allocate anything here, since this will be a memory leak */
1952 file = wzd_malloc(sizeof(struct wzd_file_t));
1953
1954 wzd_strncpy(file->filename,stripped_filename,sizeof(file->filename));
1955 file->owner[0] = '\0';
1956 file->group[0] = '\0';
1957 file->permissions = mainConfig->umask; /** \todo FIXME default permission */
1958 file->acl = NULL;
1959 file->kind = FILE_NOTSET;
1960 file->data = NULL;
1961 file->next_file = NULL;
1962 }
1963
1964 if (file) {
1965 if (S_ISDIR(s.mode)) file->kind = FILE_DIR;
1966 if (S_ISLNK(s.mode)) file->kind = FILE_LNK;
1967 if (S_ISREG(s.mode)) file->kind = FILE_REG;
1968 }
1969
1970 return file;
1971 }
1972
1973 /* if program crash, locks acquired by fcntl (POSIX) or _locking (VISUAL)
1974 * are released, and then do are less annoying.
1975 */
file_lock(fd_t fd,short lock_mode)1976 int file_lock(fd_t fd, short lock_mode)
1977 {
1978 #ifdef WZD_DBG_LOCK
1979 out_err(LEVEL_HIGH,"Locking file %d\n",fd);
1980 #endif
1981 #ifndef WIN32
1982 struct flock lck;
1983 lck.l_type = lock_mode;
1984 lck.l_whence = SEEK_SET;/* offset l_start from beginning of file */
1985 lck.l_start = 0;
1986 lck.l_len = 0;
1987 if (fcntl(fd, F_SETLK, &lck) < 0) {
1988 return -1;
1989 }
1990 #else
1991 if (_locking(fd, LK_NBLCK, -1) == -1)
1992 return -1;
1993 #endif
1994 return 0;
1995 }
1996
file_unlock(fd_t fd)1997 int file_unlock(fd_t fd)
1998 {
1999 #ifdef WZD_DBG_LOCK
2000 out_err(LEVEL_HIGH,"Unlocking file %d\n",fd);
2001 #endif
2002 #ifndef WIN32
2003 struct flock lck;
2004 lck.l_type = F_UNLCK;
2005 lck.l_whence = SEEK_SET;/* offset l_start from beginning of file */
2006 lck.l_start = 0;
2007 lck.l_len = 0;
2008 if (fcntl(fd, F_SETLK, &lck) < 0) {
2009 return -1;
2010 }
2011 #else
2012 if (_locking(fd, LK_UNLCK, -1) == -1)
2013 return -1;
2014 #endif
2015 return 0;
2016 }
2017
file_islocked(fd_t fd,short lock_mode)2018 int file_islocked(fd_t fd, short lock_mode)
2019 {
2020 #ifdef WZD_DBG_LOCK
2021 out_err(LEVEL_HIGH,"Testing lock for file %d\n",fd);
2022 #endif
2023 #ifndef WIN32
2024 struct flock lck;
2025 lck.l_type = lock_mode;
2026 lck.l_whence = SEEK_SET;/* offset l_start from beginning of file */
2027 lck.l_start = 0;
2028 lck.l_len = 0;
2029
2030 if (fcntl(fd, F_GETLK, &lck) < 0) {
2031 return -1;
2032 }
2033 if (lck.l_type == F_RDLCK || lck.l_type == F_WRLCK) return 1;
2034 #else
2035 if (_locking(fd, LK_NBLCK, -1) != -1) {
2036 _locking(fd, LK_UNLCK, -1);
2037 return 0;
2038 } else {
2039 if (errno == EACCES) return 1;
2040 return -1;
2041 }
2042 #endif
2043 return 0;
2044 }
2045
file_force_unlock(const char * file)2046 int file_force_unlock(const char *file)
2047 {
2048 int fd;
2049 #ifdef WZD_DBG_LOCK
2050 out_err(LEVEL_HIGH,"Forcing unlock file %s\n",file);
2051 #endif
2052
2053 fd = open(file,O_RDWR);
2054 if (fd < 0) return -1;
2055
2056 #ifndef WIN32
2057 {
2058 struct flock lck;
2059 lck.l_type = F_UNLCK;
2060 lck.l_whence = SEEK_SET;/* offset l_start from beginning of file */
2061 lck.l_start = 0;
2062 lck.l_len = 0;
2063 if (fcntl(fd, F_SETLK, &lck) < 0) {
2064 close(fd);
2065 return -1;
2066 }
2067 }
2068 #else
2069 if (_locking(fd, LK_UNLCK, -1) == -1)
2070 {
2071 close(fd);
2072 return -1;
2073 }
2074 #endif
2075 close(fd);
2076 return 0;
2077 }
2078
2079 /* wrappers just to keep things in same memory zones */
file_read(fd_t fd,void * data,size_t length)2080 ssize_t file_read(fd_t fd,void *data,size_t length)
2081 {
2082 return read(fd,data,length);
2083 }
2084
file_write(fd_t fd,const void * data,size_t length)2085 ssize_t file_write(fd_t fd,const void *data,size_t length)
2086 {
2087 return write(fd,data,length);
2088 }
2089
2090 /* symlink operations */
2091
2092 /** \brief create symlink
2093 * paths must be absolute
2094 * paths must not be / terminated !
2095 * \todo if paths are relative, convert them ?
2096 */
symlink_create(const char * existing,const char * link)2097 int symlink_create(const char *existing, const char *link)
2098 {
2099 /** \todo XXX FIXME check that symlink dest is inside user authorized path */
2100 #ifndef WIN32
2101 return symlink(existing, link);
2102 #else
2103 return softlink_create(existing, link);
2104 /* return CreateJunctionPoint(link, existing);*/
2105 #endif
2106 }
2107
symlink_remove(const char * link)2108 int symlink_remove(const char *link)
2109 {
2110 #ifndef WIN32
2111 fs_filestat_t s;
2112
2113 if (fs_file_lstat(link,&s)) return E_FILE_NOEXIST;
2114 if ( !S_ISLNK(s.mode) ) return E_FILE_TYPE;
2115 return unlink(link);
2116 #else
2117 return softlink_remove(link);
2118 /* return RemoveJunctionPoint(link);*/
2119 #endif
2120 }
2121
2122 /** @} */
2123
2124