source: abuse/tags/pd/macabuse/src/net/unix/fileman.c @ 49

Last change on this file since 49 was 49, checked in by Sam Hocevar, 11 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 11.3 KB
Line 
1#include "macs.hpp"
2
3#include "fileman.hpp"
4#include "netface.hpp"
5#include "ghandler.hpp"
6#include "dprint.hpp"
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <fcntl.h>
11#include <unistd.h>
12#include <string.h>
13#include <signal.h>
14
15extern net_protocol *prot;
16
17
18#if !defined( __WATCOMC__ ) && !defined( __MAC__ )
19#include <sys/stat.h>
20#endif
21
22#ifdef __MAC__
23extern char *macify_name(char *s);
24#endif
25
26file_manager *fman=NULL;
27
28file_manager::file_manager(int argc, char **argv, net_protocol *proto) : proto(proto)
29
30  default_fs=NULL;
31  no_security=0;
32  nfs_list=NULL;
33
34  int i;
35  for (i=1;i<argc;i++)
36    if (!strcmp(argv[i],"-bastard"))   // this bypasses filename security features
37    {
38      dprintf("Warning : Security measures bypassed (-bastard)\n");
39      no_security=1;
40    }
41}
42
43
44
45void file_manager::process_net()
46{
47  nfs_client *nc,*last=NULL;
48  for (nc=nfs_list;nc;)      // check for nfs request
49  {
50
51    int ok=1;
52
53    if (nc->sock->error())
54    {
55      ok=0;
56      //dprintf("Killing nfs client, socket went bad\n");
57    }
58    else if (nc->size_to_read && nc->sock->ready_to_write())
59      ok=nc->send_read();
60    else if (nc->sock->ready_to_read())
61      ok=process_nfs_command(nc);    // if we couldn't process the packeted, delete the connection
62   
63    if (ok)
64    {
65      last=nc;
66      nc=nc->next;
67    } else
68    {
69      if (last) last->next=nc->next;
70      else nfs_list=nc->next;
71      nfs_client *c=nc;
72      nc=nc->next;
73      delete c;
74    }
75  }
76}
77
78
79int file_manager::process_nfs_command(nfs_client *c)
80{
81  char cmd;
82  if (c->sock->read(&cmd,1)!=1) return 0;
83  switch (cmd)
84  {
85    case NFCMD_READ :
86    {
87      long size;
88      if (c->sock->read(&size,sizeof(size))!=sizeof(size)) return 0;
89      size=lltl(size);
90
91      c->size_to_read=size;
92      return c->send_read();
93    } break;
94    case NFCMD_CLOSE :
95    {
96      return 0;
97    } break;
98    case NFCMD_SEEK :
99    {
100      long offset;
101      if (c->sock->read(&offset,sizeof(offset))!=sizeof(offset)) return 0;
102      offset=lltl(offset);
103      offset=lseek(c->file_fd,offset,0);
104      offset=lltl(offset);
105      if (c->sock->write(&offset,sizeof(offset))!=sizeof(offset)) return 0;
106      return 1;
107    } break;
108    case NFCMD_TELL :
109    {
110      long offset=lseek(c->file_fd,0,SEEK_CUR);
111      offset=lltl(offset);
112      if (c->sock->write(&offset,sizeof(offset))!=sizeof(offset)) return 0;
113      return 1;
114    } break;
115   
116    default :
117    {
118        dprintf("net driver : bad command from nfs client\n");
119      return 0;
120    }
121  }
122}
123
124int file_manager::nfs_client::send_read()   // return 0 if failure on socket, not failure to read
125{
126  if (file_fd>=0 && sock)
127  {
128    // first make sure the socket isn't 'full'
129    if (sock->ready_to_write())
130    {
131      char buf[READ_PACKET_SIZE];   
132      short read_total;
133      short actual;
134
135      do
136      {     
137                                read_total=size_to_read>(READ_PACKET_SIZE-2) ? (READ_PACKET_SIZE-2) : size_to_read;
138                       
139                                actual=read(file_fd,buf+2,read_total);
140                                *((ushort *)buf)=lstl(actual);
141                       
142                                int write_amount=sock->write(buf,actual+2);
143                                if (write_amount!=actual+2)
144                                {
145                                  dprintf("write failed\n");
146                                  return 0;
147                                }
148                       
149                                size_to_read-=actual;
150                       
151                                if (!sock->ready_to_write())
152                                {
153                                  sock->read_unselectable();
154                                  sock->write_selectable();
155                                  return 1;    // not ok to write anymore, try again latter
156                                }
157
158      } while (size_to_read && actual==read_total);
159
160      sock->read_selectable();
161      sock->write_unselectable();
162
163      size_to_read=0;
164      return 1;
165    } else
166    {
167      sock->read_unselectable();
168      sock->write_selectable();
169      return 1;
170    }
171  }
172  return 0;
173}
174
175
176void file_manager::secure_filename(char *filename, char *mode)
177{
178  if (!no_security)
179  {   
180    if (filename[0]=='/') { filename[0]=0; return ; }
181    int level=0;
182    char *f=filename;
183    while (*f)
184    {
185      if (*f=='/') { f++; level++; }
186      else if (*f=='.' && f[1]=='.')
187      {
188        if (f[3]=='.') while (*f!='.') f++;
189        else
190        {
191          f+=2;
192          level--;
193        }
194      } else f++;
195     
196    }
197    if (level<0)
198      filename[0]=0;
199  }
200}
201
202
203
204
205file_manager::nfs_client::nfs_client(net_socket *sock, int file_fd, nfs_client *next) :
206  sock(sock),file_fd(file_fd),next(next),size_to_read(0)
207{
208  sock->read_selectable();
209
210
211
212file_manager::nfs_client::~nfs_client()
213{
214  delete sock;
215  if (file_fd>=0)
216    close(file_fd);
217}
218
219
220void file_manager::add_nfs_client(net_socket *sock)
221{
222  uchar size[2];
223  char filename[300],mode[20],*mp;
224  if (sock->read(size,2)!=2) { delete sock; return ; }
225  if (sock->read(filename,size[0])!=size[0]) { delete sock; return ; }
226  if (sock->read(mode,size[1])!=size[1]) { delete sock; return ; }
227 
228
229  secure_filename(filename,mode);  // make sure this filename isn't a security risk
230  if (filename[0]==0) { dprintf("(denied)\n"); delete sock; return ; }
231
232  mp=mode;
233  int flags=0;
234
235#ifdef __WATCOMC__
236    flags|=O_BINARY;
237#endif
238
239  while (*mp)
240  {
241    if (*mp=='w') flags|=O_CREAT|O_RDWR;
242    else if (*mp=='r') flags|=O_RDONLY;
243    mp++;
244  }
245
246#ifdef __MAC__
247  int f=open(macify_name(filename),flags);
248#else     
249  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
250#endif
251
252  FILE *fp=fopen("open.log","ab");
253  fprintf(fp,"open file %s, fd=%d\n",filename,f);
254  fclose(fp);
255 
256  if (f<0)
257    f=-1;  // make sure this is -1
258
259
260  long ret=lltl(f);
261  if (sock->write(&ret,sizeof(ret))!=sizeof(ret)) { delete sock; return ; }
262
263  if (f<0)    // no file, sorry
264    delete sock;
265  else
266  {
267    long cur_pos=lseek(f,0,SEEK_CUR);
268    long size=lseek(f,0,SEEK_END);
269    lseek(f,cur_pos,SEEK_SET);
270    size=lltl(size);
271    if (sock->write(&size,sizeof(size))!=sizeof(size)) {  close(f); delete sock; sock=NULL; return ; }
272
273    nfs_list=new nfs_client(sock,f,nfs_list);
274    nfs_list->size=size;
275  }
276}
277
278
279
280void file_manager::remote_file::r_close(char *reason)
281{
282  if (reason) dprintf("remote_file : %s\n",reason);
283
284  if (sock)
285  {
286    delete sock;
287    sock=NULL;
288  }
289
290}
291
292file_manager::remote_file::remote_file(net_socket *sock, char *filename, char *mode, remote_file *Next) : sock(sock)
293{
294  next=Next;
295  open_local=0;
296
297  uchar sizes[3]={CLIENT_NFS,strlen(filename)+1,strlen(mode)+1};
298  if (sock->write(sizes,3)!=3) { r_close("could not send open info"); return ; }
299  if (sock->write(filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; }
300  if (sock->write(mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; }
301
302  long remote_file_fd;
303  if (sock->read(&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd))
304  { r_close("could not read remote fd"); return ; }   
305  remote_file_fd=lltl(remote_file_fd);
306  if (remote_file_fd<0) { r_close("remote fd is bad"); return ; }
307
308  if (sock->read(&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; }
309
310  size=lltl(size);
311}
312
313int file_manager::remote_file::unbuffered_read(void *buffer, size_t count)
314{
315  if (sock && count)
316  {
317    uchar cmd=NFCMD_READ;
318    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("read : could not send command"); return 0; }
319
320    long rsize=lltl(count);
321    if (sock->write(&rsize,sizeof(rsize))!=sizeof(rsize)) { r_close("read : could not send size"); return 0; }
322
323    long total_read=0,total;
324    char buf[READ_PACKET_SIZE];
325    ushort size;
326
327    ushort packet_size;   
328    do
329    {
330      if (sock->read(&packet_size,sizeof(packet_size))!=sizeof(packet_size))
331      {
332                                dprintf("could not read packet size\n");
333                                return 0;
334      }
335
336      packet_size=lstl(packet_size);
337
338      ushort size_read=sock->read(buf,packet_size);
339
340      if (size_read!=packet_size)
341      {
342                                if (sock->read(buf+2+size_read,packet_size-size_read)!=packet_size-size_read)
343                                {
344                                  dprintf("incomplete packet\n");
345                                  return 0;
346                                }
347      }
348
349      memcpy(buffer,buf,packet_size);
350      buffer=(void *)(((char *)buffer)+packet_size);
351
352      total_read+=packet_size;
353      count-=packet_size;
354    } while (packet_size==READ_PACKET_SIZE-2 && count);     
355    return total_read;
356  }
357  return 0;
358}
359
360long file_manager::remote_file::unbuffered_tell()   // ask server where the offset of the file pointer is
361{
362  if (sock)
363  {
364    uchar cmd=NFCMD_TELL;
365    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; }
366
367    long offset;
368    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; }   
369    return lltl(offset);
370  }   
371  return 0;
372}
373
374long file_manager::remote_file::unbuffered_seek(long offset)  // tell server to seek to a spot in a file
375{
376  if (sock)
377  {
378    uchar cmd=NFCMD_SEEK;
379    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; }
380
381    long off=lltl(offset);
382    if (sock->write(&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; }
383
384    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; }   
385    return lltl(offset);
386  }   
387  return 0;
388}
389
390
391file_manager::remote_file::~remote_file()
392{ r_close(NULL); }
393
394int file_manager::rf_open_file(char *&filename, char *mode)
395{
396  net_address *fs_server_addr=NULL;
397
398  if (filename[0]=='/' && filename[1]=='/')   // passive server file reference?
399  {
400    filename+=2;
401
402    fs_server_addr=prot->get_node_address(filename,DEFAULT_COMM_PORT,0);
403    if (!fs_server_addr)
404    {
405      dprintf("couldn not get address for %s\n",filename);
406      return -1;
407    }
408  } else if (default_fs)
409    fs_server_addr=default_fs->copy();
410 
411  if (fs_server_addr)
412  {
413    net_socket *sock=proto->connect_to_server(fs_server_addr,net_socket::SOCKET_SECURE);
414    delete fs_server_addr;
415
416    if (!sock)
417    {
418      dprintf("unable to connect\n");
419      return -1;
420    }
421
422    remote_file *rf=new remote_file(sock,filename,mode,remote_list);
423    if (rf->open_failure())
424    {
425      delete rf;
426      return -1;
427    }
428    else
429    {
430      remote_list=rf;
431      return rf->sock->get_fd();
432    }     
433  }
434
435  secure_filename(filename,mode);
436  if (filename[0]==0) return -1;
437
438  int flags=0;
439  while (*mode)
440  {
441    if (*mode=='w') flags|=O_CREAT|O_RDWR;
442    else if (*mode=='r') flags|=O_RDONLY;
443    mode++;
444  }
445
446#ifdef __MAC__
447  int f=open(macify_name(filename),flags);
448#else
449  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
450#endif
451  if (f>=0)
452  { close(f);
453    return -2;
454  }
455 
456  return -1;
457}
458
459
460file_manager::remote_file *file_manager::find_rf(int fd)
461{
462  remote_file *r=remote_list;
463  for (;r && r->sock->get_fd()!=fd;r=r->next)
464  {
465    if (r->sock->get_fd()==-1)
466    {
467      dprintf("bad sock\n");
468    }
469  }
470  if (!r) { dprintf("Bad fd for remote file %d\n",fd); }
471  return r;
472}
473
474
475long file_manager::rf_tell(int fd)
476{
477  remote_file *rf=find_rf(fd);
478  if (rf) return rf->unbuffered_tell();
479  else return 0;
480}
481
482long file_manager::rf_seek(int fd, long offset)
483{
484  remote_file *rf=find_rf(fd);
485  if (rf) return rf->unbuffered_seek(offset);
486  else return 0;
487}
488
489int file_manager::rf_read(int fd, void *buffer, size_t count)
490{
491  remote_file *rf=find_rf(fd);
492  if (rf) return rf->unbuffered_read(buffer,count);
493  else return 0;
494}
495
496int file_manager::rf_close(int fd)
497{
498  remote_file *rf=remote_list,*last=NULL;
499  while (rf && rf->sock->get_fd()!=fd) rf=rf->next;
500  if (rf)
501  {
502    if (last) last->next=rf->next;
503    else remote_list=rf->next;
504    delete rf;
505    return 1;
506  } else
507  {
508    dprintf("Bad fd for remote file %d\n",fd);
509    return 0;
510  } 
511}
512
513long file_manager::rf_file_size(int fd)
514{
515  remote_file *rf=find_rf(fd);
516  if (rf) return rf->file_size();
517  else return 0;
518}
Note: See TracBrowser for help on using the repository browser.