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 #elif defined __GNUC__
00079 # define alloca __builtin_alloca
00080 #elif defined _AIX
00081 # define alloca __alloca
00082 #elif defined _MSC_VER
00083 # include <malloc.h>
00084 # define alloca _alloca
00085 #else
00086 # include <stddef.h>
00087 #endif
00088
00089 using namespace YAPET;
00090
00100 const char CONTROL_STR[] = "ABCDEFGHIJKLMNOPQRSTUVW";
00101
00110 const char RECOG_STR[] = "YAPET1.0";
00111
00117 void
00118 File::openCreate() throw(YAPETException) {
00119 fd = ::open(filename.c_str(),
00120 O_RDWR | O_CREAT | O_TRUNC | O_APPEND, S_IRUSR | S_IWUSR);
00121 if (fd == -1)
00122 throw YAPETException(strerror(errno));
00123 }
00124
00129 void
00130 File::openNoCreate() throw(YAPETException) {
00131 fd = ::open(filename.c_str(), O_RDWR | O_APPEND);
00132 if (fd == -1)
00133 throw YAPETException(strerror(errno));
00134 }
00135
00142 time_t
00143 File::lastModified() const throw(YAPETException){
00144 struct stat st_buf;
00145 int retval = fstat(fd, &st_buf);
00146 if (retval == -1)
00147 throw YAPETException(strerror(errno));
00148
00149 return st_buf.st_mtime;
00150 }
00151
00159 void
00160 File::seekCurr(off_t offset) const throw(YAPETException) {
00161 off_t pos = lseek(fd, offset, SEEK_CUR);
00162 if ( ((off_t)-1) == pos)
00163 throw YAPETException(strerror(errno));
00164 }
00165
00171 void
00172 File::seekAbs(off_t offset) const throw(YAPETException) {
00173 off_t pos = lseek(fd, offset, SEEK_SET);
00174 if ( ((off_t)-1) == pos)
00175 throw YAPETException(strerror(errno));
00176
00177 if (pos != offset)
00178 throw YAPETException(_("Error seeking within file: ") + filename);
00179 }
00180
00185 void
00186 File::preparePWSave() throw(YAPETException) {
00187 BDBuffer* curr_header = readHeader();
00188
00189 ::close(fd);
00190 try {
00191 openCreate();
00192 } catch (YAPETException& ex) {
00193 if (curr_header != NULL)
00194 delete curr_header;
00195 throw;
00196 }
00197
00198 mtime = lastModified();
00199 writeHeader(*curr_header);
00200 delete curr_header;
00201 }
00202
00208 void
00209 File::seekDataSection() const throw(YAPETException) {
00210 seekAbs(strlen(RECOG_STR));
00211 uint32_t len;
00212 int retval = ::read(fd, &len, sizeof(uint32_t));
00213 if (retval == -1)
00214 throw YAPETException(strerror(errno));
00215
00216 if ( ((size_t)retval) != sizeof(uint32_t))
00217 throw YAPETException(_("Unable to seek to data section"));
00218
00219 len = uint32_from_disk(len);
00220
00221 seekCurr(len);
00222 }
00223
00224 #ifndef WORDS_BIGENDIAN
00225
00233 uint32_t
00234 File::uint32_to_disk(uint32_t i) const {
00235 ENDIAN endian;
00236 endian.abcd = i;
00237
00238 uint8_t tmp = endian.dword.b.b;
00239 endian.dword.b.b = endian.dword.a.a;
00240 endian.dword.a.a = tmp;
00241
00242 tmp = endian.dword.b.a;
00243 endian.dword.b.a = endian.dword.a.b;
00244 endian.dword.a.b = tmp;
00245
00246 return endian.abcd;
00247 }
00248
00257 uint32_t
00258 File::uint32_from_disk(uint32_t i) const {
00259 return uint32_to_disk(i);
00260 }
00261 #endif // WORDS_BIGENDIAN
00262
00280 BDBuffer*
00281 File::read() const throw(YAPETException) {
00282 uint32_t len;
00283 int retval = ::read(fd, &len, sizeof(uint32_t));
00284 if (retval == -1)
00285 throw YAPETException(strerror(errno));
00286
00287 if (retval == 0)
00288 return NULL;
00289
00290 if ( ((size_t)retval) < sizeof(uint32_t) )
00291 throw YAPETException(_("Short read on file: ") + filename);
00292
00293
00294 len = uint32_from_disk(len);
00295
00296 BDBuffer* buf = new BDBuffer(len);
00297 retval = ::read(fd, *buf, len);
00298 if (retval == -1)
00299 throw YAPETException(strerror(errno));
00300
00301 if (retval == 0) {
00302 delete buf;
00303 return NULL;
00304 }
00305
00306 if (((uint32_t)retval) < len) {
00307 delete buf;
00308 throw YAPETException(_("Short read on file: ") + filename);
00309 }
00310
00311 return buf;
00312 }
00313
00336 void
00337 File::write(const BDBuffer& buff, bool forceappend, bool forcewrite)
00338 throw(YAPETException, YAPETRetryException) {
00339 if ( (mtime != lastModified()) && !forcewrite)
00340 throw YAPETRetryException(_("File has been modified"));
00341
00342 if (forceappend) {
00343 off_t pos = lseek(fd, 0, SEEK_END);
00344 if ( ((off_t)-1) == pos)
00345 throw YAPETException(strerror(errno));
00346 }
00347 uint32_t s = buff.size();
00348
00349
00350 s = uint32_to_disk(s);
00351
00352 int retval = ::write(fd, &s, sizeof(uint32_t));
00353 if (retval == -1)
00354 throw YAPETException(strerror(errno));
00355 if (retval != sizeof(uint32_t) )
00356 throw YAPETException(_("Short write on file: ") + filename);
00357
00358 retval = ::write(fd, buff, buff.size());
00359 if (retval == -1)
00360 throw YAPETException(strerror(errno));
00361
00362 if (((size_t)retval) < buff.size())
00363 throw YAPETException(_("Short write on file: ") + filename);
00364
00365 mtime = lastModified();
00366 }
00367
00373 bool
00374 File::isempty() const throw(YAPETException){
00375 struct stat st_buf;
00376 int retval = fstat(fd, &st_buf);
00377 if (retval == -1)
00378 throw YAPETException(strerror(errno));
00379
00380 if (st_buf.st_size == 0)
00381 return true;
00382
00383 return false;
00384 }
00385
00392 void
00393 File::initFile(const Key& key) throw(YAPETException) {
00394 Crypt crypt(key);
00395
00396 Record<FileHeader> header;
00397 FileHeader* ptr = header;
00398 ptr->version = 1;
00399 memcpy(ptr->control, CONTROL_STR, HEADER_CONTROL_SIZE);
00400 ptr->pwset = uint32_to_disk(time(NULL));
00401
00402 mtime = lastModified();
00403
00404 writeHeader(header, key);
00405
00406
00407 BDBuffer* buff = readHeader();
00408 if (buff == NULL)
00409 throw YAPETException(_("EOF encountered while reading header"));
00410
00411 Record<FileHeader>* dec_hdr = crypt.decrypt<FileHeader>(*buff);
00412
00413 FileHeader* ptr_dec_hdr = *dec_hdr;
00414
00415 int retval = memcmp(ptr_dec_hdr->control, ptr->control, HEADER_CONTROL_SIZE);
00416 if (retval != 0)
00417 throw YAPETException(_("Sanity check for control field failed"));
00418
00419 delete buff;
00420 delete dec_hdr;
00421 }
00422
00431 void
00432 File::writeHeader(const Record<FileHeader>& header, const Key& key)
00433 throw(YAPETException) {
00434
00435 Crypt crypt(key);
00436 BDBuffer* buff = NULL;
00437 try {
00438 buff = crypt.encrypt(header);
00439 writeHeader(*buff);
00440 } catch (YAPETException& ex) {
00441 if (buff != NULL)
00442 delete buff;
00443 throw;
00444 } catch (...) {
00445 if (buff != NULL)
00446 delete buff;
00447
00448 throw YAPETException(_("Unknown exception catched"));
00449 }
00450
00451 delete buff;
00452 }
00453
00461 void
00462 File::writeHeader(const BDBuffer& enc_header) throw(YAPETException) {
00463 seekAbs(0);
00464
00465
00466 ssize_t retval = ::write(fd, RECOG_STR, strlen(RECOG_STR));
00467 if (retval == -1)
00468 throw YAPETException(strerror(errno));
00469
00470 if (((size_t)retval) != strlen(RECOG_STR) )
00471 throw YAPETException(_("Short write on file: ") + filename);
00472
00473 mtime = lastModified();
00474
00475 write(enc_header);
00476 }
00477
00490 BDBuffer*
00491 File::readHeader() const throw(YAPETException) {
00492 seekAbs(0);
00493
00494 char* buff = (char*) alloca(strlen(RECOG_STR));
00495 if (buff == NULL)
00496 throw YAPETException(_("Memory exhausted"));
00497
00498 int retval = ::read(fd, buff, strlen(RECOG_STR));
00499 if (retval == -1)
00500 throw YAPETException(strerror(errno));
00501
00502 if (((size_t)retval) != strlen(RECOG_STR) )
00503 throw YAPETException(_("File type not recognized"));
00504
00505 retval = memcmp(RECOG_STR, buff, strlen(RECOG_STR));
00506 if (retval != 0)
00507 throw YAPETException(_("File type not recognized"));
00508
00509 return read();
00510 }
00511
00523 void
00524 File::validateKey(const Key& key)
00525 throw(YAPETException,YAPETInvalidPasswordException) {
00526
00527 Crypt crypt(key);
00528 BDBuffer* enc_header = NULL;
00529 Record<FileHeader>* dec_header = NULL;
00530 FileHeader* ptr_dec_header = NULL;
00531
00532 try {
00533 enc_header = readHeader();
00534 dec_header = crypt.decrypt<FileHeader>(*enc_header);
00535 ptr_dec_header = *dec_header;
00536 } catch (YAPETEncryptionException& ex) {
00537 if (enc_header != NULL) delete enc_header;
00538 if (dec_header != NULL) delete dec_header;
00539 throw YAPETInvalidPasswordException();
00540 } catch (YAPETException& ex) {
00541 if (enc_header != NULL) delete enc_header;
00542 if (dec_header != NULL) delete dec_header;
00543 throw;
00544 }
00545
00546 int retval = memcmp(ptr_dec_header->control,
00547 CONTROL_STR,
00548 HEADER_CONTROL_SIZE);
00549 delete enc_header;
00550 delete dec_header;
00551 if (retval != 0)
00552 throw YAPETInvalidPasswordException();
00553 }
00554
00577 File::File(const std::string& fn, const Key& key, bool create)
00578 throw(YAPETException) : filename(fn) {
00579 if (create)
00580 openCreate();
00581 else
00582 openNoCreate();
00583
00584 if (isempty()) {
00585 initFile(key);
00586 } else {
00587 validateKey(key);
00588 }
00589 }
00590
00594 File::File(const File& f) throw(YAPETException) {
00595 fd = dup(f.fd);
00596 if (fd == -1)
00597 throw YAPETException(strerror(errno));
00598
00599 filename = f.filename;
00600 mtime = f.mtime;
00601 }
00602
00606 File::~File() {
00607 close(fd);
00608 }
00609
00617 void
00618 File::save(std::list<PartDec>& records) throw(YAPETException) {
00619 preparePWSave();
00620 std::list<PartDec>::iterator it = records.begin();
00621 while (it != records.end() ) {
00622 write( it->getEncRecord());
00623 it++;
00624 }
00625 }
00626
00640 std::list<PartDec>
00641 File::read(const Key& key) const throw(YAPETException) {
00642 seekDataSection();
00643
00644 BDBuffer* buff = NULL;
00645 std::list<PartDec> retval;
00646
00647 try {
00648 buff = read();
00649 while (buff != NULL) {
00650 retval.push_back(PartDec(*buff, key));
00651 delete buff;
00652 buff = read();
00653 }
00654 } catch (YAPETException& ex) {
00655 if (buff != NULL)
00656 delete buff;
00657 throw;
00658 }
00659
00660 return retval;
00661 }
00662
00677 void
00678 File::setNewKey(const Key& oldkey,
00679 const Key& newkey) throw (YAPETException) {
00680 close(fd);
00681 std::string backupfilename(filename + ".bak");
00682 int retval = rename(filename.c_str(), backupfilename.c_str());
00683 if (retval == -1) {
00684
00685 openNoCreate();
00686 throw YAPETException(strerror(errno));
00687 }
00688
00689
00690 File* oldfile = NULL;
00691 try {
00692
00693 oldfile = new File(backupfilename, oldkey, false);
00694
00695 openCreate();
00696 initFile(newkey);
00697
00698
00699 std::list<PartDec> entries = oldfile->read(oldkey);
00700 std::list<PartDec>::iterator it = entries.begin();
00701 Crypt oldcrypt(oldkey);
00702 Crypt newcrypt(newkey);
00703 while (it != entries.end() ) {
00704 Record<PasswordRecord>* dec_rec_ptr = NULL;
00705 BDBuffer* new_enc_rec = NULL;
00706 try {
00707
00708 const BDBuffer old_enc_rec = (*it).getEncRecord();
00709 dec_rec_ptr =
00710 oldcrypt.decrypt<PasswordRecord>(old_enc_rec);
00711 new_enc_rec =
00712 newcrypt.encrypt(*dec_rec_ptr);
00713 write(*new_enc_rec);
00714 delete dec_rec_ptr;
00715 delete new_enc_rec;
00716 } catch (YAPETException& ex) {
00717 if (dec_rec_ptr != NULL)
00718 delete dec_rec_ptr;
00719 if (new_enc_rec != NULL)
00720 delete new_enc_rec;
00721 throw;
00722 }
00723 it++;
00724 }
00725 } catch (YAPETException& ex) {
00726 if (oldfile != NULL)
00727 delete oldfile;
00728 throw;
00729 }
00730 delete oldfile;
00731 }
00732
00741 time_t
00742 File::getMasterPWSet(const Key& key) const
00743 throw(YAPETException,YAPETInvalidPasswordException) {
00744 Crypt crypt(key);
00745 BDBuffer* enc_header = NULL;
00746 Record<FileHeader>* dec_header = NULL;
00747 FileHeader* ptr_dec_header = NULL;
00748
00749 try {
00750 enc_header = readHeader();
00751 dec_header = crypt.decrypt<FileHeader>(*enc_header);
00752 ptr_dec_header = *dec_header;
00753 } catch (YAPETEncryptionException& ex) {
00754 if (enc_header != NULL) delete enc_header;
00755 if (dec_header != NULL) delete dec_header;
00756 throw YAPETInvalidPasswordException();
00757 } catch (YAPETException& ex) {
00758 if (enc_header != NULL) delete enc_header;
00759 if (dec_header != NULL) delete dec_header;
00760 throw;
00761 }
00762
00763 time_t t = uint32_from_disk(ptr_dec_header->pwset);
00764 delete enc_header;
00765 delete dec_header;
00766
00767 return t;
00768 }
00769
00770
00771 const File&
00772 File::operator=(const File& f) throw(YAPETException) {
00773 if (this == &f) return *this;
00774
00775 close(fd);
00776
00777 fd = dup(f.fd);
00778 if (fd == -1)
00779 throw YAPETException(strerror(errno));
00780
00781 filename = f.filename;
00782
00783 return *this;
00784 }