PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/keyring_1_0+4/keyring/pack.c

#
C | 242 lines | 112 code | 44 blank | 86 comment | 11 complexity | d1906dfc912ac3f2bf5289274dc72d24 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* -*- c-file-style: "k&r"; -*-
  2. *
  3. * $Id: pack.c 350 2000-10-31 12:57:22Z mbp $
  4. *
  5. * GNU Keyring -- store passwords securely on a handheld
  6. * Copyright (C) 1999, 2000 Martin Pool <mbp@humbug.org.au>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. */
  22. /* XXX: It seems there is some kind of bug here in resizing
  23. * the record, but I don't know what it is yet.
  24. *
  25. * From the Programmer's Companion: ``To resize a record to
  26. * grow or shrink its contents, call DmResizeRecord. This
  27. * routine automatically reallocates the record in another
  28. * heap of the same card if the current heap does not have
  29. * enough space for it. Note that if the data manager needs to
  30. * move the record into another heap to resize it, the handle
  31. * to the record changes. DmResizeRecord returns the new
  32. * handle to the record.''
  33. *
  34. * ``May display a fatal error message if any of the following
  35. * occur: [] You don t have write access to the database. []
  36. * The index parameter is out of range. [] The record chunk is
  37. * locked.''
  38. *
  39. * Alternatively I wonder if something really strange is happening
  40. * here, like perhaps we're running out of heap or dynamic memory.
  41. * Certainly the encryption stuff might be a bit
  42. * memory-intensive.
  43. *
  44. * TODO: Check record is released before resizing.
  45. *
  46. * TODO: Better error checking that e.g. we're not running past the
  47. * end of the record. Display an error dialog rather than crashing.
  48. */
  49. #include <PalmOS.h>
  50. #include "keyring.h"
  51. #include "record.h"
  52. #include "pack.h"
  53. #include "crypto.h"
  54. #include "auto.h"
  55. #include "resource.h"
  56. #include "memutil.h"
  57. #include "dbutil.h"
  58. #include "keydb.h"
  59. #include "uiutil.h"
  60. #include "snib.h"
  61. static UInt32 packBodyLen, packRecLen;
  62. /*
  63. * Calculate and store into packRecLen and packBodyLen the amount of
  64. * database space this key will use.
  65. */
  66. void Keys_CalcPackedSize(UnpackedKeyType const *unpacked)
  67. {
  68. packBodyLen = unpacked->acctLen + 1
  69. + unpacked->passwdLen + 1
  70. + unpacked->notesLen + 1;
  71. if (packBodyLen & (kDESBlockSize-1))
  72. packBodyLen = (packBodyLen & ~(kDESBlockSize-1)) + kDESBlockSize;
  73. packRecLen = unpacked->nameLen + 1 + packBodyLen;
  74. }
  75. /*
  76. * Return a newly-allocated buffer containing a packed form of the
  77. * body of this key. The caller should encrypt and store it, then
  78. * free the buffer.
  79. */
  80. static char *Keys_PackBody(UnpackedKeyType const *u)
  81. {
  82. char *buf, *ptr;
  83. ptr = buf = MemPtrNew(packBodyLen);
  84. ErrFatalDisplayIf(!buf, "Not enough dynamic memory to encode record");
  85. Mem_CopyFromHandle(&ptr, u->acctHandle, u->acctLen+1);
  86. Mem_CopyFromHandle(&ptr, u->passwdHandle, u->passwdLen+1);
  87. Mem_CopyFromHandle(&ptr, u->notesHandle, u->notesLen+1);
  88. return buf;
  89. }
  90. /*
  91. * Encrypt and store an unpacked record into an open and locked
  92. * database record.
  93. */
  94. void Keys_WriteRecord(UnpackedKeyType const *unpacked, void *recPtr,
  95. UInt8 *cryptKey)
  96. {
  97. UInt32 off = 0;
  98. void *bodyBuf;
  99. DB_WriteStringFromHandle(recPtr, &off, unpacked->nameHandle,
  100. unpacked->nameLen + 1); /* NUL */
  101. bodyBuf = Keys_PackBody(unpacked);
  102. DES3_Write(recPtr, off, bodyBuf, packBodyLen, cryptKey);
  103. MemPtrFree(bodyBuf);
  104. }
  105. /*
  106. * Write just a single NUL to keep space for this record. It's not
  107. * marked dirty yet -- that'll happen when some real data is written
  108. * in.
  109. */
  110. Err KeyDB_CreateNew(UInt16 *idx)
  111. {
  112. MemHandle recHandle;
  113. Char *ptr;
  114. Err err;
  115. *idx = dmMaxRecordIndex;
  116. recHandle = DmNewRecord(gKeyDB, idx, 1);
  117. if (!recHandle)
  118. goto findErrOut;
  119. ptr = MemHandleLock(recHandle);
  120. if (!ptr)
  121. goto findErrOut;
  122. if ((err = DmWrite(ptr, 0, "", 1)))
  123. goto errOut;
  124. MemHandleUnlock(recHandle);
  125. /* XXX: I'm not sure if we should mark the record dirty at this
  126. * point or not. If we do, then it might be sync'd all the way
  127. * back to the PC even if it's never used. */
  128. if ((err = DmReleaseRecord(gKeyDB, *idx, true)))
  129. goto errOut;
  130. return 0;
  131. findErrOut:
  132. err = DmGetLastErr();
  133. errOut:
  134. UI_ReportSysError2(ID_KeyDatabaseAlert, err, __FUNCTION__);
  135. return err;
  136. }
  137. static MemHandle Keys_PrepareExisting(UInt16 *idx, Int16 recLen)
  138. {
  139. MemHandle recHandle;
  140. recHandle = DmResizeRecord(gKeyDB, *idx, recLen);
  141. if (!recHandle) {
  142. UI_ReportSysError2(ID_KeyDatabaseAlert, DmGetLastErr(),
  143. __FUNCTION__);
  144. return NULL;
  145. }
  146. return recHandle;
  147. }
  148. void Key_SetCategory(UInt16 idx, UInt16 category)
  149. {
  150. UInt16 attr;
  151. Err err;
  152. if ((err = DmRecordInfo(gKeyDB, idx, &attr, NULL, NULL)))
  153. goto fail;
  154. attr = (attr & ~dmRecAttrCategoryMask) | category;
  155. if ((err = DmSetRecordInfo(gKeyDB, idx, &attr, NULL)))
  156. goto fail;
  157. return;
  158. fail:
  159. UI_ReportSysError2(ID_KeyDatabaseAlert, err, __FUNCTION__);
  160. }
  161. /*
  162. * Basic procedure to save a record:
  163. *
  164. * setup record:
  165. * calculate the required record length
  166. * resize record to the required length
  167. * lock record
  168. * write plaintext name
  169. * write body:
  170. * allocate a temporary buffer equal to the encrypted-part length
  171. * write the unencoded form into the temporary buffer
  172. * allocate a temporary encryption buffer
  173. * one block at a time, encrypt and write into the database
  174. * release temporary buffer
  175. * unlock record
  176. * set record position
  177. */
  178. void Keys_SaveRecord(UnpackedKeyType const *unpacked, UInt16 *idx)
  179. {
  180. MemHandle recHandle;
  181. void *recPtr;
  182. Err err;
  183. Keys_CalcPackedSize(unpacked);
  184. ErrFatalDisplayIf(packRecLen > 8000,
  185. __FUNCTION__ ": immmoderate packRecLen"); /* paranoia */
  186. ErrNonFatalDisplayIf(idx == kNoRecord,
  187. __FUNCTION__ ": no record to save");
  188. ErrFatalDisplayIf(*idx > kMaxRecords, __FUNCTION__ ": outlandish idx");
  189. recHandle = Keys_PrepareExisting(idx, packRecLen);
  190. if (!recHandle)
  191. return;
  192. recPtr = MemHandleLock(recHandle);
  193. Keys_WriteRecord(unpacked, recPtr, g_Snib->recordKey);
  194. MemHandleUnlock(recHandle);
  195. err = DmReleaseRecord(gKeyDB, *idx, true);
  196. if (err)
  197. UI_ReportSysError2(ID_KeyDatabaseAlert, err, __FUNCTION__);
  198. }