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