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