1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <kfg/extern.h>
28
29 #include <kfg/keystore-priv.h>
30
31 #include <klib/refcount.h>
32 #include <klib/rc.h>
33 #include <klib/text.h>
34 #include <klib/printf.h>
35
36 #include <kfg/config.h>
37 #include <kfg/repository.h>
38 #include <kfg/kfg-priv.h>
39
40 #include <kfs/directory.h>
41 #include <kfs/file.h>
42 #include <kfs/lockfile.h>
43 #include <kfs/nullfile.h>
44
45 #include <strtol.h>
46
47 #include <sysalloc.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #define PASSWORD_MAX_SIZE 4096
52 #define MAX_PATH_SIZE 4096
53
54 static char defaultBindingsFile[MAX_PATH_SIZE];
55
56 static rc_t KEncryptionKeyMakeFromFile(const char* path, KEncryptionKey** self);
57
58 /*
59 * Non-keyring implementation, using a combination of location-based and global keys
60 */
61
62 struct KKeyStore
63 {
64 KKeyStore_vt vt;
65 KRefcount refcount;
66
67 KEncryptionKey* temp_key; /* temp key provided by the client code*/
68
69 const KConfig* kfg;
70 char* bindingsFile;
71 };
72
73 static rc_t KKeyStoreWhack(KKeyStore* self);
74
75 static KKeyStore_vt_v1 v1 = {
76 1, 0,
77 KKeyStoreWhack,
78 KKeyStoreGetKey
79 };
80
KKeyStoreWhack(KKeyStore * self)81 rc_t KKeyStoreWhack(KKeyStore* self)
82 {
83 rc_t rc = KConfigRelease(self->kfg);
84 rc_t rc2 = KEncryptionKeyRelease(self->temp_key);
85 if (rc == 0)
86 rc = rc2;
87 if (self->bindingsFile != defaultBindingsFile)
88 free(self->bindingsFile);
89 free(self);
90 return rc;
91 }
92
KKeyStoreMake(KKeyStore ** self,KConfig * kfg)93 LIB_EXPORT rc_t CC KKeyStoreMake(KKeyStore** self, KConfig* kfg)
94 {
95 rc_t rc = 0;
96 KKeyStore* ret;
97
98 if ( self == NULL )
99 return RC ( rcKFG, rcStorage, rcCreating, rcSelf, rcNull );
100
101 *self = NULL;
102
103 ret = malloc(sizeof(*ret));
104 if (ret == NULL)
105 return RC ( rcKFG, rcStorage, rcCreating, rcMemory, rcExhausted );
106
107 ret -> vt . v1 = &v1;
108
109 KRefcountInit ( & ret -> refcount, 1, "KKeyStore", "init", "" );
110
111 ret->temp_key = NULL;
112 ret->bindingsFile = NULL;
113 ret->kfg = kfg;
114 if (kfg != NULL)
115 {
116 rc = KConfigAddRef(kfg);
117 if (rc == 0)
118 ret->kfg = kfg;
119 }
120 else
121 ret->kfg = NULL;
122
123 if (rc == 0)
124 *self = ret;
125 else
126 KKeyStoreWhack(ret);
127
128 return rc;
129 }
130
KKeyStoreAddRef(const KKeyStore * self)131 LIB_EXPORT rc_t CC KKeyStoreAddRef ( const KKeyStore *self )
132 {
133 if ( self != NULL )
134 {
135 switch ( KRefcountAdd ( & self -> refcount, "KKeyStore" ) )
136 {
137 case krefLimit:
138 return RC ( rcKFG, rcStorage, rcAttaching, rcRange, rcExcessive );
139 }
140 }
141 return 0;
142 }
143
KKeyStoreRelease(const KKeyStore * self)144 LIB_EXPORT rc_t CC KKeyStoreRelease ( const KKeyStore *self )
145 {
146 if ( self != NULL )
147 {
148 switch ( KRefcountDrop ( & self -> refcount, "KKeyStore" ) )
149 {
150 case krefWhack:
151 self -> vt . v1 -> destroy ( ( KKeyStore* ) self );
152 break;
153 case krefLimit:
154 return RC ( rcKFG, rcStorage, rcReleasing, rcRange, rcExcessive );
155 }
156 }
157 return 0;
158 }
159
160 /*
161 * the result is always 0-terminated
162 */
163 static
ReadEncKey(const KFile * file,char * buf,size_t bufsize)164 rc_t ReadEncKey(const KFile* file, char* buf, size_t bufsize)
165 {
166 /* at this point we are only getting the password from a
167 * file but in the future if we can get it from a pipe of
168 * some sort we can't count on the ReadAll to really know
169 * if we hit end of file and not just a pause in the
170 * streaming. VDB 3 / VFS/KFS 2 will have to fix this somehow
171 */
172 size_t readNum;
173 rc_t rc = KFileReadAll (file, 0, buf, bufsize - 1, &readNum);
174
175 if (rc == 0)
176 {
177 char * pc;
178
179 /* ensure buffer is NUL terminated */
180 buf [ readNum ] = 0;
181
182 /* -----
183 * trim back the contents of the file to
184 * a single ASCII/UTF-8 text line
185 * We actually only check for the two normal
186 * end of line characters so it could have other
187 * control characters...
188 */
189 pc = memchr ( buf, '\r', readNum );
190 if ( pc == NULL )
191 pc = memchr ( buf, '\n', readNum );
192 if (pc != NULL)
193 *pc = 0;
194
195 /* disallow a length of 0 */
196 if ( buf [ 0 ] == 0 )
197 rc = RC (rcKFG, rcEncryptionKey, rcRetrieving, rcSize, rcTooShort);
198 else if ( memcmp ( buf, "n/a", 4 ) == 0 )
199 {
200 /* download-only NGC file */
201 rc = RC ( rcKFG, rcEncryptionKey, rcRetrieving, rcEncryptionKey, rcNoPerm );
202 }
203 }
204 return rc;
205 }
206
KKeyStoreSetTemporaryKeyFromFile(KKeyStore * self,const struct KFile * file)207 LIB_EXPORT rc_t CC KKeyStoreSetTemporaryKeyFromFile(KKeyStore* self, const struct KFile* file)
208 {
209 rc_t rc;
210 char key[PASSWORD_MAX_SIZE + 1];
211
212 if ( self == NULL )
213 return RC ( rcKFG, rcEncryptionKey, rcRetrieving, rcSelf, rcNull );
214
215 if ( file == NULL )
216 {
217 rc = KEncryptionKeyRelease(self->temp_key);
218 self->temp_key = NULL;
219 }
220 else
221 {
222 rc = ReadEncKey(file, key, PASSWORD_MAX_SIZE);
223 if (rc == 0)
224 {
225 rc = KEncryptionKeyRelease(self->temp_key);
226 if ( rc == 0)
227 rc = KEncryptionKeyMake(key, &self->temp_key);
228 memset(key, 0, PASSWORD_MAX_SIZE); /* is this enough security? */
229 }
230 }
231
232 return rc;
233 }
234
235
KKeyStoreGetKeyInt(const KKeyStore * self,const char * obj_key,KEncryptionKey ** enc_key,bool by_project_id,uint32_t projectId)236 static rc_t CC KKeyStoreGetKeyInt(const KKeyStore* self, const char* obj_key,
237 KEncryptionKey** enc_key, bool by_project_id, uint32_t projectId)
238 {
239 rc_t rc = 0;
240
241 if ( self == NULL )
242 return RC ( rcKFG, rcEncryptionKey, rcRetrieving, rcSelf, rcNull );
243 if ( enc_key == NULL )
244 return RC ( rcKFG, rcEncryptionKey, rcRetrieving, rcParam, rcNull );
245
246 if (self->temp_key != NULL)
247 {
248 rc = KEncryptionKeyAddRef(self->temp_key);
249 if (rc == 0)
250 *enc_key = self->temp_key;
251 }
252 else
253 {
254 const char * env = getenv (ENV_KRYPTO_PWFILE);
255 if (env != NULL)
256 rc = KEncryptionKeyMakeFromFile(env, enc_key);
257 else
258 { /* try protected repository */
259 if ( self -> kfg == NULL )
260 rc = KConfigMake( (KConfig**) &(self -> kfg), NULL );
261 if ( rc == 0 )
262 {
263 rc_t rc2;
264 const KRepositoryMgr *rmgr;
265 rc = KConfigMakeRepositoryMgrRead ( self -> kfg, & rmgr );
266 if ( rc == 0 )
267 {
268 const KRepository *protected;
269 if (by_project_id) {
270 rc = KRepositoryMgrGetProtectedRepository
271 ( rmgr, projectId, & protected );
272 }
273 else {
274 rc = KRepositoryMgrCurrentProtectedRepository
275 ( rmgr, & protected );
276 }
277 if ( rc == 0 )
278 { /* in a protected area */
279 char path [ MAX_PATH_SIZE ];
280 rc = KRepositoryEncryptionKeyFile ( protected, path, sizeof(path), NULL );
281 if ( rc == 0 && path [ 0 ] != 0 )
282 rc = KEncryptionKeyMakeFromFile(path, enc_key);
283 else {
284 rc = KRepositoryEncryptionKey ( protected,
285 path, sizeof(path), NULL );
286 if ( rc == 0 )
287 rc = KEncryptionKeyMake ( path, enc_key );
288 }
289
290 rc2 = KRepositoryRelease ( protected );
291 if (rc == 0)
292 rc = rc2;
293 }
294 else /* use global password file */
295 {
296 String* path;
297 rc = KConfigReadString ( self -> kfg, KFG_KRYPTO_PWFILE, &path );
298 if (rc == 0)
299 {
300 rc = KEncryptionKeyMakeFromFile(path->addr, enc_key);
301 StringWhack(path);
302 }
303 else
304 rc = RC(rcKFG, rcEncryptionKey, rcRetrieving, rcItem, rcNotFound);
305 }
306 rc2 = KRepositoryMgrRelease ( rmgr );
307 if (rc == 0)
308 rc = rc2;
309 }
310 }
311 }
312 }
313 return rc;
314 }
315
KKeyStoreGetKey(const KKeyStore * self,const char * obj_key,KEncryptionKey ** enc_key)316 LIB_EXPORT rc_t CC KKeyStoreGetKey(const KKeyStore* self,
317 const char* obj_key, KEncryptionKey** enc_key)
318 {
319 return KKeyStoreGetKeyInt(self, obj_key, enc_key, false, 0);
320 }
321
KKeyStoreGetKeyByProjectId(const KKeyStore * self,const char * obj_key,KEncryptionKey ** enc_key,uint32_t projectId)322 LIB_EXPORT rc_t CC KKeyStoreGetKeyByProjectId(const KKeyStore* self,
323 const char* obj_key, KEncryptionKey** enc_key, uint32_t projectId)
324 {
325 return KKeyStoreGetKeyInt(self, obj_key, enc_key, true, projectId);
326 }
327
328
KKeyStoreSetConfig(struct KKeyStore * self,const struct KConfig * kfg)329 LIB_EXPORT rc_t CC KKeyStoreSetConfig(struct KKeyStore* self, const struct KConfig* kfg)
330 {
331 rc_t rc = 0;
332 if ( self == NULL )
333 return RC ( rcKFG, rcEncryptionKey, rcRetrieving, rcSelf, rcNull );
334
335 if ( kfg != NULL )
336 rc = KConfigAddRef(kfg);
337
338 if ( rc == 0 )
339 {
340 if ( self->kfg != NULL )
341 KConfigRelease(self->kfg);
342 self->kfg = kfg;
343 }
344
345 return rc;
346 }
347
348 /*
349 * KEncryptionKey
350 */
351
KEncryptionKeyAddRef(KEncryptionKey * self)352 LIB_EXPORT rc_t CC KEncryptionKeyAddRef ( KEncryptionKey *self )
353 {
354 if ( self != NULL )
355 {
356 switch ( KRefcountAdd ( & self -> refcount, "KEncryptionKey" ) )
357 {
358 case krefLimit:
359 return RC ( rcKFG, rcEncryptionKey, rcAttaching, rcRange, rcExcessive );
360 }
361 }
362 return 0;
363 }
364
KEncryptionKeyRelease(KEncryptionKey * self)365 LIB_EXPORT rc_t CC KEncryptionKeyRelease ( KEncryptionKey *self )
366 {
367 if ( self != NULL )
368 {
369 switch ( KRefcountDrop ( & self -> refcount, "KEncryptionKey" ) )
370 {
371 case krefWhack:
372 free((char*)self->value.addr); /*TODO: unlock memory? */
373 free(self);
374 break;
375 case krefLimit:
376 return RC ( rcKFG, rcEncryptionKey, rcReleasing, rcRange, rcExcessive );
377 }
378 }
379 return 0;
380 }
381
KEncryptionKeyMakeInt(const char * value,KEncryptionKey ** self)382 static rc_t KEncryptionKeyMakeInt(const char* value, KEncryptionKey** self)
383 {
384 KEncryptionKey* ret;
385
386 *self = NULL;
387
388 ret = malloc(sizeof(KEncryptionKey));
389 if (ret == NULL)
390 return RC ( rcKFG, rcEncryptionKey, rcCreating, rcMemory, rcExhausted );
391 else
392 {
393 /* VDB-3590: Encryption key is a sequence of bytes.
394 It is not a string and can represent an invalid UNICODE sequence */
395 size_t size = string_size (value);
396
397 char* data = malloc(size+1);/*TODO: place in protected memory*/
398 if (data == NULL)
399 {
400 free(ret);
401 return RC ( rcKFG, rcEncryptionKey, rcCreating, rcMemory, rcExhausted );
402 }
403
404 memmove(data, value, size);
405
406 StringInit( & ret -> value, data, size, (uint32_t)size ); /* do not include the 0-terminator */
407
408 KRefcountInit ( & ret -> refcount, 1, "KEncryptionKey", "init", "" );
409
410 *self = ret;
411 return 0;
412 }
413 }
414
KEncryptionKeyMake(const char * value,KEncryptionKey ** self)415 LIB_EXPORT rc_t CC KEncryptionKeyMake(const char* value, KEncryptionKey** self)
416 {
417 if ( value == NULL )
418 return RC ( rcKFG, rcEncryptionKey, rcCreating, rcParam, rcNull );
419 if ( self == NULL )
420 return RC ( rcKFG, rcEncryptionKey, rcCreating, rcSelf, rcNull );
421
422 return KEncryptionKeyMakeInt(value, self);
423 }
424
KEncryptionKeyMakeFromFile(const char * path,KEncryptionKey ** self)425 static rc_t KEncryptionKeyMakeFromFile(const char* path, KEncryptionKey** self)
426 {
427 rc_t rc;
428 KDirectory* wd;
429
430 if ( path == NULL )
431 return RC ( rcKFG, rcEncryptionKey, rcCreating, rcParam, rcNull );
432 if ( self == NULL )
433 return RC ( rcKFG, rcEncryptionKey, rcCreating, rcSelf, rcNull );
434
435 rc = KDirectoryNativeDir(&wd);
436 if (rc == 0)
437 {
438 rc_t rc2;
439 const KFile* file;
440 const char dev_stdin [] = "/dev/stdin";
441 const char dev_null [] = "/dev/null";
442
443 if (strcmp (dev_stdin, path) == 0)
444 rc = KFileMakeStdIn (&file);
445 else if (strcmp (dev_null, path) == 0)
446 rc = KFileMakeNullRead (&file);
447 else
448 rc = KDirectoryOpenFileRead(wd, &file, "%s", path);
449 if (rc == 0)
450 {
451 char key[PASSWORD_MAX_SIZE + 1];
452 rc = ReadEncKey(file, key, PASSWORD_MAX_SIZE);
453 if (rc == 0)
454 rc = KEncryptionKeyMakeInt(key, self);
455
456 rc2 = KFileRelease(file);
457 if (rc == 0)
458 rc = rc2;
459 }
460 rc2 = KDirectoryRelease(wd);
461 if (rc == 0)
462 rc = rc2;
463 }
464 return rc;
465 }
466
KKeyStoreSetBindingsFile(struct KKeyStore * self,const char * path)467 LIB_EXPORT rc_t CC KKeyStoreSetBindingsFile(struct KKeyStore* self, const char* path)
468 {
469 if ( self == NULL )
470 return RC ( rcKFG, rcStorage, rcInitializing, rcSelf, rcNull );
471
472 if (self->bindingsFile != defaultBindingsFile)
473 free(self->bindingsFile);
474 if (path == NULL)
475 self->bindingsFile = NULL;
476 else
477 {
478 self->bindingsFile = string_dup(path, string_size(path));
479 if (self->bindingsFile == NULL)
480 return RC ( rcKFG, rcStorage, rcInitializing, rcMemory, rcExhausted );
481 }
482 return 0;
483 }
484
KKeyStoreGetBindingsFile(const struct KKeyStore * self)485 LIB_EXPORT const char* KKeyStoreGetBindingsFile(const struct KKeyStore* self)
486 {
487 if ( self == NULL )
488 return NULL;
489
490 return self->bindingsFile;
491 }
492
493
494 #define MAX_OBJID_SIZE 20
495 #define MAX_NAME_SIZE 4096
496
LocateObjectId(const KFile * file,const char * key,char * value,size_t value_size,size_t * value_read)497 static rc_t LocateObjectId(const KFile* file, const char* key, char* value, size_t value_size, size_t* value_read)
498 {
499 char buf[MAX_OBJID_SIZE + 1 + MAX_NAME_SIZE + 1];
500 size_t num_read;
501 uint64_t pos = 0;
502 size_t key_size = string_size(key);
503 bool eof = false;
504 do
505 {
506 rc_t rc = KFileReadAll(file, pos, buf, sizeof(buf), &num_read);
507 if (rc != 0)
508 return rc;
509 else
510 {
511 size_t start;
512 if (num_read == sizeof(buf))
513 { /* locate the last incomplete line and ignore it; will be considered after the next read() */
514 while (num_read > 0)
515 {
516 --num_read;
517 if (buf[num_read] == '\r' || buf[num_read] == '\n')
518 break;
519 }
520 if (num_read == 0)
521 return RC ( rcVFS, rcMgr, rcReading, rcRow, rcTooLong);
522 }
523 else
524 eof = true;
525
526 start = 0;
527 while (start + key_size < num_read)
528 {
529 /* find the beginning of a line */
530 while (buf[start] == '\r' || buf[start] == '\n')
531 {
532 ++start;
533 if (start >= num_read)
534 break;
535 }
536 /* check the key */
537 if (string_cmp(key, key_size, buf + start, key_size, (uint32_t) ( num_read - start )) == 0)
538 {
539 if (buf [ start + key_size ] == '=')
540 {
541 size_t i = 0;
542 size_t sourceIdx = start + key_size + 1; /* 1st character after '=' */
543 while (sourceIdx < num_read)
544 {
545 if (i >= value_size)
546 return RC ( rcVFS, rcMgr, rcReading, rcName, rcTooLong);
547
548 if (buf[sourceIdx] == '\r' || buf[sourceIdx] == '\n')
549 break;
550
551 value[i] = buf[sourceIdx];
552
553 ++i;
554 ++sourceIdx;
555 }
556 *value_read = i;
557 return 0;
558 }
559 }
560
561 /* skip until the next end of line */
562 while (buf[start] != '\r' && buf[start] != '\n')
563 {
564 ++start;
565 if (start >= num_read)
566 break;
567 }
568 }
569
570 pos += num_read;
571 }
572 }
573 while (!eof);
574
575 return RC ( rcVFS, rcMgr, rcReading, rcId, rcNotFound );
576 }
577
578 /*
579 * Reverse lookup
580 */
LocateObject(const KFile * file,const char * value,const size_t value_size,char * key,size_t key_size,size_t * key_read)581 static rc_t LocateObject(const KFile* file, const char* value, const size_t value_size, char* key, size_t key_size, size_t* key_read)
582 {
583 char buf[MAX_OBJID_SIZE + 1 + MAX_NAME_SIZE + 1];
584 size_t num_read;
585 uint64_t pos = 0;
586 bool eof = false;
587 do
588 {
589 rc_t rc = KFileReadAll(file, pos, buf, sizeof(buf), &num_read);
590 if (rc != 0)
591 return rc;
592 else
593 {
594 size_t start;
595 if (num_read == sizeof(buf))
596 { /* locate the last incomplete line and ignore it; will be considered after the next read() */
597 while (num_read > 0)
598 {
599 --num_read;
600 if (buf[num_read] == '\r' || buf[num_read] == '\n')
601 break;
602 }
603 if (num_read == 0)
604 return RC ( rcVFS, rcMgr, rcReading, rcRow, rcTooLong);
605 }
606 else
607 eof = true;
608
609 start = 0;
610 while (start + value_size < num_read)
611 {
612 size_t key_start, key_end;
613 size_t value_start;
614
615 /* find the beginning of a line */
616 while (buf[start] == '\r' || buf[start] == '\n')
617 {
618 ++start;
619 if (start >= num_read)
620 break;
621 }
622 if (start >= num_read)
623 continue;
624
625 key_start = start;
626
627 /* find the separator */
628 while (buf[start] != '=')
629 {
630 if (buf[start] == '\r' || buf[start] == '\n') /* separator not found, ignore the line*/
631 break;
632
633 ++start;
634 if (start >= num_read)
635 break;
636 }
637 if (start >= num_read || buf[start] != '=')
638 continue;
639
640 key_end = start;
641
642 ++start; /* skip the separator */
643
644 value_start = start;
645 /* find the next end of line */
646 while (buf[start] != '\r' && buf[start] != '\n')
647 {
648 ++start;
649 if (start >= num_read)
650 break;
651 }
652
653 /* compare the value */
654 if (string_cmp(value, value_size, buf + value_start, start - value_start, (uint32_t) ( start - value_start )) == 0)
655 {
656 *key_read = key_end - key_start;
657 if (string_copy(key, key_size, buf + key_start, *key_read) != *key_read)
658 return RC ( rcVFS, rcMgr, rcReading, rcId, rcTooLong);
659 return 0;
660 }
661 }
662
663 pos += num_read;
664 }
665 }
666 while (!eof);
667
668 return RC ( rcVFS, rcMgr, rcReading, rcId, rcNotFound );
669 }
670
AppendObject(KFile * file,const char * name,const String * value)671 static rc_t AppendObject(KFile* file, const char* name, const String* value)
672 {
673 uint64_t size;
674 rc_t rc = KFileSize ( file, &size );
675 if (rc == 0)
676 {
677 char buf[MAX_OBJID_SIZE + 1 + MAX_NAME_SIZE + 1];
678 size_t num_writ;
679 rc = string_printf(buf, sizeof(buf), &num_writ, "%s=%S\n", name, value);
680 if (rc == 0)
681 rc = KFileWrite ( file, size, buf, num_writ, &num_writ );
682 }
683 return rc;
684 }
685
OpenBindingsFile(KKeyStore * self,const KFile ** ret)686 static rc_t OpenBindingsFile(KKeyStore* self, const KFile** ret)
687 {
688 rc_t rc = 0;
689 if (self->bindingsFile == NULL)
690 {
691 String* home;
692 if ( self->kfg == NULL )
693 rc = KConfigMake( (KConfig**) &(self -> kfg), NULL );
694 if (rc == 0)
695 {
696 if (KConfigReadString(self->kfg, "NCBI_HOME", &home) == 0 ||
697 KConfigReadString(self->kfg, "HOME", &home) == 0 ||
698 KConfigReadString(self->kfg, "USERPROFILE", &home) == 0 )
699 {
700 size_t num_writ;
701 rc = string_printf(defaultBindingsFile, sizeof(defaultBindingsFile), &num_writ, "%S/objid.mapping", home);
702 if (rc == 0)
703 self->bindingsFile = defaultBindingsFile;
704 StringWhack(home);
705 }
706 else
707 rc = RC ( rcVFS, rcMgr, rcOpening, rcEnvironment, rcNull );
708 }
709 }
710
711 if (rc == 0)
712 {
713 rc_t rc2;
714 KDirectory* wd;
715 rc = KDirectoryNativeDir (&wd);
716 if (rc == 0)
717 rc = KDirectoryOpenFileRead(wd, ret, "%s", self->bindingsFile);
718 else
719 *ret = NULL;
720
721 rc2 = KDirectoryRelease(wd);
722 if (rc == 0)
723 rc = rc2;
724 }
725 return rc;
726 }
727
KKeyStoreRegisterObject(struct KKeyStore * self,uint32_t oid,const struct String * newName)728 LIB_EXPORT rc_t CC KKeyStoreRegisterObject(struct KKeyStore* self, uint32_t oid, const struct String* newName)
729 {
730 rc_t rc = 0;
731 if ( self == NULL )
732 return RC ( rcKFG, rcStorage, rcInitializing, rcSelf, rcNull );
733 else if ( newName == NULL )
734 rc = RC ( rcKFG, rcStorage, rcInitializing, rcParam, rcNull );
735 else
736 {
737 char oidString[MAX_OBJID_SIZE];
738 size_t num_writ;
739 rc = string_printf(oidString, sizeof(oidString), &num_writ, "%d", oid);
740 if (rc == 0)
741 {
742 rc_t rc2;
743 const KFile* file;
744 char oldName[MAX_NAME_SIZE];
745 size_t num_read;
746
747 rc = OpenBindingsFile(self, &file);
748 if (rc == 0)
749 { /* see if already registered */
750 if (LocateObjectId(file, oidString, oldName, sizeof(oldName), &num_read) == 0 &&
751 string_cmp(oldName, num_read, newName->addr, newName->size, (uint32_t)newName->size) != 0)
752 rc = RC ( rcVFS, rcMgr, rcRegistering, rcId, rcExists );
753 rc2 = KFileRelease(file);
754 if (rc == 0)
755 rc = rc2;
756 }
757 else /* no bindings file; will create */
758 rc = 0;
759
760 if (rc == 0)
761 { /* not registered; lock the bindings file and append the binding */
762 KDirectory* wd;
763 rc = KDirectoryNativeDir (&wd);
764 if (rc == 0)
765 {
766 KFile* lockedFile;
767 /*TODO: loop until locking succeeds or times out */
768 rc = KDirectoryCreateExclusiveAccessFile(wd, &lockedFile, true, 0600, kcmOpen, "%s", self->bindingsFile);
769 if (rc == 0)
770 {
771 if (LocateObjectId(lockedFile, oidString, oldName, sizeof(oldName), &num_read) == 0)
772 { /* somebody inserted the binding before we locked - make sure their binding was the same */
773 if (string_cmp(oldName, num_read, newName->addr, newName->size, (uint32_t)newName->size) != 0)
774 rc = RC ( rcVFS, rcMgr, rcRegistering, rcId, rcExists );
775 }
776 else
777 rc = AppendObject(lockedFile, oidString, newName);
778
779 rc2 = KFileRelease(lockedFile);
780 if (rc == 0)
781 rc = rc2;
782 }
783 rc2 = KDirectoryRelease(wd);
784 if (rc == 0)
785 rc = rc2;
786 }
787 }
788 }
789 }
790 return rc;
791 }
792
VKKeyStoreGetObjectId(const struct KKeyStore * self,const struct String * name,uint32_t * oid)793 LIB_EXPORT rc_t CC VKKeyStoreGetObjectId(const struct KKeyStore* self, const struct String* name, uint32_t* oid)
794 {
795 rc_t rc = 0;
796 if ( self == NULL )
797 return RC ( rcKFG, rcStorage, rcRetrieving, rcSelf, rcNull );
798 else if ( oid == NULL )
799 rc = RC ( rcKFG, rcStorage, rcRetrieving, rcParam, rcNull );
800 else
801 {
802 const KFile* file;
803 rc = OpenBindingsFile((KKeyStore*)self, &file);
804 if (rc == 0)
805 {
806 rc_t rc2;
807 char id_buf[MAX_OBJID_SIZE+1];
808 size_t id_read;
809 if (LocateObject(file, name->addr, name->size, id_buf, MAX_OBJID_SIZE, &id_read) == 0)
810 {
811 char* endptr;
812 unsigned long int res;
813 id_buf[id_read] = 0;
814 res = strtou32(id_buf, &endptr, 10);
815 if (*endptr != 0)
816 rc = RC ( rcKFG, rcStorage, rcRetrieving, rcId, rcCorrupt);
817 else
818 *oid = (uint32_t)res;
819 }
820 else
821 rc = RC ( rcKFG, rcStorage, rcRetrieving, rcName, rcNotFound);
822
823 rc2 = KFileRelease(file);
824 if (rc == 0)
825 rc = rc2;
826 }
827 }
828 return rc;
829 }
830
KKeyStoreGetObjectName(const struct KKeyStore * self,uint32_t oid,const struct String ** result)831 LIB_EXPORT rc_t CC KKeyStoreGetObjectName(const struct KKeyStore* self, uint32_t oid, const struct String** result)
832 {
833 rc_t rc = 0;
834 if ( self == NULL )
835 return RC ( rcKFG, rcStorage, rcRetrieving, rcSelf, rcNull );
836 else if ( result == NULL )
837 rc = RC ( rcKFG, rcStorage, rcRetrieving, rcParam, rcNull );
838 else
839 {
840 char oidString[MAX_OBJID_SIZE];
841 size_t num_writ;
842 rc = string_printf(oidString, sizeof(oidString), &num_writ, "%d", oid);
843 if (rc == 0)
844 {
845 const KFile* file;
846
847 rc = OpenBindingsFile((KKeyStore*)self, &file);
848 if (rc == 0)
849 {
850 rc_t rc2;
851 char name[MAX_NAME_SIZE];
852 size_t num_read;
853 if (LocateObjectId(file, oidString, name, sizeof(name), &num_read) == 0)
854 {
855 String* res = (String*)malloc(sizeof(String) + num_read);
856 if (res != NULL)
857 {
858 string_copy((char*)res + sizeof(String), num_read, name, num_read);
859 StringInit(res, (char*)res + sizeof(String), num_read, (uint32_t)num_read);
860 *result = res;
861 }
862 else
863 rc = RC ( rcKFG, rcStorage, rcRetrieving, rcMemory, rcExhausted );
864 }
865 else
866 rc = RC ( rcKFG, rcStorage, rcRetrieving, rcId, rcNotFound);
867
868 rc2 = KFileRelease(file);
869 if (rc == 0)
870 rc = rc2;
871 }
872 }
873 }
874 return rc;
875 }
876
877