/[muddleftpd]/muddleftpd/src/file.c
ViewVC logotype

Diff of /muddleftpd/src/file.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by ganneff, Thu Sep 26 07:55:42 2002 UTC revision 1.1.6.1 by ganneff, Mon Oct 21 19:52:58 2002 UTC
# Line 1  Line 1 
1    
2  /* Copyright (C) 1999 Beau Kuiper  /* Copyright (C) 1999 Beau Kuiper
3    
4     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
# Line 16  Line 17 
17    
18  #include "ftpd.h"  #include "ftpd.h"
19    
20  void file_becomeuser(FTPSTATE *peer)  void file_becomeuser(FTPSTATE * peer)
21  {  {
22          if (config->rootmode)          if (config->rootmode)
23          {          {
24                  if (setegid(peer->gidt_asgid) == -1)                  if (setegid(peer->gidt_asgid) == -1)
25                          log_giveentry(MYLOG_INFO, NULL, safe_snprintf("setegid failed: %s", strerror(errno)));                          log_giveentry(MYLOG_INFO, NULL,
26                                                      safe_snprintf("setegid failed: %s",
27                                                                                    strerror(errno)));
28                  if (seteuid(peer->uidt_asuid) == -1)                  if (seteuid(peer->uidt_asuid) == -1)
29                          log_giveentry(MYLOG_INFO, NULL, safe_snprintf("seteuid failed: %s", strerror(errno)));                          log_giveentry(MYLOG_INFO, NULL,
30                                                      safe_snprintf("seteuid failed: %s",
31                                                                                    strerror(errno)));
32          }          }
33  }  }
34    
35  void file_becomeroot(FTPSTATE *peer)  void file_becomeroot(FTPSTATE * peer)
36  {  {
37          if (config->rootmode)          if (config->rootmode)
38          {          {
39                  if (seteuid((uid_t)0) == -1)                  if (seteuid((uid_t) 0) == -1)
40                          log_giveentry(MYLOG_INFO, NULL, safe_snprintf("seteuid failed: %s", strerror(errno)));                          log_giveentry(MYLOG_INFO, NULL,
41                  if (setegid((gid_t)0) == -1)                                                    safe_snprintf("seteuid failed: %s",
42                          log_giveentry(MYLOG_INFO, NULL, safe_snprintf("setegid failed: %s", strerror(errno)));                                                                                  strerror(errno)));
43                    if (setegid((gid_t) 0) == -1)
44                            log_giveentry(MYLOG_INFO, NULL,
45                                                      safe_snprintf("setegid failed: %s",
46                                                                                    strerror(errno)));
47          }          }
48  }  }
49    
# Line 45  int checkdir(char *dir) Line 54  int checkdir(char *dir)
54    
55          if (result == 0)          if (result == 0)
56                  if (S_ISDIR(check.st_mode))                  if (S_ISDIR(check.st_mode))
57                          return(TRUE);                          return (TRUE);
58    
59          return(FALSE);          return (FALSE);
60  }  }
61    
62  int checkfile(char *file)  int checkfile(char *file)
# Line 57  int checkfile(char *file) Line 66  int checkfile(char *file)
66    
67          if (result == 0)          if (result == 0)
68                  if (!S_ISDIR(check.st_mode))                  if (!S_ISDIR(check.st_mode))
69                          return(TRUE);                          return (TRUE);
70          return(FALSE);          return (FALSE);
71  }  }
72    
73  int checkchdir(FTPSTATE *peer, char *dir)  int checkchdir(FTPSTATE * peer,
74                               char *dir)
75  {  {
76          int result;          int result;
77          char *dir2 = safe_snprintf("%s/", dir);          char *dir2 = safe_snprintf("%s/", dir);
78            
79          result = (check_acl(peer, dir2, ACL_CHDIR) == 0);          result = (check_acl(peer, dir2, ACL_CHDIR) == 0);
80    
81          if (result)          if (result)
82                  result = (chdir(dir) == 0);                  result = (chdir(dir) == 0);
83          freewrapper(dir2);          freewrapper(dir2);
84          return(result);          return (result);
85  }  }
86    
87  /* this needs explaining, send this function a pointer to nine '-' in a string ie "---------"  /* this needs explaining, send this function a pointer to nine '-' in a string ie "---------"
# Line 79  int checkchdir(FTPSTATE *peer, char *dir Line 89  int checkchdir(FTPSTATE *peer, char *dir
89     string, eg "-rw-r--r--" */     string, eg "-rw-r--r--" */
90    
91  /* this version was inspired by how GNU fileutils does it */  /* this version was inspired by how GNU fileutils does it */
92      
93  void convertperms(char *permstr, int mode)  void convertperms(char *permstr,
94                                      int mode)
95  {  {
96          int mcpy = mode;          int mcpy = mode;
97          int cnt;          int cnt;
98            
99          /* work out the 3 sets of rwx's */          /*
100                     * work out the 3 sets of rwx's
101          for(cnt = 6; cnt > -1; cnt -= 3)           */
102    
103            for (cnt = 6; cnt > -1; cnt -= 3)
104          {          {
105                  permstr[cnt+1] = (mcpy & S_IROTH) ? 'r' : '-';                  permstr[cnt + 1] = (mcpy & S_IROTH) ? 'r' : '-';
106                  permstr[cnt+2] = (mcpy & S_IWOTH) ? 'w' : '-';                  permstr[cnt + 2] = (mcpy & S_IWOTH) ? 'w' : '-';
107                  permstr[cnt+3] = (mcpy & S_IXOTH) ? 'x' : '-';                  permstr[cnt + 3] = (mcpy & S_IXOTH) ? 'x' : '-';
108                  mcpy = (mcpy >> 3);                  mcpy = (mcpy >> 3);
109          }          }
110    
111          /* work out special bits. Setuid the setgid the sticky bit */          /*
112                             * work out special bits. Setuid the setgid the sticky bit
113          if (mode & S_ISUID) permstr[3] = (mode & S_IXUSR) ? 's' : 'S';           */
114          if (mode & S_ISGID) permstr[6] = (mode & S_IXGRP) ? 's' : 'S';  
115          if (mode & S_ISVTX) permstr[9] = (mode & S_IXOTH) ? 't' : 'T';          if (mode & S_ISUID)
116                            permstr[3] = (mode & S_IXUSR) ? 's' : 'S';
117          /* check for regular files first, better performace! */          if (mode & S_ISGID)
118                    permstr[6] = (mode & S_IXGRP) ? 's' : 'S';
119            if (mode & S_ISVTX)
120                    permstr[9] = (mode & S_IXOTH) ? 't' : 'T';
121    
122            /*
123             * check for regular files first, better performace!
124             */
125          if (S_ISREG(mode))          if (S_ISREG(mode))
126                  permstr[0] = '-';                  permstr[0] = '-';
127          else if (S_ISLNK(mode))          else if (S_ISLNK(mode))
128                  permstr[0] = 'l';                  permstr[0] = 'l';
129          else if (S_ISDIR(mode))          else if (S_ISDIR(mode))
# Line 122  void convertperms(char *permstr, int mod Line 142  void convertperms(char *permstr, int mod
142                  permstr[0] = '?';                  permstr[0] = '?';
143  }  }
144    
145  char *file_expand(FTPSTATE *peer, char *filename)  char *file_expand(FTPSTATE * peer,
146                                      char *filename)
147  {  {
148          char *newfile = strdupwrapper(peer->pwd);          char *newfile = strdupwrapper(peer->pwd);
149    
150          dir_combine(peer, &newfile, filename);          dir_combine(peer, &newfile, filename);
151          return(newfile);          return (newfile);
152  }  }
153    
154  int file_isfdregularfile(int fd)  int file_isfdregularfile(int fd)
155  {  {
156          struct stat buf;          struct stat buf;
157            
158          if (fstat(fd, &buf) == 0)          if (fstat(fd, &buf) == 0)
159                  return(S_ISREG(buf.st_mode));                  return (S_ISREG(buf.st_mode));
160          else          else
161                  return(TRUE);           /* assume yes! */                  return (TRUE);                  /* assume yes! */
162  }  }
163    
164  int file_isfdadir(int fd)  int file_isfdadir(int fd)
165  {  {
166          struct stat buf;          struct stat buf;
167            
168          if (fstat(fd, &buf) == 0)          if (fstat(fd, &buf) == 0)
169                  return(S_ISDIR(buf.st_mode));                  return (S_ISDIR(buf.st_mode));
170          else          else
171                  return(TRUE);           /* assume yes, but there is no good reason fstat                  return (TRUE);                  /* assume yes, but there is no good reason fstat
172                                             won't work! */                                                                   * won't work! */
173  }  }
174    
175  /* opens a unique filename, in peers virtual space, returns the real name in  /* opens a unique filename, in peers virtual space, returns the real name in
176     rname for logging */     rname for logging */
177    
178  int file_ustoreopen(FTPSTATE *peer, char *infile, int *nounique, char **rname)  int file_ustoreopen(FTPSTATE * peer,
179                                            char *infile,
180                                            int *nounique,
181                                            char **rname)
182  {  {
183          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
184          int checknext = TRUE;          int checknext = TRUE;
185          int pos = 0;          int pos = 0;
186          int filefd = -1;          int filefd = -1;
187          int epos = strlen(filename);          int epos = strlen(filename);
188    
189          *nounique = FALSE;          *nounique = FALSE;
190          reallocwrapper(epos + 5, (void **)&filename);          reallocwrapper(epos + 5, (void **) &filename);
191    
192          if (check_acl(peer, filename, ACL_ADD) == 0)          if (check_acl(peer, filename, ACL_ADD) == 0)
193          {          {
194                  filefd = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666 & ~peer->umask);                  filefd =
195                            open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666 & ~peer->umask);
196                  checknext = ((filefd == -1) && (errno == EEXIST));                  checknext = ((filefd == -1) && (errno == EEXIST));
197          }          }
198            
199          while((checknext) && (pos < 1000))          while ((checknext) && (pos < 1000))
200          {          {
201                  filename[epos] = '.';                  filename[epos] = '.';
202                  filename[epos+1] = (pos / 100) + '0';                  filename[epos + 1] = (pos / 100) + '0';
203                  filename[epos+2] = (pos % 100) / 10 + '0';                  filename[epos + 2] = (pos % 100) / 10 + '0';
204                  filename[epos+3] = (pos % 10) + '0';                  filename[epos + 3] = (pos % 10) + '0';
205                  filename[epos+4] = 0;                  filename[epos + 4] = 0;
206                  pos++;                  pos++;
207                    
208                  if (check_acl(peer, filename, ACL_ADD) == 0)                  if (check_acl(peer, filename, ACL_ADD) == 0)
209                  {                  {
210                          filefd = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666 & ~peer->umask);                          filefd =
211                                    open(filename, O_CREAT | O_EXCL | O_WRONLY,
212                                             0666 & ~peer->umask);
213                          checknext = ((filefd == -1) && (errno == EEXIST));                          checknext = ((filefd == -1) && (errno == EEXIST));
214                  }                  }
215          }          }
# Line 190  int file_ustoreopen(FTPSTATE *peer, char Line 218  int file_ustoreopen(FTPSTATE *peer, char
218                  *nounique = TRUE;                  *nounique = TRUE;
219    
220          *rname = filename;          *rname = filename;
221          return(filefd);          return (filefd);
222  }  }
223    
224  /* opens a file for storing in peers virtual space, returns the real name for logging in rname */  /* opens a file for storing in peers virtual space, returns the real name for logging in rname */
225    
226  int file_storeopen(FTPSTATE *peer, char *infile, char **rname)  int file_storeopen(FTPSTATE * peer,
227                                       char *infile,
228                                       char **rname)
229  {  {
230          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
231          int newfd = -1;          int newfd = -1;
232          int openflags = FALSE;          int openflags = FALSE;
233          int canoverwrite = FALSE;          int canoverwrite = FALSE;
234          int canadd;          int canadd;
235            
236          canoverwrite = (check_acl(peer, filename, ACL_REPLACE) == 0);          canoverwrite = (check_acl(peer, filename, ACL_REPLACE) == 0);
237          canadd = (check_acl(peer, filename, ACL_ADD) == 0);          canadd = (check_acl(peer, filename, ACL_ADD) == 0);
238            
239          /* if the user can add files, then allow creation */          /*
240             * if the user can add files, then allow creation
241             */
242          if (canadd)          if (canadd)
243          {          {
244                  openflags |= O_CREAT;                  openflags |= O_CREAT;
245                  /* if the user cannot overwrite files */                  /*
246                     * if the user cannot overwrite files
247                     */
248                  if (!canoverwrite)                  if (!canoverwrite)
249                          openflags |= O_EXCL;                          openflags |= O_EXCL;
250          }          }
251    
252          /* try opening the file, or no-op if no acl perms available */          /*
253                     * try opening the file, or no-op if no acl perms available
254             */
255    
256          if (canoverwrite || canadd)          if (canoverwrite || canadd)
257                  newfd = open(filename, openflags | O_WRONLY, 0666 & ~peer->umask);                  newfd = open(filename, openflags | O_WRONLY, 0666 & ~peer->umask);
258          else          else
259                  errno = EACCES;                  errno = EACCES;
260            
261          /* now test it against device file access settings */          /*
262             * now test it against device file access settings
263             */
264          if ((errno == 0) && (!peer->accessdevices))          if ((errno == 0) && (!peer->accessdevices))
265                  if (!file_isfdregularfile(newfd))                  if (!file_isfdregularfile(newfd))
266                  {                  {
# Line 232  int file_storeopen(FTPSTATE *peer, char Line 270  int file_storeopen(FTPSTATE *peer, char
270                  }                  }
271    
272          *rname = filename;          *rname = filename;
273          return(newfd);          return (newfd);
274  }                                }
   
275    
276  int file_readopen(FTPSTATE *peer, char *infile, char **rname)  int file_readopen(FTPSTATE * peer,
277                                      char *infile,
278                                      char **rname)
279  {  {
280          int filefd = -1;          int filefd = -1;
281          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
282            
283          check_acl(peer, filename, ACL_READ);          check_acl(peer, filename, ACL_READ);
284            
285          if (errno == 0)          if (errno == 0)
286                  filefd = open(filename, O_RDONLY);                  filefd = open(filename, O_RDONLY);
287            
288          if (errno == 0)          if (errno == 0)
289                  if (file_isfdadir(filefd))                  if (file_isfdadir(filefd))
290                  {                  {
# Line 253  int file_readopen(FTPSTATE *peer, char * Line 292  int file_readopen(FTPSTATE *peer, char *
292                          errno = EISDIR;                          errno = EISDIR;
293                          filefd = -1;                          filefd = -1;
294                  }                  }
295                    
296          if ((errno == 0) && (!peer->accessdevices))          if ((errno == 0) && (!peer->accessdevices))
297                  if (!file_isfdregularfile(filefd))                  if (!file_isfdregularfile(filefd))
298                  {                  {
# Line 261  int file_readopen(FTPSTATE *peer, char * Line 300  int file_readopen(FTPSTATE *peer, char *
300                          errno = EACCES;                          errno = EACCES;
301                          filefd = -1;                          filefd = -1;
302                  }                  }
303            
304          *rname = filename;          *rname = filename;
305          return(filefd);          return (filefd);
306  }  }
307    
308  NEWFILE *file_nfopen(FTPSTATE *peer, char *filename)  NEWFILE *file_nfopen(FTPSTATE * peer,
309                                             char *filename)
310  {  {
311          char *rname;          char *rname;
312          int fd = file_readopen(peer, filename, &rname);          int fd = file_readopen(peer, filename, &rname);
313          NEWFILE *result = NULL;          NEWFILE *result = NULL;
314            
315          if (fd > 0)          if (fd > 0)
316                  result = nfdopen(fd);                  result = nfdopen(fd);
317            
318          freewrapper(rname);          freewrapper(rname);
319          return(result);          return (result);
320  }  }
321    
322  MYGLOBDATA *file_glob(FTPSTATE *peer, char *dir, char *pattern, int allfiles)  MYGLOBDATA *file_glob(FTPSTATE * peer,
323                                              char *dir,
324                                              char *pattern,
325                                              int allfiles)
326  {  {
327          int dirlen = strlen(dir);          int dirlen = strlen(dir);
328          MYGLOBDATA *mg = NULL;          MYGLOBDATA *mg = NULL;
329          char *pdir = mallocwrapper(dirlen + 2);          char *pdir = mallocwrapper(dirlen + 2);
330            
331          memcpy(pdir, dir, dirlen);          memcpy(pdir, dir, dirlen);
332          if (pdir[dirlen-1] == '/')          if (pdir[dirlen - 1] == '/')
333                  dirlen--;                  dirlen--;
334                    
335          pdir[dirlen] = '/';          pdir[dirlen] = '/';
336          pdir[dirlen+1] = 0;          pdir[dirlen + 1] = 0;
337            
338          check_acl(peer, pdir, ACL_LIST);          check_acl(peer, pdir, ACL_LIST);
339            
340          if (errno == 0)          if (errno == 0)
341                  mg = myglob(pdir, pattern, allfiles, TRUE);                  mg = myglob(pdir, pattern, allfiles, TRUE);
342            
343          freewrapper(pdir);          freewrapper(pdir);
344          return(mg);          return (mg);
345  }  }
346    
347  int file_unlink(FTPSTATE *peer, char *infile)  int file_unlink(FTPSTATE * peer,
348                                    char *infile)
349  {  {
350          int result = -1;          int result = -1;
351          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
352    
353          check_acl(peer, filename, ACL_DELETE);          check_acl(peer, filename, ACL_DELETE);
354            
355          if (errno == 0)          if (errno == 0)
356                  result = unlink(filename);                  result = unlink(filename);
357            
358          freewrapper(filename);          freewrapper(filename);
359          return(result);          return (result);
360  }  }
361    
362  /* there is a race here, where the user can get to overwrite a file if it created between  /* there is a race here, where the user can get to overwrite a file if it created between
363     checkfile and rename. It appears to be very difficult to prevent */     checkfile and rename. It appears to be very difficult to prevent */
364    
365  char *file_rename(FTPSTATE *peer, char *infile, char *infile2)  char *file_rename(FTPSTATE * peer,
366                                      char *infile,
367                                      char *infile2)
368  {  {
369          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
370          char *filename2 = file_expand(peer, infile2);          char *filename2 = file_expand(peer, infile2);
371          char *badfile = NULL;          char *badfile = NULL;
372            
373          if (checkfile(filename2))          if (checkfile(filename2))
374          {          {
375                  if (check_acl(peer, filename2, ACL_DELETE) == -1)                  if (check_acl(peer, filename2, ACL_DELETE) == -1)
376                          badfile = infile2;                          badfile = infile2;
377          }          }
378          else          else
379                  errno = 0;                  errno = 0;
380                    
381          if (errno == 0)          if (errno == 0)
382                  if (check_acl(peer, filename2, ACL_ADD) == -1)                  if (check_acl(peer, filename2, ACL_ADD) == -1)
383                          badfile = infile2;                          badfile = infile2;
384          if (errno == 0)          if (errno == 0)
385                  if (check_acl(peer, filename, ACL_DELETE) == -1)                  if (check_acl(peer, filename, ACL_DELETE) == -1)
386                          badfile = infile;                          badfile = infile;
387                    
388          if (errno == 0)          if (errno == 0)
389          {          {
390                  if (rename(filename, filename2) == -1)                  if (rename(filename, filename2) == -1)
391                          badfile = infile;                          badfile = infile;
392          }          }
393            
394          freewrapper(filename);          freewrapper(filename);
395          freewrapper(filename2);          freewrapper(filename2);
396          return(badfile);          return (badfile);
397  }  }
398    
399  int file_stat(FTPSTATE *peer, char *infile, struct stat *output)  int file_stat(FTPSTATE * peer,
400                              char *infile,
401                              struct stat *output)
402  {  {
403          int result = -1;          int result = -1;
404          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
405            
406          check_acl(peer, filename, ACL_READ);          check_acl(peer, filename, ACL_READ);
407            
408          if (errno == 0)          if (errno == 0)
409                  result = stat(filename, output);                  result = stat(filename, output);
410            
411          freewrapper(filename);          freewrapper(filename);
412          return(result);          return (result);
413  }  }
414    
415  int file_mkdir(FTPSTATE *peer, char *infile)  int file_mkdir(FTPSTATE * peer,
416                               char *infile)
417  {  {
418          int result = -1;          int result = -1;
419          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
420    
421          check_acl(peer, filename, ACL_MKDIR);          check_acl(peer, filename, ACL_MKDIR);
422            
423          if (errno == 0)          if (errno == 0)
424                  result = mkdir(filename, 0777 & ~peer->umask);                  result = mkdir(filename, 0777 & ~peer->umask);
425            
426          freewrapper(filename);          freewrapper(filename);
427          return(result);          return (result);
428  }  }
429    
430  int file_rmdir(FTPSTATE *peer, char *infile)  int file_rmdir(FTPSTATE * peer,
431                               char *infile)
432  {  {
433          int result = -1;          int result = -1;
434          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
435            
436          check_acl(peer, filename, ACL_RMDIR);          check_acl(peer, filename, ACL_RMDIR);
437            
438          if (errno == 0)          if (errno == 0)
439                  result = rmdir(filename);                  result = rmdir(filename);
440            
441          freewrapper(filename);          freewrapper(filename);
442          return(result);          return (result);
443  }  }
444    
445  int file_chmod(FTPSTATE *peer, char *infile, int mode)  int file_chmod(FTPSTATE * peer,
446                               char *infile,
447                               int mode)
448  {  {
449          int result = -1;          int result = -1;
450          char *filename = file_expand(peer, infile);          char *filename = file_expand(peer, infile);
451            
452          check_acl(peer, filename, ACL_CHMOD);          check_acl(peer, filename, ACL_CHMOD);
453            
454          if (errno == 0)          if (errno == 0)
455                  /* never allow sticky bit or setgid or setuid to be set */                  /*
456                     * never allow sticky bit or setgid or setuid to be set
457                     */
458                  result = chmod(filename, mode & 0777);                  result = chmod(filename, mode & 0777);
459            
460          freewrapper(filename);          freewrapper(filename);
461          return(result);          return (result);
462  }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.6.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26