00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "../intl.h"
00021 #include "crypt.h"
00022 #include "record.h"
00023 #include "structs.h"
00024 #include "file.h"
00025
00026 #ifdef TIME_WITH_SYS_TIME
00027 # include <sys/time.h>
00028 # include <time.h>
00029 #else
00030 # ifdef HAVE_SYS_TIME_H
00031 # include <sys/time.h>
00032 # else
00033 # include <time.h>
00034 # endif
00035 #endif // TIME_WITH_SYS_TIME
00036
00037 #ifdef HAVE_INTTYPES_H
00038 # include <inttypes.h>
00039 #endif
00040
00041 #ifdef HAVE_SYS_TYPES_H
00042 # include <sys/types.h>
00043 #endif
00044
00045 #ifdef HAVE_SYS_STAT_H
00046 # include <sys/stat.h>
00047 #endif
00048
00049 #ifdef HAVE_FCNTL_H
00050 # include <fcntl.h>
00051 #endif
00052
00053 #ifdef HAVE_STRING_H
00054 # include <string.h>
00055 #endif
00056
00057 #ifdef HAVE_ERRNO_H
00058 # include <errno.h>
00059 #endif
00060
00061 #ifdef HAVE_UNISTD_H
00062 # include <unistd.h>
00063 #endif
00064
00065 #ifdef HAVE_ALLOCA_H
00066 # include <alloca.h>
00067 #elif defined __GNUC__
00068 # define alloca __builtin_alloca
00069 #elif defined _AIX
00070 # define alloca __alloca
00071 #elif defined _MSC_VER
00072 # include <malloc.h>
00073 # define alloca _alloca
00074 #else
00075 # include <stddef.h>
00076 #endif
00077
00078 using namespace YAPET;
00079
00089 const char CONTROL_STR[] = "ABCDEFGHIJKLMNOPQRSTUVW";
00090
00099 const char RECOG_STR[] = "YAPET1.0";
00100
00106 void
00107 File::openCreate() throw(YAPETException) {
00108 fd = ::open(filename.c_str(),
00109 O_RDWR | O_CREAT | O_TRUNC | O_APPEND, S_IRUSR | S_IWUSR);
00110 if (fd == -1)
00111 throw YAPETException(strerror(errno));
00112 }
00113
00118 void
00119 File::openNoCreate() throw(YAPETException) {
00120 fd = ::open(filename.c_str(), O_RDWR | O_APPEND);
00121 if (fd == -1)
00122 throw YAPETException(strerror(errno));
00123 }
00124
00131 time_t
00132 File::lastModified() const throw(YAPETException){
00133 struct stat st_buf;
00134 int retval = fstat(fd, &st_buf);
00135 if (retval == -1)
00136 throw YAPETException(strerror(errno));
00137
00138 return st_buf.st_mtime;
00139 }
00140
00148 void
00149 File::seekCurr(off_t offset) const throw(YAPETException) {
00150 off_t pos = lseek(fd, offset, SEEK_CUR);
00151 if ( ((off_t)-1) == pos)
00152 throw YAPETException(strerror(errno));
00153 }
00154
00160 void
00161 File::seekAbs(off_t offset) const throw(YAPETException) {
00162 off_t pos = lseek(fd, offset, SEEK_SET);
00163 if ( ((off_t)-1) == pos)
00164 throw YAPETException(strerror(errno));
00165
00166 if (pos != offset)
00167 throw YAPETException(_("Error seeking within file: ") + filename);
00168 }
00169
00174 void
00175 File::preparePWSave() throw(YAPETException) {
00176 BDBuffer* curr_header = readHeader();
00177
00178 ::close(fd);
00179 try {
00180 openCreate();
00181 } catch (YAPETException& ex) {
00182 if (curr_header != NULL)
00183 delete curr_header;
00184 throw;
00185 }
00186
00187 mtime = lastModified();
00188 writeHeader(*curr_header);
00189 delete curr_header;
00190 }
00191
00197 void
00198 File::seekDataSection() const throw(YAPETException) {
00199 seekAbs(strlen(RECOG_STR));
00200 uint32_t len;
00201 int retval = ::read(fd, &len, sizeof(uint32_t));
00202 if (retval == -1)
00203 throw YAPETException(strerror(errno));
00204
00205 if ( ((size_t)retval) != sizeof(uint32_t))
00206 throw YAPETException(_("Unable to seek to data section"));
00207
00208 len = uint32_from_disk(len);
00209
00210 seekCurr(len);
00211 }
00212
00213 #ifndef WORDS_BIGENDIAN
00214
00222 uint32_t
00223 File::uint32_to_disk(uint32_t i) const {
00224 ENDIAN endian;
00225 endian.abcd = i;
00226
00227 uint8_t tmp = endian.dword.b.b;
00228 endian.dword.b.b = endian.dword.a.a;
00229 endian.dword.a.a = tmp;
00230
00231 tmp = endian.dword.b.a;
00232 endian.dword.b.a = endian.dword.a.b;
00233 endian.dword.a.b = tmp;
00234
00235 return endian.abcd;
00236 }
00237
00246 uint32_t
00247 File::uint32_from_disk(uint32_t i) const {
00248 return uint32_to_disk(i);
00249 }
00250 #endif // WORDS_BIGENDIAN
00251
00269 BDBuffer*
00270 File::read() const throw(YAPETException) {
00271 uint32_t len;
00272 int retval = ::read(fd, &len, sizeof(uint32_t));
00273 if (retval == -1)
00274 throw YAPETException(strerror(errno));
00275
00276 if (retval == 0)
00277 return NULL;
00278
00279 if ( ((size_t)retval) < sizeof(uint32_t) )
00280 throw YAPETException(_("Short read on file: ") + filename);
00281
00282
00283 len = uint32_from_disk(len);
00284
00285 BDBuffer* buf = new BDBuffer(len);
00286 retval = ::read(fd, *buf, len);
00287 if (retval == -1)
00288 throw YAPETException(strerror(errno));
00289
00290 if (retval == 0) {
00291 delete buf;
00292 return NULL;
00293 }
00294
00295 if (((uint32_t)retval) < len) {
00296 delete buf;
00297 throw YAPETException(_("Short read on file: ") + filename);
00298 }
00299
00300 return buf;
00301 }
00302
00325 void
00326 File::write(const BDBuffer& buff, bool forceappend, bool forcewrite)
00327 throw(YAPETException, YAPETRetryException) {
00328 if ( (mtime != lastModified()) && !forcewrite)
00329 throw YAPETRetryException(_("File has been modified"));
00330
00331 if (forceappend) {
00332 off_t pos = lseek(fd, 0, SEEK_END);
00333 if ( ((off_t)-1) == pos)
00334 throw YAPETException(strerror(errno));
00335 }
00336 uint32_t s = buff.size();
00337
00338
00339 s = uint32_to_disk(s);
00340
00341 int retval = ::write(fd, &s, sizeof(uint32_t));
00342 if (retval == -1)
00343 throw YAPETException(strerror(errno));
00344 if (retval != sizeof(uint32_t) )
00345 throw YAPETException(_("Short write on file: ") + filename);
00346
00347 retval = ::write(fd, buff, buff.size());
00348 if (retval == -1)
00349 throw YAPETException(strerror(errno));
00350
00351 if (((size_t)retval) < buff.size())
00352 throw YAPETException(_("Short write on file: ") + filename);
00353
00354 mtime = lastModified();
00355 }
00356
00362 bool
00363 File::isempty() const throw(YAPETException){
00364 struct stat st_buf;
00365 int retval = fstat(fd, &st_buf);
00366 if (retval == -1)
00367 throw YAPETException(strerror(errno));
00368
00369 if (st_buf.st_size == 0)
00370 return true;
00371
00372 return false;
00373 }
00374
00381 void
00382 File::initFile(const Key& key) throw(YAPETException) {
00383 Crypt crypt(key);
00384
00385 Record<FileHeader> header;
00386 FileHeader* ptr = header;
00387 ptr->version = 1;
00388 memcpy(ptr->control, CONTROL_STR, HEADER_CONTROL_SIZE);
00389 ptr->pwset = uint32_to_disk(time(NULL));
00390
00391 mtime = lastModified();
00392
00393 writeHeader(header, key);
00394
00395
00396 BDBuffer* buff = readHeader();
00397 if (buff == NULL)
00398 throw YAPETException(_("EOF encountered while reading header"));
00399
00400 Record<FileHeader>* dec_hdr = crypt.decrypt<FileHeader>(*buff);
00401
00402 FileHeader* ptr_dec_hdr = *dec_hdr;
00403
00404 int retval = memcmp(ptr_dec_hdr->control, ptr->control, HEADER_CONTROL_SIZE);
00405 if (retval != 0)
00406 throw YAPETException(_("Sanity check for control field failed"));
00407
00408 delete buff;
00409 delete dec_hdr;
00410 }
00411
00420 void
00421 File::writeHeader(const Record<FileHeader>& header, const Key& key)
00422 throw(YAPETException) {
00423
00424 Crypt crypt(key);
00425 BDBuffer* buff = NULL;
00426 try {
00427 buff = crypt.encrypt(header);
00428 writeHeader(*buff);
00429 } catch (YAPETException& ex) {
00430 if (buff != NULL)
00431 delete buff;
00432 throw;
00433 } catch (...) {
00434 if (buff != NULL)
00435 delete buff;
00436
00437 throw YAPETException(_("Unknown exception catched"));
00438 }
00439
00440 delete buff;
00441 }
00442
00450 void
00451 File::writeHeader(const BDBuffer& enc_header) throw(YAPETException) {
00452 seekAbs(0);
00453
00454
00455 ssize_t retval = ::write(fd, RECOG_STR, strlen(RECOG_STR));
00456 if (retval == -1)
00457 throw YAPETException(strerror(errno));
00458
00459 if (((size_t)retval) != strlen(RECOG_STR) )
00460 throw YAPETException(_("Short write on file: ") + filename);
00461
00462 mtime = lastModified();
00463
00464 write(enc_header);
00465 }
00466
00479 BDBuffer*
00480 File::readHeader() const throw(YAPETException) {
00481 seekAbs(0);
00482
00483 char* buff = (char*) alloca(strlen(RECOG_STR));
00484 if (buff == NULL)
00485 throw YAPETException(_("Memory exhausted"));
00486
00487 int retval = ::read(fd, buff, strlen(RECOG_STR));
00488 if (retval == -1)
00489 throw YAPETException(strerror(errno));
00490
00491 if (((size_t)retval) != strlen(RECOG_STR) )
00492 throw YAPETException(_("File type not recognized"));
00493
00494 retval = memcmp(RECOG_STR, buff, strlen(RECOG_STR));
00495 if (retval != 0)
00496 throw YAPETException(_("File type not recognized"));
00497
00498 return read();
00499 }
00500
00512 void
00513 File::validateKey(const Key& key)
00514 throw(YAPETException,YAPETInvalidPasswordException) {
00515
00516 Crypt crypt(key);
00517 BDBuffer* enc_header = NULL;
00518 Record<FileHeader>* dec_header = NULL;
00519 FileHeader* ptr_dec_header = NULL;
00520
00521 try {
00522 enc_header = readHeader();
00523 dec_header = crypt.decrypt<FileHeader>(*enc_header);
00524 ptr_dec_header = *dec_header;
00525 } catch (YAPETEncryptionException& ex) {
00526 if (enc_header != NULL) delete enc_header;
00527 if (dec_header != NULL) delete dec_header;
00528 throw YAPETInvalidPasswordException();
00529 } catch (YAPETException& ex) {
00530 if (enc_header != NULL) delete enc_header;
00531 if (dec_header != NULL) delete dec_header;
00532 throw;
00533 }
00534
00535 int retval = memcmp(ptr_dec_header->control,
00536 CONTROL_STR,
00537 HEADER_CONTROL_SIZE);
00538 delete enc_header;
00539 delete dec_header;
00540 if (retval != 0)
00541 throw YAPETInvalidPasswordException();
00542 }
00543
00566 File::File(const std::string& fn, const Key& key, bool create)
00567 throw(YAPETException) : filename(fn) {
00568 if (create)
00569 openCreate();
00570 else
00571 openNoCreate();
00572
00573 if (isempty()) {
00574 initFile(key);
00575 } else {
00576 validateKey(key);
00577 }
00578 }
00579
00583 File::File(const File& f) throw(YAPETException) {
00584 fd = dup(f.fd);
00585 if (fd == -1)
00586 throw YAPETException(strerror(errno));
00587
00588 filename = f.filename;
00589 mtime = f.mtime;
00590 }
00591
00595 File::~File() {
00596 close(fd);
00597 }
00598
00606 void
00607 File::save(std::list<PartDec>& records) throw(YAPETException) {
00608 preparePWSave();
00609 std::list<PartDec>::iterator it = records.begin();
00610 while (it != records.end() ) {
00611 write( it->getEncRecord());
00612 it++;
00613 }
00614 }
00615
00629 std::list<PartDec>
00630 File::read(const Key& key) const throw(YAPETException) {
00631 seekDataSection();
00632
00633 BDBuffer* buff = NULL;
00634 std::list<PartDec> retval;
00635
00636 try {
00637 buff = read();
00638 while (buff != NULL) {
00639 retval.push_back(PartDec(*buff, key));
00640 delete buff;
00641 buff = read();
00642 }
00643 } catch (YAPETException& ex) {
00644 if (buff != NULL)
00645 delete buff;
00646 throw;
00647 }
00648
00649 return retval;
00650 }
00651
00666 void
00667 File::setNewKey(const Key& oldkey,
00668 const Key& newkey) throw (YAPETException) {
00669 close(fd);
00670 std::string backupfilename(filename + ".bak");
00671 int retval = rename(filename.c_str(), backupfilename.c_str());
00672 if (retval == -1) {
00673
00674 openNoCreate();
00675 throw YAPETException(strerror(errno));
00676 }
00677
00678
00679 File* oldfile = NULL;
00680 try {
00681
00682 oldfile = new File(backupfilename, oldkey, false);
00683
00684 openCreate();
00685 initFile(newkey);
00686
00687
00688 std::list<PartDec> entries = oldfile->read(oldkey);
00689 std::list<PartDec>::iterator it = entries.begin();
00690 Crypt oldcrypt(oldkey);
00691 Crypt newcrypt(newkey);
00692 while (it != entries.end() ) {
00693 Record<PasswordRecord>* dec_rec_ptr = NULL;
00694 BDBuffer* new_enc_rec = NULL;
00695 try {
00696
00697 const BDBuffer old_enc_rec = (*it).getEncRecord();
00698 dec_rec_ptr =
00699 oldcrypt.decrypt<PasswordRecord>(old_enc_rec);
00700 new_enc_rec =
00701 newcrypt.encrypt(*dec_rec_ptr);
00702 write(*new_enc_rec);
00703 delete dec_rec_ptr;
00704 delete new_enc_rec;
00705 } catch (YAPETException& ex) {
00706 if (dec_rec_ptr != NULL)
00707 delete dec_rec_ptr;
00708 if (new_enc_rec != NULL)
00709 delete new_enc_rec;
00710 throw;
00711 }
00712 it++;
00713 }
00714 } catch (YAPETException& ex) {
00715 if (oldfile != NULL)
00716 delete oldfile;
00717 throw;
00718 }
00719 delete oldfile;
00720 }
00721
00730 time_t
00731 File::getMasterPWSet(const Key& key) const
00732 throw(YAPETException,YAPETInvalidPasswordException) {
00733 Crypt crypt(key);
00734 BDBuffer* enc_header = NULL;
00735 Record<FileHeader>* dec_header = NULL;
00736 FileHeader* ptr_dec_header = NULL;
00737
00738 try {
00739 enc_header = readHeader();
00740 dec_header = crypt.decrypt<FileHeader>(*enc_header);
00741 ptr_dec_header = *dec_header;
00742 } catch (YAPETEncryptionException& ex) {
00743 if (enc_header != NULL) delete enc_header;
00744 if (dec_header != NULL) delete dec_header;
00745 throw YAPETInvalidPasswordException();
00746 } catch (YAPETException& ex) {
00747 if (enc_header != NULL) delete enc_header;
00748 if (dec_header != NULL) delete dec_header;
00749 throw;
00750 }
00751
00752 time_t t = uint32_from_disk(ptr_dec_header->pwset);
00753 delete enc_header;
00754 delete dec_header;
00755
00756 return t;
00757 }
00758
00759
00760 const File&
00761 File::operator=(const File& f) throw(YAPETException) {
00762 if (this == &f) return *this;
00763
00764 close(fd);
00765
00766 fd = dup(f.fd);
00767 if (fd == -1)
00768 throw YAPETException(strerror(errno));
00769
00770 filename = f.filename;
00771
00772 return *this;
00773 }