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