00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "../intl.h"
00032 #include "crypt.h"
00033 #include "record.h"
00034 #include "structs.h"
00035 #include "file.h"
00036
00037 #ifdef TIME_WITH_SYS_TIME
00038 # include <sys/time.h>
00039 # include <time.h>
00040 #else
00041 # ifdef HAVE_SYS_TIME_H
00042 # include <sys/time.h>
00043 # else
00044 # include <time.h>
00045 # endif
00046 #endif // TIME_WITH_SYS_TIME
00047
00048 #ifdef HAVE_INTTYPES_H
00049 # include <inttypes.h>
00050 #endif
00051
00052 #ifdef HAVE_SYS_TYPES_H
00053 # include <sys/types.h>
00054 #endif
00055
00056 #ifdef HAVE_SYS_STAT_H
00057 # include <sys/stat.h>
00058 #endif
00059
00060 #ifdef HAVE_FCNTL_H
00061 # include <fcntl.h>
00062 #endif
00063
00064 #ifdef HAVE_STRING_H
00065 # include <string.h>
00066 #endif
00067
00068 #ifdef HAVE_ERRNO_H
00069 # include <errno.h>
00070 #endif
00071
00072 #ifdef HAVE_UNISTD_H
00073 # include <unistd.h>
00074 #endif
00075
00076 #ifdef HAVE_ALLOCA_H
00077 # include <alloca.h>
00078 #endif
00079
00080 using namespace YAPET;
00081
00091 const char CONTROL_STR[] = "ABCDEFGHIJKLMNOPQRSTUVW";
00092
00101 const char RECOG_STR[] = "YAPET1.0";
00102
00110 void
00111 File::checkFileSecurity() throw (YAPETException) {
00112 #if defined(HAVE_FSTAT) && defined(HAVE_GETUID)
00113 struct stat buf;
00114 int err = fstat (fd, &buf);
00115
00116 if (err == -1)
00117 throw YAPETException (strerror (errno) );
00118
00119 uid_t uid = getuid();
00120
00121 if (buf.st_uid != uid) {
00122 std::string tmp (_ ("You are not the owner of ") );
00123 throw YAPETRetryException (tmp + filename);
00124 }
00125
00126 if (buf.st_mode != (S_IFREG | S_IRUSR | S_IWUSR) ) {
00127 std::string tmp1 (_ ("Permissions of ") );
00128 std::string tmp2 (_ (" not secure.") );
00129 throw YAPETRetryException (tmp1 + filename + tmp2);
00130 }
00131
00132 #endif
00133 }
00134
00142 void
00143 File::setFileSecurity() throw (YAPETException) {
00144 #if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD) && defined(HAVE_FSTAT)
00145 struct stat buf;
00146 int err = fstat (fd, &buf);
00147
00148 if (err == -1)
00149 throw YAPETException (strerror (errno) );
00150
00151 err = fchown (fd, getuid(), buf.st_gid);
00152
00153 if (err == -1) {
00154 std::string tmp (_ ("Cannot set the owner of ") );
00155 throw YAPETRetryException (tmp + filename);
00156 }
00157
00158 err = fchmod (fd, S_IRUSR | S_IWUSR);
00159
00160 if (err == -1) {
00161 std::string tmp (_ ("Cannot set file permissions on ") );
00162 throw YAPETRetryException (tmp + filename);
00163 }
00164
00165 #endif
00166 }
00167
00168
00174 void
00175 File::openCreate() throw (YAPETException) {
00176 fd = ::open (filename.c_str(),
00177 O_RDWR | O_CREAT | O_TRUNC | O_APPEND,
00178 (usefsecurity ? S_IRUSR | S_IWUSR :
00179 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) );
00180
00181 if (fd == -1)
00182 throw YAPETException (strerror (errno) );
00183
00184 if (usefsecurity)
00185 checkFileSecurity();
00186 }
00187
00192 void
00193 File::openNoCreate() throw (YAPETException) {
00194 fd = ::open (filename.c_str(), O_RDWR | O_APPEND);
00195
00196 if (fd == -1)
00197 throw YAPETException (strerror (errno) );
00198
00199 if (usefsecurity)
00200 checkFileSecurity();
00201 }
00202
00209 int64_t
00210 File::lastModified() const throw (YAPETException) {
00211 struct stat st_buf;
00212 int retval = fstat (fd, &st_buf);
00213
00214 if (retval == -1)
00215 throw YAPETException (strerror (errno) );
00216
00217 return st_buf.st_mtime;
00218 }
00219
00227 void
00228 File::seekCurr (off_t offset) const throw (YAPETException) {
00229 off_t pos = lseek (fd, offset, SEEK_CUR);
00230
00231 if ( ( (off_t) - 1) == pos)
00232 throw YAPETException (strerror (errno) );
00233 }
00234
00240 void
00241 File::seekAbs (off_t offset) const throw (YAPETException) {
00242 off_t pos = lseek (fd, offset, SEEK_SET);
00243
00244 if ( ( (off_t) - 1) == pos)
00245 throw YAPETException (strerror (errno) );
00246
00247 if (pos != offset)
00248 throw YAPETException (_ ("Error seeking within file: ") + filename);
00249 }
00250
00256 void
00257 File::preparePWSave() throw (YAPETException) {
00258 BDBuffer* curr_header = readHeader();
00259 ::close (fd);
00260
00261 try {
00262 openCreate();
00263 } catch (YAPETException& ex) {
00264 if (curr_header != NULL)
00265 delete curr_header;
00266
00267 throw;
00268 }
00269
00270 mtime = lastModified();
00271 writeHeader (*curr_header);
00272 delete curr_header;
00273 }
00274
00280 void
00281 File::seekDataSection() const throw (YAPETException) {
00282 seekAbs (strlen (RECOG_STR) );
00283 uint32_t len;
00284 int retval = ::read (fd, &len, sizeof (uint32_t) );
00285
00286 if (retval == -1)
00287 throw YAPETException (strerror (errno) );
00288
00289 if ( ( (size_t) retval) != sizeof (uint32_t) )
00290 throw YAPETException (_ ("Unable to seek to data section") );
00291
00292 len = int_from_disk<uint32_t> (len);
00293 seekCurr (len);
00294 }
00295
00313 BDBuffer*
00314 File::read() const throw (YAPETException) {
00315 uint32_t len;
00316 int retval = ::read (fd, &len, sizeof (uint32_t) );
00317
00318 if (retval == -1)
00319 throw YAPETException (strerror (errno) );
00320
00321 if (retval == 0)
00322 return NULL;
00323
00324 if ( ( (size_t) retval) < sizeof (uint32_t) )
00325 throw YAPETException (_ ("Short read on file: ") + filename);
00326
00327
00328 len = int_from_disk<uint32_t> (len);
00329 BDBuffer* buf = new BDBuffer (len);
00330 retval = ::read (fd, *buf, len);
00331
00332 if (retval == -1)
00333 throw YAPETException (strerror (errno) );
00334
00335 if (retval == 0) {
00336 delete buf;
00337 return NULL;
00338 }
00339
00340 if ( ( (uint32_t) retval) < len) {
00341 delete buf;
00342 throw YAPETException (_ ("Short read on file: ") + filename);
00343 }
00344
00345 return buf;
00346 }
00347
00370 void
00371 File::write (const BDBuffer& buff, bool forceappend, bool forcewrite)
00372 throw (YAPETException, YAPETRetryException) {
00373 if ( (mtime != lastModified() ) && !forcewrite)
00374 throw YAPETRetryException (_ ("File has been modified") );
00375
00376 if (forceappend) {
00377 off_t pos = lseek (fd, 0, SEEK_END);
00378
00379 if ( ( (off_t) - 1) == pos)
00380 throw YAPETException (strerror (errno) );
00381 }
00382
00383 uint32_t s = buff.size();
00384
00385 s = int_to_disk<uint32_t> (s);
00386 int retval = ::write (fd, &s, sizeof (uint32_t) );
00387
00388 if (retval == -1)
00389 throw YAPETException (strerror (errno) );
00390
00391 if (retval != sizeof (uint32_t) )
00392 throw YAPETException (_ ("Short write on file: ") + filename);
00393
00394 retval = ::write (fd, buff, buff.size() );
00395
00396 if (retval == -1)
00397 throw YAPETException (strerror (errno) );
00398
00399 if ( ( (size_t) retval) < buff.size() )
00400 throw YAPETException (_ ("Short write on file: ") + filename);
00401
00402 mtime = lastModified();
00403 }
00404
00410 bool
00411 File::isempty() const throw (YAPETException) {
00412 struct stat st_buf;
00413 int retval = fstat (fd, &st_buf);
00414
00415 if (retval == -1)
00416 throw YAPETException (strerror (errno) );
00417
00418 if (st_buf.st_size == 0)
00419 return true;
00420
00421 return false;
00422 }
00423
00432 void
00433 File::initFile (const Key& key) throw (YAPETException) {
00434 Crypt crypt (key);
00435 Record<FileHeader_64> header;
00436 FileHeader_64* ptr = header;
00437 ptr->version = VERSION_2;
00438 memcpy (ptr->control, CONTROL_STR, HEADER_CONTROL_SIZE);
00439 ptr->pwset = int_to_disk<int64_t> (time (NULL) );
00440 mtime = lastModified();
00441 writeHeader (header, key);
00442
00443 BDBuffer* buff = readHeader();
00444
00445 if (buff == NULL)
00446 throw YAPETException (_ ("EOF encountered while reading header") );
00447
00448 Record<FileHeader_64>* dec_hdr = crypt.decrypt<FileHeader_64> (*buff);
00449 FileHeader_64* ptr_dec_hdr = *dec_hdr;
00450 int retval = memcmp (ptr_dec_hdr->control, ptr->control, HEADER_CONTROL_SIZE);
00451
00452 if (retval != 0)
00453 throw YAPETException (_ ("Sanity check for control field failed") );
00454
00455 delete buff;
00456 delete dec_hdr;
00457 }
00458
00471 void
00472 File::writeHeader (const Record<FileHeader_64>& header, const Key& key)
00473 throw (YAPETException) {
00474 Crypt crypt (key);
00475 BDBuffer* buff = NULL;
00476
00477 try {
00478 buff = crypt.encrypt (header);
00479 writeHeader (*buff);
00480 } catch (YAPETException& ex) {
00481 if (buff != NULL)
00482 delete buff;
00483
00484 throw;
00485 } catch (...) {
00486 if (buff != NULL)
00487 delete buff;
00488
00489 throw YAPETException (_ ("Unknown exception catched") );
00490 }
00491
00492 delete buff;
00493 }
00494
00502 void
00503 File::writeHeader (const BDBuffer& enc_header) throw (YAPETException) {
00504 seekAbs (0);
00505
00506 ssize_t retval = ::write (fd, RECOG_STR, strlen (RECOG_STR) );
00507
00508 if (retval == -1)
00509 throw YAPETException (strerror (errno) );
00510
00511 if ( ( (size_t) retval) != strlen (RECOG_STR) )
00512 throw YAPETException (_ ("Short write on file: ") + filename);
00513
00514 mtime = lastModified();
00515 write (enc_header);
00516 }
00517
00530 BDBuffer*
00531 File::readHeader() const throw (YAPETException) {
00532 seekAbs (0);
00533 char* buff = (char*) alloca (strlen (RECOG_STR) );
00534
00535 if (buff == NULL)
00536 throw YAPETException (_ ("Memory exhausted") );
00537
00538 int retval = ::read (fd, buff, strlen (RECOG_STR) );
00539
00540 if (retval == -1)
00541 throw YAPETException (strerror (errno) );
00542
00543 if ( ( (size_t) retval) != strlen (RECOG_STR) )
00544 throw YAPETException (_ ("File type not recognized") );
00545
00546 retval = memcmp (RECOG_STR, buff, strlen (RECOG_STR) );
00547
00548 if (retval != 0)
00549 throw YAPETException (_ ("File type not recognized") );
00550
00551 return read();
00552 }
00553
00581 void
00582 File::readHeader(const Key& key, Record<FileHeader_32>** ptr32, Record<FileHeader_64>** ptr64) const throw(YAPETException) {
00583 assert(ptr32 != NULL && ptr64 != NULL);
00584 if (ptr32 == NULL)
00585 throw YAPETException(_("Null pointer passed in ptr32"), NULLPOINTER);
00586 if (ptr64 == NULL)
00587 throw YAPETException(_("Null pointer passed in ptr64"), NULLPOINTER);
00588
00589 Crypt crypt (key);
00590 BDBuffer* enc_header = NULL;
00591
00592 try {
00593 enc_header = readHeader();
00594
00595 try {
00596 *ptr32 = crypt.decrypt<FileHeader_32> (*enc_header);
00597 } catch (YAPETException& ex) {
00598
00599 if (*ptr32 != NULL) {
00600 delete *ptr32;
00601 *ptr32 = NULL;
00602 }
00603
00604 try {
00605 *ptr64 = crypt.decrypt<FileHeader_64> (*enc_header);
00606 } catch (YAPETEncryptionException& ex) {
00607 if (enc_header != NULL) {
00608 delete enc_header;
00609 enc_header = NULL;
00610 }
00611
00612 if (*ptr32 != NULL) {
00613 delete *ptr32;
00614 *ptr32 = NULL;
00615 }
00616 if (*ptr64 != NULL) {
00617 delete *ptr64;
00618 *ptr64 = NULL;
00619 }
00620
00621 throw YAPETInvalidPasswordException();
00622 } catch (YAPETException &ex) {
00623
00624 if (*ptr64 != NULL) {
00625 delete *ptr64;
00626 *ptr64 = NULL;
00627 }
00628 throw;
00629 }
00630 }
00631 } catch (YAPETEncryptionException& ex) {
00632 if (enc_header != NULL) delete enc_header;
00633
00634 if (*ptr32 != NULL) {
00635 delete *ptr32;
00636 *ptr32 = NULL;
00637 }
00638 if (*ptr64 != NULL) {
00639 delete *ptr64;
00640 *ptr64 = NULL;
00641 }
00642
00643 throw YAPETInvalidPasswordException();
00644 } catch (YAPETException& ex) {
00645 if (enc_header != NULL) delete enc_header;
00646
00647 if (*ptr32 != NULL) {
00648 delete *ptr32;
00649 *ptr32 = NULL;
00650 }
00651 if (*ptr64 != NULL) {
00652 delete *ptr64;
00653 *ptr64 = NULL;
00654 }
00655
00656 throw;
00657 }
00658
00659 delete enc_header;
00660 }
00661
00675 void
00676 File::validateKey (const Key& key)
00677 throw (YAPETException, YAPETInvalidPasswordException) {
00678
00679 Record<FileHeader_32>* dec_header_32 = NULL;
00680 Record<FileHeader_64>* dec_header_64 = NULL;
00681
00682 readHeader(key, &dec_header_32, &dec_header_64);
00683 assert(dec_header_32 != NULL || dec_header_64 != NULL);
00684
00685 FileHeader_32* ptr_dec_header_32 =
00686 (dec_header_32 != NULL) ? static_cast<FileHeader_32*>(*dec_header_32) : NULL;
00687 FileHeader_64* ptr_dec_header_64 =
00688 (dec_header_64 != NULL) ? static_cast<FileHeader_64*>(*dec_header_64) : NULL;
00689
00690 int retval;
00691 if (ptr_dec_header_32 != NULL) {
00692 retval = memcmp (ptr_dec_header_32->control,
00693 CONTROL_STR,
00694 HEADER_CONTROL_SIZE);
00695 } else {
00696 assert(ptr_dec_header_64 != NULL);
00697 retval = memcmp (ptr_dec_header_64->control,
00698 CONTROL_STR,
00699 HEADER_CONTROL_SIZE);
00700 }
00701 if (dec_header_32 != NULL)
00702 delete dec_header_32;
00703 if (dec_header_64 != NULL)
00704 delete dec_header_64;
00705
00706 if (retval != 0)
00707 throw YAPETInvalidPasswordException();
00708 }
00709
00739 File::File (const std::string& fn, const Key& key, bool create, bool secure)
00740 throw (YAPETException) : filename (fn), usefsecurity (secure) {
00741 if (create)
00742 openCreate();
00743 else
00744 openNoCreate();
00745
00746 if (isempty() ) {
00747 initFile (key);
00748 } else {
00749 validateKey (key);
00750 }
00751 }
00752
00756 File::File (const File& f) throw (YAPETException) {
00757 fd = dup (f.fd);
00758
00759 if (fd == -1)
00760 throw YAPETException (strerror (errno) );
00761
00762 filename = f.filename;
00763 mtime = f.mtime;
00764 usefsecurity = f.usefsecurity;
00765 }
00766
00770 File::~File() {
00771 close (fd);
00772 }
00773
00781 void
00782 File::save (std::list<PartDec>& records) throw (YAPETException) {
00783 if (usefsecurity)
00784 setFileSecurity();
00785
00786 preparePWSave();
00787 std::list<PartDec>::iterator it = records.begin();
00788
00789 while (it != records.end() ) {
00790 write ( it->getEncRecord() );
00791 it++;
00792 }
00793 }
00794
00808 std::list<PartDec>
00809 File::read (const Key& key) const throw (YAPETException) {
00810 seekDataSection();
00811 BDBuffer* buff = NULL;
00812 std::list<PartDec> retval;
00813
00814 try {
00815 buff = read();
00816
00817 while (buff != NULL) {
00818 retval.push_back (PartDec (*buff, key) );
00819 delete buff;
00820 buff = read();
00821 }
00822 } catch (YAPETException& ex) {
00823 if (buff != NULL)
00824 delete buff;
00825
00826 throw;
00827 }
00828
00829 return retval;
00830 }
00831
00846 void
00847 File::setNewKey (const Key& oldkey,
00848 const Key& newkey) throw (YAPETException) {
00849 close (fd);
00850 std::string backupfilename (filename + ".bak");
00851 int retval = rename (filename.c_str(), backupfilename.c_str() );
00852
00853 if (retval == -1) {
00854
00855 openNoCreate();
00856 throw YAPETException (strerror (errno) );
00857 }
00858
00859 File* oldfile = NULL;
00860
00861 try {
00862
00863 oldfile = new File (backupfilename, oldkey, false, false);
00864
00865 openCreate();
00866 initFile (newkey);
00867
00868 std::list<PartDec> entries = oldfile->read (oldkey);
00869 std::list<PartDec>::iterator it = entries.begin();
00870 Crypt oldcrypt (oldkey);
00871 Crypt newcrypt (newkey);
00872
00873 while (it != entries.end() ) {
00874 Record<PasswordRecord>* dec_rec_ptr = NULL;
00875 BDBuffer* new_enc_rec = NULL;
00876
00877 try {
00878
00879 const BDBuffer old_enc_rec = (*it).getEncRecord();
00880 dec_rec_ptr =
00881 oldcrypt.decrypt<PasswordRecord> (old_enc_rec);
00882 new_enc_rec =
00883 newcrypt.encrypt (*dec_rec_ptr);
00884 write (*new_enc_rec);
00885 delete dec_rec_ptr;
00886 delete new_enc_rec;
00887 } catch (YAPETException& ex) {
00888 if (dec_rec_ptr != NULL)
00889 delete dec_rec_ptr;
00890
00891 if (new_enc_rec != NULL)
00892 delete new_enc_rec;
00893
00894 throw;
00895 }
00896
00897 it++;
00898 }
00899 } catch (YAPETException& ex) {
00900 if (oldfile != NULL)
00901 delete oldfile;
00902
00903 throw;
00904 }
00905
00906 delete oldfile;
00907 }
00908
00919 int64_t
00920 File::getMasterPWSet (const Key& key) const
00921 throw (YAPETException, YAPETInvalidPasswordException) {
00922
00923 Record<FileHeader_32>* dec_header_32 = NULL;
00924 Record<FileHeader_64>* dec_header_64 = NULL;
00925
00926 readHeader(key, &dec_header_32, &dec_header_64);
00927 assert(dec_header_32 != NULL || dec_header_64 != NULL);
00928
00929 FileHeader_32* ptr_dec_header_32 =
00930 (dec_header_32 != NULL) ? static_cast<FileHeader_32*>(*dec_header_32) : NULL;
00931 FileHeader_64* ptr_dec_header_64 =
00932 (dec_header_64 != NULL) ? static_cast<FileHeader_64*>(*dec_header_64) : NULL;
00933
00934 int64_t t;
00935 if (ptr_dec_header_32 != NULL) {
00936 t = int_from_disk<int32_t> (ptr_dec_header_32->pwset);
00937 } else {
00938 assert(ptr_dec_header_64 != NULL);
00939 t = int_from_disk<int64_t> (ptr_dec_header_64->pwset);
00940 }
00941
00942 if (dec_header_32 != NULL)
00943 delete dec_header_32;
00944 if (dec_header_64 != NULL)
00945 delete dec_header_64;
00946
00947 return t;
00948 }
00949
00955 FILE_VERSION
00956 File::getFileVersion(const Key& key) const throw (YAPETException, YAPETInvalidPasswordException) {
00957
00958 Record<FileHeader_32>* dec_header_32 = NULL;
00959 Record<FileHeader_64>* dec_header_64 = NULL;
00960
00961 readHeader(key, &dec_header_32, &dec_header_64);
00962 assert(dec_header_32 != NULL || dec_header_64 != NULL);
00963
00964 FileHeader_32* ptr_dec_header_32 =
00965 (dec_header_32 != NULL) ? static_cast<FileHeader_32*>(*dec_header_32) : NULL;
00966 FileHeader_64* ptr_dec_header_64 =
00967 (dec_header_64 != NULL) ? static_cast<FileHeader_64*>(*dec_header_64) : NULL;
00968
00969 FILE_VERSION v;
00970 if (ptr_dec_header_32 != NULL) {
00971 v = static_cast<FILE_VERSION>(ptr_dec_header_32->version);
00972 } else {
00973 assert(ptr_dec_header_64 != NULL);
00974 v = static_cast<FILE_VERSION>(ptr_dec_header_64->version);
00975 }
00976
00977 if (dec_header_32 != NULL)
00978 delete dec_header_32;
00979 if (dec_header_64 != NULL)
00980 delete dec_header_64;
00981
00982 return v;
00983 }
00984
00985 const File&
00986 File::operator= (const File & f) throw (YAPETException) {
00987 if (this == &f) return *this;
00988
00989 close (fd);
00990 fd = dup (f.fd);
00991
00992 if (fd == -1)
00993 throw YAPETException (strerror (errno) );
00994
00995 filename = f.filename;
00996 return *this;
00997 }