Pol  Revision:cb584c9
filemod.cpp
Go to the documentation of this file.
1 
12 #include <cerrno>
13 #include <ctime>
14 #include <iosfwd>
15 #include <string>
16 
17 #include "../../bscript/berror.h"
18 #include "../../bscript/bobject.h"
19 #include "../../bscript/impstr.h"
20 #include "../../clib/cfgelem.h"
21 #include "../../clib/cfgfile.h"
22 #include "../../clib/clib.h"
23 #include "../../clib/dirlist.h"
24 #include "../../clib/fileutil.h"
25 #include "../../clib/logfacility.h"
26 #include "../../plib/pkg.h"
27 #include "../binaryfilescrobj.h"
28 #include "../core.h"
29 #include "../globals/ucfg.h"
30 #include "../xmlfilescrobj.h"
31 #include "fileaccess.h"
32 #include "filemod.h"
33 
34 namespace Pol
35 {
36 namespace Bscript
37 {
38 using namespace Module;
39 template <>
51  {"CreateXMLFile", &FileAccessExecutorModule::mf_CreateXMLFile}};
52 }
53 namespace Module
54 {
55 using namespace Bscript;
56 
113  : AllowWrite( elem.remove_bool( "AllowWrite", false ) ),
114  AllowAppend( elem.remove_bool( "AllowAppend", false ) ),
115  AllowRead( elem.remove_bool( "AllowRead", false ) ),
116  AllowRemote( elem.remove_bool( "AllowRemote", false ) ),
117  AllPackages( false ),
118  AllDirectories( false ),
119  AllExtensions( false )
120 {
121  std::string tmp;
122  while ( elem.remove_prop( "Package", &tmp ) )
123  {
124  if ( tmp == "*" )
125  AllPackages = true;
126  else
127  {
128  auto pkg = Plib::find_package( tmp );
129  if ( pkg == nullptr )
130  ERROR_PRINT << "Fileaccess package entry not found: " << tmp << "\n";
131  else
132  Packages.insert( pkg );
133  }
134  while ( elem.remove_prop( "Directory", &tmp ) )
135  {
136  if ( tmp == "*" )
137  AllDirectories = true;
138  else
139  {
140  const Plib::Package* cfgpkg;
141  std::string cfgpath;
142  if ( pkgdef_split( tmp, nullptr, &cfgpkg, &cfgpath ) )
143  Directories.push_back( std::make_pair( cfgpkg, cfgpath ) );
144  else
145  ERROR_PRINT << "Invalid fileaccess Directory entry: " << tmp << "\n";
146  }
147  }
148  if ( Directories.empty() )
149  AllDirectories = true;
150  while ( elem.remove_prop( "Extension", &tmp ) )
151  {
152  if ( tmp == "*" )
153  AllExtensions = true;
154  else
155  Extensions.push_back( tmp );
156  }
157  }
158 }
159 bool FileAccess::AllowsAccessTo( const Plib::Package* pkg, const Plib::Package* filepackage ) const
160 {
161  if ( AllowRemote )
162  return true;
163 
164  if ( pkg == filepackage )
165  return true;
166 
167  return false;
168 }
169 
171 {
172  if ( AllPackages )
173  return true;
174 
175  if ( pkg == nullptr )
176  return false;
177 
178  if ( Packages.count( pkg ) )
179  return true;
180 
181  return false;
182 }
183 
184 bool FileAccess::AppliesToPath( const std::string& path, const Plib::Package* filepkg ) const
185 {
186  if ( !AllDirectories )
187  {
188  std::string filepath = path;
189  if ( Clib::strip_one( filepath ) != 0 )
190  filepath = "";
191 
192  bool found( false );
193  for ( const auto& dir : Directories )
194  {
195  const auto& cfgpkg = dir.first;
196  const auto& cfgpath = dir.second;
197  if ( cfgpkg == filepkg )
198  {
199  if ( filepath.size() < cfgpath.size() )
200  {
201  found = false;
202  continue;
203  }
204  found = true;
205  for ( size_t i = 0; i < filepath.size() && i < cfgpath.size(); ++i )
206  {
207  if ( filepath[i] != cfgpath[i] )
208  {
209  found = false;
210  break;
211  }
212  }
213  if ( found )
214  break;
215  }
216  }
217  if ( !found )
218  return false;
219  }
220  if ( AllExtensions )
221  return true;
222 
223  // check for weirdness in the path
224  if ( path.find( '\0' ) != std::string::npos )
225  return false;
226  if ( path.find( ".." ) != std::string::npos )
227  return false;
228  for ( const auto& ext : Extensions )
229  {
230  if ( path.size() >= ext.size() )
231  {
232  std::string path_ext = path.substr( path.size() - ext.size() );
233  if ( Clib::stringicmp( path_ext, ext ) == 0 )
234  {
235  return true;
236  }
237  }
238  }
239  return false;
240 }
241 
243 {
244  size_t size = sizeof( FileAccess );
245  size += Packages.size() * ( sizeof( void* ) + 3 * sizeof( void* ) );
246 
247  for ( const auto& d : Directories )
248  size += sizeof( decltype( Directories )::value_type ) + d.second.capacity();
249  for ( const auto& e : Extensions )
250  size += e.capacity();
251  return size;
252 }
253 
254 bool HasReadAccess( const Plib::Package* pkg, const Plib::Package* filepackage,
255  const std::string& path )
256 {
257  for ( const auto& fa : Core::configurationbuffer.file_access_rules )
258  {
259  if ( fa.AllowRead && fa.AllowsAccessTo( pkg, filepackage ) && fa.AppliesToPackage( pkg ) &&
260  fa.AppliesToPath( path, filepackage ) )
261  {
262  return true;
263  }
264  }
265  return false;
266 }
267 bool HasWriteAccess( const Plib::Package* pkg, const Plib::Package* filepackage,
268  const std::string& path )
269 {
270  for ( const auto& fa : Core::configurationbuffer.file_access_rules )
271  {
272  if ( fa.AllowWrite && fa.AllowsAccessTo( pkg, filepackage ) && fa.AppliesToPackage( pkg ) &&
273  fa.AppliesToPath( path, filepackage ) )
274  {
275  return true;
276  }
277  }
278  return false;
279 }
280 bool HasAppendAccess( const Plib::Package* pkg, const Plib::Package* filepackage,
281  const std::string& path )
282 {
283  for ( const auto& fa : Core::configurationbuffer.file_access_rules )
284  {
285  if ( fa.AllowAppend && fa.AllowsAccessTo( pkg, filepackage ) && fa.AppliesToPackage( pkg ) &&
286  fa.AppliesToPath( path, filepackage ) )
287  {
288  return true;
289  }
290  }
291  return false;
292 }
293 
296 {
297 }
298 
300 {
301  return new FileAccessExecutorModule( exec );
302 }
303 
305 {
306  const String* filename;
307  if ( !getStringParam( 0, filename ) )
308  return new BError( "Invalid parameter type." );
309 
310  const Plib::Package* outpkg;
311  std::string path;
312  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
313  return new BError( "Error in filename descriptor." );
314 
315  if ( path.find( ".." ) != std::string::npos )
316  return new BError( "No parent path traversal allowed." );
317 
318  std::string filepath;
319  if ( outpkg == nullptr )
320  filepath = path;
321  else
322  filepath = outpkg->dir() + path;
323 
324  return new BLong( Clib::FileExists( filepath ) );
325 }
326 
328 {
329  const String* filename;
330  if ( !getStringParam( 0, filename ) )
331  return new BError( "Invalid parameter type" );
332 
333  const Plib::Package* outpkg;
334  std::string path;
335  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
336  return new BError( "Error in filename descriptor" );
337 
338  if ( path.find( ".." ) != std::string::npos )
339  return new BError( "No parent path traversal please." );
340 
341  if ( !HasReadAccess( exec.prog()->pkg, outpkg, path ) )
342  return new BError( "Access denied" );
343 
344  std::string filepath;
345  if ( outpkg == nullptr )
346  filepath = path;
347  else
348  filepath = outpkg->dir() + path;
349 
350  std::ifstream ifs( filepath.c_str() );
351  if ( !ifs.is_open() )
352  return new BError( "File not found: " + filepath );
353 
354  std::unique_ptr<Bscript::ObjArray> arr( new Bscript::ObjArray() );
355 
356  std::string line;
357  while ( getline( ifs, line ) )
358  arr->addElement( new String( line ) );
359 
360  return arr.release();
361 }
362 
364 {
365  const String* filename;
366  Bscript::ObjArray* contents;
367  if ( !getStringParam( 0, filename ) || !getObjArrayParam( 1, contents ) )
368  {
369  return new BError( "Invalid parameter type" );
370  }
371  const Plib::Package* outpkg;
372  std::string path;
373  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
374  return new BError( "Error in filename descriptor" );
375 
376  if ( path.find( ".." ) != std::string::npos )
377  return new BError( "No parent path traversal please." );
378  if ( !HasWriteAccess( exec.prog()->pkg, outpkg, path ) )
379  return new BError( "Access denied" );
380 
381  std::string filepath;
382  if ( outpkg == nullptr )
383  filepath = path;
384  else
385  filepath = outpkg->dir() + path;
386 
387  std::string bakpath = filepath + ".bak";
388  std::string tmppath = filepath + ".tmp";
389 
390  std::ofstream ofs( tmppath.c_str(), std::ios::out | std::ios::trunc );
391 
392  if ( !ofs.is_open() )
393  return new BError( "File not found: " + filepath );
394 
395  for ( unsigned i = 0; i < contents->ref_arr.size(); ++i )
396  {
397  BObjectRef& ref = contents->ref_arr[i];
398  BObject* obj = ref.get();
399  if ( obj != nullptr )
400  {
401  ofs << ( *obj )->getStringRep();
402  }
403  ofs << std::endl;
404  }
405  if ( ofs.fail() )
406  return new BError( "Error during write." );
407  ofs.close();
408 
409  if ( Clib::FileExists( bakpath ) )
410  {
411  if ( unlink( bakpath.c_str() ) )
412  {
413  int err = errno;
414  std::string message = "Unable to remove " + filepath + ": " + strerror( err );
415 
416  return new BError( message );
417  }
418  }
419  if ( Clib::FileExists( filepath ) )
420  {
421  if ( rename( filepath.c_str(), bakpath.c_str() ) )
422  {
423  int err = errno;
424  std::string message =
425  "Unable to rename " + filepath + " to " + bakpath + ": " + strerror( err );
426  return new BError( message );
427  }
428  }
429  if ( rename( tmppath.c_str(), filepath.c_str() ) )
430  {
431  int err = errno;
432  std::string message =
433  "Unable to rename " + tmppath + " to " + filepath + ": " + strerror( err );
434  return new BError( message );
435  }
436 
437  return new BLong( 1 );
438 }
439 
441 {
442  const String* filename;
443  ObjArray* contents;
444  if ( !getStringParam( 0, filename ) || !getObjArrayParam( 1, contents ) )
445  {
446  return new BError( "Invalid parameter type" );
447  }
448 
449  const Plib::Package* outpkg;
450  std::string path;
451  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
452  return new BError( "Error in filename descriptor" );
453 
454  if ( path.find( ".." ) != std::string::npos )
455  return new BError( "No parent path traversal please." );
456 
457  if ( !HasAppendAccess( exec.prog()->pkg, outpkg, path ) )
458  return new BError( "Access denied" );
459 
460  std::string filepath;
461  if ( outpkg == nullptr )
462  filepath = path;
463  else
464  filepath = outpkg->dir() + path;
465 
466  std::ofstream ofs( filepath.c_str(), std::ios::out | std::ios::app );
467 
468  if ( !ofs.is_open() )
469  return new BError( "Unable to open file: " + filepath );
470 
471  for ( unsigned i = 0; i < contents->ref_arr.size(); ++i )
472  {
473  BObjectRef& ref = contents->ref_arr[i];
474  BObject* obj = ref.get();
475  if ( obj != nullptr )
476  {
477  ofs << ( *obj )->getStringRep();
478  }
479  ofs << std::endl;
480  }
481  if ( ofs.fail() )
482  return new BError( "Error during write." );
483 
484  return new BLong( 1 );
485 }
486 
488 { //
489  const String* filename;
490  const String* textline;
491  if ( getStringParam( 0, filename ) && getStringParam( 1, textline ) )
492  {
493  int flags;
494  if ( exec.fparams.size() >= 3 )
495  {
496  if ( !getParam( 2, flags ) )
497  return new BError( "Invalid parameter type" );
498  }
499  else
500  {
501  flags = 0;
502  }
503 
504  const Plib::Package* outpkg;
505  std::string path;
506  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
507  return new BError( "Error in filename descriptor" );
508 
509  if ( path.find( ".." ) != std::string::npos )
510  return new BError( "No parent path traversal please." );
511 
512  if ( !HasAppendAccess( exec.prog()->pkg, outpkg, path ) )
513  return new BError( "Access denied" );
514 
515  std::string filepath;
516  if ( outpkg == nullptr )
517  filepath = path;
518  else
519  filepath = outpkg->dir() + path;
520 
521  std::ofstream ofs( filepath.c_str(), std::ios::out | std::ios::app );
522 
523  if ( !ofs.is_open() )
524  return new BError( "Unable to open file: " + filepath );
525 
526  if ( flags & Core::LOG_DATETIME )
527  {
528  auto time_tm = Clib::localtime( time( nullptr ) );
529 
530  char buffer[30];
531  if ( strftime( buffer, sizeof buffer, "%m/%d %H:%M:%S", &time_tm ) > 0 )
532  ofs << "[" << buffer << "] ";
533  }
534 
535  ofs << textline->value() << std::endl;
536 
537  if ( ofs.fail() )
538  return new BError( "Error during write." );
539 
540  return new BLong( 1 );
541  }
542  else
543  return new BError( "Invalid parameter type" );
544 }
545 
547 {
548  const String* filename;
549  unsigned short mode, bigendian;
550  if ( ( !getStringParam( 0, filename ) ) || ( !getParam( 1, mode ) ) ||
551  ( !getParam( 2, bigendian ) ) )
552  return new BError( "Invalid parameter type" );
553 
554  const Plib::Package* outpkg;
555  std::string path;
556  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
557  return new BError( "Error in filename descriptor" );
558 
559  if ( path.find( ".." ) != std::string::npos )
560  return new BError( "No parent path traversal please." );
561 
562  if ( mode & 0x01 )
563  {
564  if ( !HasReadAccess( exec.prog()->pkg, outpkg, path ) )
565  return new BError( "Access denied" );
566  }
567  if ( mode & 0x02 )
568  {
569  if ( !HasWriteAccess( exec.prog()->pkg, outpkg, path ) )
570  return new BError( "Access denied" );
571  }
572 
573  std::string filepath;
574  if ( outpkg == nullptr )
575  filepath = path;
576  else
577  filepath = outpkg->dir() + path;
578 
579  return new Core::BBinaryfile( filepath, mode, bigendian == 1 ? true : false );
580 }
581 
583 {
584  const String* dirname;
585  if ( !getStringParam( 0, dirname ) )
586  return new BError( "Invalid parameter type" );
587 
588  const Plib::Package* outpkg;
589  std::string path;
590  if ( !pkgdef_split( dirname->value(), exec.prog()->pkg, &outpkg, &path ) )
591  return new BError( "Error in dirname descriptor" );
592  if ( path.find( ".." ) != std::string::npos )
593  return new BError( "No parent path traversal please." );
594 
595  if ( outpkg != nullptr )
596  path = outpkg->dir() + path;
597  path = Clib::normalized_dir_form( path );
598  if ( Clib::IsDirectory( path.c_str() ) )
599  return new BError( "Directory already exists." );
600  int res = Clib::make_dir( path.c_str() );
601  if ( res != 0 )
602  return new BError( "Could not create directory." );
603  return new BLong( 1 );
604 }
605 
607 {
608  const String* dirname;
609  const String* extension;
610  short listdirs;
611  if ( ( !getStringParam( 0, dirname ) ) || ( !getStringParam( 1, extension ) ) ||
612  ( !getParam( 2, listdirs ) ) )
613  return new BError( "Invalid parameter type" );
614 
615  const Plib::Package* outpkg;
616  std::string path;
617  if ( !pkgdef_split( dirname->value(), exec.prog()->pkg, &outpkg, &path ) )
618  return new BError( "Error in dirname descriptor" );
619  if ( path.find( ".." ) != std::string::npos )
620  return new BError( "No parent path traversal please." );
621 
622  if ( outpkg != nullptr )
623  path = outpkg->dir() + path;
624  path = Clib::normalized_dir_form( path );
625  if ( !Clib::IsDirectory( path.c_str() ) )
626  return new BError( "Directory not found." );
627  bool asterisk = false;
628  bool nofiles = false;
629  if ( extension->getStringRep().find( '*', 0 ) != std::string::npos )
630  asterisk = true;
631  else if ( extension->length() == 0 )
632  nofiles = true;
633 
635 
636  for ( Clib::DirList dl( path.c_str() ); !dl.at_end(); dl.next() )
637  {
638  std::string name = dl.name();
639  if ( name[0] == '.' )
640  continue;
641 
642  if ( Clib::IsDirectory( ( path + name ).c_str() ) )
643  {
644  if ( listdirs == 0 )
645  continue;
646  }
647  else if ( nofiles )
648  continue;
649  else if ( !asterisk )
650  {
651  std::string::size_type extensionPointPos = name.rfind( '.' );
652  if ( extensionPointPos == std::string::npos )
653  continue;
654  if ( name.substr( extensionPointPos + 1 ) != extension->value() )
655  continue;
656  }
657 
658  arr->addElement( new String( name ) );
659  }
660 
661  return arr;
662 }
663 
665 {
666  const String* filename;
667  if ( !getStringParam( 0, filename ) )
668  return new BError( "Invalid parameter type" );
669 
670  const Plib::Package* outpkg;
671  std::string path;
672  if ( !pkgdef_split( filename->value(), exec.prog()->pkg, &outpkg, &path ) )
673  return new BError( "Error in filename descriptor" );
674 
675  if ( path.find( ".." ) != std::string::npos )
676  return new BError( "No parent path traversal please." );
677 
678  if ( !HasReadAccess( exec.prog()->pkg, outpkg, path ) )
679  return new BError( "Access denied" );
680 
681  std::string filepath;
682  if ( outpkg == nullptr )
683  filepath = path;
684  else
685  filepath = outpkg->dir() + path;
686 
687  return new Core::BXMLfile( filepath );
688 }
689 
691 {
692  return new Core::BXMLfile();
693 }
694 
696 {
698 
699  if ( !Clib::FileExists( "config/fileaccess.cfg" ) )
700  return;
701 
702  Clib::ConfigFile cf( "config/fileaccess.cfg", "FileAccess" );
703  Clib::ConfigElem elem;
704 
705 
706  while ( cf.read( elem ) )
707  {
708  FileAccess fa( elem );
710  }
711 }
712 }
713 }
bool AppliesToPackage(const Plib::Package *pkg) const
Definition: filemod.cpp:170
bool HasWriteAccess(const Plib::Package *pkg, const Plib::Package *filepackage, const std::string &path)
Definition: filemod.cpp:267
Bscript::BObjectImp * mf_OpenXMLFile()
Definition: filemod.cpp:664
const EScriptProgram * prog() const
Definition: executor.h:423
const std::string & value() const
Definition: impstr.h:67
Bscript::BObjectImp * mf_CreateXMLFile()
Definition: filemod.cpp:690
int strip_one(std::string &direc)
Definition: fileutil.cpp:71
std::vector< std::string > Extensions
Definition: fileaccess.h:50
T * get() const
Definition: refptr.h:176
std::tm localtime(const std::time_t &t)
threadsafe version of localtime
Definition: clib.h:143
bool getParam(unsigned param, int &value)
Definition: execmodl.cpp:62
Bscript::BObjectImp * mf_LogToFile()
Definition: filemod.cpp:487
FileAccessExecutorModule(Bscript::Executor &exec)
Definition: filemod.cpp:294
virtual std::string getStringRep() const POL_OVERRIDE
Definition: impstr.h:129
std::vector< Module::FileAccess > file_access_rules
Definition: ucfg.h:52
bool at_end() const
Definition: dirlist.cpp:102
Bscript::BObjectImp * mf_CreateDirectory()
Definition: filemod.cpp:582
Package * find_package(const std::string &pkgname)
Definition: pkg.cpp:33
bool AllowsAccessTo(const Plib::Package *pkg, const Plib::Package *filepackage) const
Definition: filemod.cpp:159
unsigned char buffer[10000]
Definition: UoToolMain.cpp:109
bool pkgdef_split(const std::string &spec, const Package *inpkg, const Package **outpkg, std::string *path)
Definition: pkg.cpp:410
bool IsDirectory(const char *dir)
Definition: fileutil.cpp:51
Bscript::BObjectImp * mf_WriteFile()
Definition: filemod.cpp:363
std::vector< BObjectRef > fparams
Definition: executor.h:133
ConfigurationBuffer configurationbuffer
Definition: ucfg.cpp:13
bool HasAppendAccess(const Plib::Package *pkg, const Plib::Package *filepackage, const std::string &path)
Definition: filemod.cpp:280
void load_fileaccess_cfg()
Definition: filemod.cpp:695
Bscript::BObjectImp * mf_FileExists()
Definition: filemod.cpp:304
std::set< const Plib::Package * > Packages
Definition: fileaccess.h:48
Bscript::BObjectImp * mf_OpenBinaryFile()
Definition: filemod.cpp:546
const String * getStringParam(unsigned param)
Definition: execmodl.cpp:36
size_t estimateSize() const
Definition: filemod.cpp:242
bool AppliesToPath(const std::string &path, const Plib::Package *filepkg) const
Definition: filemod.cpp:184
Bscript::BObjectImp * mf_AppendToFile()
Definition: filemod.cpp:440
FileAccess(Clib::ConfigElem &elem)
Definition: filemod.cpp:112
std::vector< std::pair< const Plib::Package *, std::string > > Directories
Definition: fileaccess.h:49
bool remove_prop(const char *propname, std::string *value)
Definition: cfgfile.cpp:128
int stringicmp(const S1 &str1, const S2 &str2)
Definition: stlutil.h:46
void addElement(BObjectImp *imp)
Definition: object.cpp:1399
Plib::Package const * pkg
Definition: eprog.h:123
Bscript::BObjectImp * mf_ListDirectory()
Definition: filemod.cpp:606
ExecutorModule * CreateFileAccessExecutorModule(Executor &exec)
Definition: filemod.cpp:299
std::string name
Definition: osmod.cpp:943
const int LOG_DATETIME
Definition: core.h:80
bool getObjArrayParam(unsigned param, ObjArray *&pobjarr)
Definition: execmodl.cpp:57
Bscript::BObjectImp * mf_ReadFile()
Definition: filemod.cpp:327
#define ERROR_PRINT
Definition: logfacility.h:230
bool HasReadAccess(const Plib::Package *pkg, const Plib::Package *filepackage, const std::string &path)
Definition: filemod.cpp:254
std::string normalized_dir_form(const std::string &istr)
Definition: fileutil.cpp:25
bool FileExists(const char *filename)
Definition: fileutil.cpp:118
bool read(ConfigElem &elem)
Definition: cfgfile.cpp:1015
Definition: berror.cpp:12
size_t length() const
Definition: impstr.h:68
const std::string & dir() const
Definition: pkg.h:79
int make_dir(const char *dir)
Definition: fileutil.cpp:82