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/ngc.h> /* KNgcObjRelease */
30
31 #include <klib/rc.h>
32 #include <klib/text.h>
33 #include <klib/printf.h>
34 #include <klib/data-buffer.h>
35 #include <klib/refcount.h>
36
37 #include <kfg/ngc.h>
38
39 #include <kfs/directory.h> /* KDirectoryOpenFileRead */
40 #include <kfs/file.h>
41 #include <kfs/subfile.h>
42 #include <kfs/gzip.h>
43
44 #include <strtol.h>
45
46 #include "kfg-priv.h" /* KConfigGetNgcFile */
47 #include "ngc-priv.h"
48
49 #include <string.h>
50 #include <sysalloc.h>
51
52
53 #define MIN_ENC_KEY_LEN 1
54 #define MAX_ENC_KEY_LEN 256
55 #define MIN_DNLD_TICKET_LEN 1
56 #define MAX_DNLD_TICKET_LEN 256
57 #define MIN_DESCRIPTION_LEN 1
58 #define MAX_DESCRIPTION_LEN 256
59
60
61 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
62 if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
63
64
KNgcObjWhack(KNgcObj * self)65 static rc_t KNgcObjWhack ( KNgcObj * self )
66 {
67 KDataBufferWhack ( & self-> buffer );
68 free( self );
69 return 0;
70 }
71
72
KNgcObjParseIdKeyTicketDesc(KNgcObj * self,uint32_t offset)73 static rc_t KNgcObjParseIdKeyTicketDesc ( KNgcObj * self, uint32_t offset )
74 {
75 rc_t rc = 0;
76 uint64_t i;
77 uint64_t l = ( self -> buffer . elem_count ) - offset;
78 uint8_t state;
79 const char * ptr = ( const char * ) self -> buffer . base;
80 String projectId;
81 String * dst = & projectId;
82
83 memset ( & projectId, 0, sizeof projectId );
84
85 ptr += offset;
86 dst -> addr = ptr;
87 for ( i = 0, state = 0; i < l && state < 4; i++ )
88 {
89 if ( ptr[ i ] == '|' )
90 {
91 dst -> size = dst -> len;
92 switch( state )
93 {
94 case 0 : dst = & self -> encryptionKey; break;
95 case 1 : dst = & self -> downloadTicket; break;
96 case 2 : dst = & self -> description; break;
97 }
98 state ++;
99 if ( state < 4 )
100 {
101 if ( i < ( l - 1 ) )
102 dst -> addr = &( ptr[ i + 1 ] );
103 }
104 }
105 else
106 {
107 ( dst -> len )++;
108 }
109 }
110 if ( projectId . addr == NULL ||
111 self -> encryptionKey . addr == NULL ||
112 self -> downloadTicket . addr == NULL ||
113 self -> description . addr == NULL )
114 {
115 rc = RC ( rcKFG, rcFile, rcParsing, rcParam, rcInvalid );
116 }
117 else if ( projectId . len < 1 ||
118 self -> encryptionKey . len < 1 ||
119 self -> downloadTicket . len < 1 ||
120 self -> description . len < 1 )
121 {
122 rc = RC ( rcKFG, rcFile, rcParsing, rcParam, rcInvalid );
123 }
124
125 /* the following tests may be version depended */
126
127 /* test to verify that the project ID is a valid Integer */
128 if ( rc == 0 )
129 {
130 char * end;
131 self -> projectId = strtou32 ( projectId . addr, & end, 10 );
132 if ( ( end - ( char* ) projectId . addr ) != projectId . size )
133 rc = RC ( rcKFG, rcFile, rcParsing, rcParam, rcInvalid );
134 }
135
136 /* test that the download ticket and the encKey do have a minimum and maximum length */
137 if ( rc == 0 )
138 {
139 if ( ( self -> downloadTicket . len < MIN_DNLD_TICKET_LEN ) ||
140 ( self -> downloadTicket . len > MAX_DNLD_TICKET_LEN ) )
141 rc = RC ( rcKFG, rcFile, rcParsing, rcParam, rcInvalid );
142 }
143
144 if ( rc == 0 )
145 {
146 if ( ( self -> encryptionKey . len < MIN_ENC_KEY_LEN ) ||
147 ( self -> encryptionKey . len > MAX_ENC_KEY_LEN ) )
148 rc = RC ( rcKFG, rcFile, rcParsing, rcParam, rcInvalid );
149 }
150
151 if ( rc == 0 )
152 {
153 if ( ( self -> description . len < MIN_DESCRIPTION_LEN ) ||
154 ( self -> description . len > MAX_DESCRIPTION_LEN ) )
155 rc = RC ( rcKFG, rcFile, rcParsing, rcParam, rcInvalid );
156 }
157
158 return rc;
159 }
160
161
KNgcParseUntilfound(const char * src,uint32_t l,const char * term,uint32_t term_count,String * dst)162 static bool KNgcParseUntilfound ( const char * src, uint32_t l, const char * term, uint32_t term_count, String * dst )
163 {
164 bool res = false;
165 uint32_t i;
166
167 dst -> addr = src;
168 for ( i = 0; i < l && !res; ++i )
169 {
170 char * found = string_chr ( term, term_count, src[ i ] );
171 res = ( found != NULL );
172 if ( !res )
173 ( dst -> len )++;
174 }
175 if ( res )
176 dst -> size = dst -> len;
177 else
178 dst -> size = dst -> len = 0;
179 return res;
180 }
181
182
KNgcObjParseBuffer(KNgcObj * self)183 static rc_t KNgcObjParseBuffer ( KNgcObj * self )
184 {
185 rc_t rc = 0;
186 uint32_t l = ( uint32_t ) self -> buffer . elem_count;
187 const char * ptr = ( const char * ) self -> buffer . base;
188
189 const char s_version[] = "version ";
190 const char s_v1_0[] = "1.0";
191
192 if ( ( size_t ) l != self -> buffer . elem_count )
193 l = INT32_MAX;
194
195 if ( string_cmp( s_version, sizeof s_version - 1, ptr, l, sizeof s_version - 1 ) != 0 )
196 rc = RC( rcKFG, rcFile, rcParsing, rcFormat, rcUnrecognized );
197 else if ( !KNgcParseUntilfound ( &( ptr[ 8 ] ), l - 8, "\n\r", 2, & self -> version ) )
198 rc = RC( rcKFG, rcFile, rcParsing, rcFormat, rcUnrecognized );
199
200 if ( rc == 0 )
201 {
202 if ( self -> version . len != 3 )
203 rc = RC( rcKFG, rcFile, rcParsing, rcFormat, rcUnrecognized );
204 else if ( string_cmp( s_v1_0, sizeof s_v1_0 - 1, self -> version . addr, sizeof s_v1_0 - 1, sizeof s_v1_0 - 1 ) != 0 )
205 rc = RC( rcKFG, rcFile, rcParsing, rcFormat, rcUnrecognized );
206 }
207
208 if ( rc == 0 )
209 {
210 uint32_t offset = sizeof s_version - 1 + ( self -> version . len ) + 1;
211 rc = KNgcObjParseIdKeyTicketDesc ( self, offset );
212 }
213 return rc;
214 }
215
216
KNgcObjInitFromString(KNgcObj * self,const char * line)217 static rc_t KNgcObjInitFromString ( KNgcObj * self, const char * line )
218 {
219 rc_t rc = 0;
220 uint32_t len = string_measure( line, NULL );
221 rc = KDataBufferResize ( &self -> buffer, len + 20 );
222 if ( rc == 0 )
223 {
224 size_t written;
225 rc = string_printf( self -> buffer . base, len + 20, &written, "version 1.0\n%s", line );
226 if ( rc == 0 )
227 {
228 self -> buffer . elem_count = written;
229 rc = KNgcObjParseBuffer ( self );
230 }
231 }
232 return rc;
233 }
234
235
KNgcObjInitFromFile(KNgcObj * self,const struct KFile * src)236 static rc_t KNgcObjInitFromFile ( KNgcObj * self, const struct KFile * src )
237 {
238 char hdr [ 8 ];
239 size_t num_read;
240 rc_t rc = KFileReadAll ( src, 0, hdr, sizeof hdr, & num_read );
241 if ( rc == 0 )
242 {
243 if ( num_read != sizeof hdr )
244 rc = RC( rcKFG, rcFile, rcReading, rcFile, rcWrongType );
245 else if ( memcmp( hdr, "ncbi_gap", sizeof hdr ) != 0 )
246 rc = RC( rcKFG, rcFile, rcReading, rcFile, rcWrongType );
247 else
248 {
249 uint64_t src_size;
250 rc = KFileSize ( src, & src_size );
251 if ( rc == 0 )
252 {
253 const struct KFile * sub;
254 rc = KFileMakeSubRead ( &sub, src, sizeof hdr, src_size - sizeof hdr );
255 if ( rc == 0 )
256 {
257 const struct KFile * gzip;
258 rc = KFileMakeGzipForRead ( & gzip, sub );
259 if ( rc == 0 )
260 {
261 size_t to_read = ( src_size * 10 );
262 /* guessing that the unzip version will not be bigger that 10 x the zipped one */
263 rc = KDataBufferResize ( & self -> buffer, to_read );
264 if ( rc == 0 )
265 {
266 size_t num_read;
267 rc = KFileReadAll ( gzip, 0, self -> buffer . base, to_read, & num_read );
268 if ( rc == 0 )
269 {
270 self -> buffer . elem_count = num_read;
271 rc = KNgcObjParseBuffer ( self );
272 }
273 }
274 KFileRelease ( gzip );
275 }
276 KFileRelease ( sub );
277 }
278 }
279 }
280 }
281 return rc;
282 }
283
284
KNgcObjMakeFromString(const KNgcObj ** ngc,const char * line)285 LIB_EXPORT rc_t CC KNgcObjMakeFromString ( const KNgcObj **ngc, const char * line )
286 {
287 rc_t rc;
288 if ( ngc == NULL || line == NULL )
289 rc = RC ( rcKFG, rcMgr, rcAllocating, rcParam, rcNull );
290 else
291 {
292 struct KNgcObj * f = calloc ( 1, sizeof * f );
293 if ( f == NULL )
294 rc = RC ( rcKFG, rcMgr, rcAllocating, rcMemory, rcExhausted );
295 else
296 {
297 KRefcountInit ( & f -> refcount, 1, "KNgcObj", "init", "kfg" );
298 memset ( & f -> buffer, 0, sizeof f -> buffer );
299 rc = KDataBufferMakeBytes ( & f -> buffer, 0 );
300 if ( rc == 0 )
301 {
302 rc = KNgcObjInitFromString( f, line );
303 if ( rc == 0 )
304 {
305 * ngc = f;
306 return rc;
307 }
308 }
309 KNgcObjWhack ( f );
310 }
311 * ngc = NULL;
312 }
313 return rc;
314 }
315
316
KNgcObjMakeFromFile(const KNgcObj ** ngc,const struct KFile * src)317 LIB_EXPORT rc_t CC KNgcObjMakeFromFile ( const KNgcObj **ngc, const struct KFile * src )
318 {
319 rc_t rc;
320 if ( ngc == NULL || src == NULL )
321 rc = RC ( rcKFG, rcFile, rcAllocating, rcParam, rcNull );
322 else
323 {
324 struct KNgcObj * f = calloc ( 1, sizeof * f );
325 if ( f == NULL )
326 rc = RC ( rcKFG, rcFile, rcAllocating, rcMemory, rcExhausted );
327 else
328 {
329 KRefcountInit ( & f -> refcount, 1, "KNgcObj", "init", "kfg" );
330 memset ( & f -> buffer, 0, sizeof f -> buffer );
331 rc = KDataBufferMakeBytes ( & f -> buffer, 0 );
332 if ( rc == 0 )
333 {
334 rc = KNgcObjInitFromFile( f, src );
335 if ( rc == 0 )
336 {
337 * ngc = f;
338 return rc;
339 }
340 }
341 KNgcObjWhack ( f );
342 }
343 * ngc = NULL;
344 }
345 return rc;
346 }
347
348
KNgcObjAddRef(const KNgcObj * self)349 LIB_EXPORT rc_t CC KNgcObjAddRef ( const KNgcObj *self )
350 {
351 if ( self != NULL )
352 {
353 switch ( KRefcountAdd( &self->refcount, "KNgcObj" ) )
354 {
355 case krefLimit:
356 return RC ( rcKFG, rcFile, rcAttaching, rcRefcount, rcExcessive );
357 case krefNegative:
358 return RC ( rcKFG, rcFile, rcAttaching, rcRefcount, rcInvalid );
359 }
360 }
361 return 0;
362 }
363
364
KNgcObjRelease(const KNgcObj * self)365 LIB_EXPORT rc_t CC KNgcObjRelease ( const KNgcObj *self )
366 {
367 if ( self != NULL )
368 {
369 switch ( KRefcountDrop ( & self -> refcount, "KNgcObj" ) )
370 {
371 case krefWhack:
372 return KNgcObjWhack ( ( KNgcObj * ) self );
373 case krefNegative:
374 return RC ( rcKFG, rcFile, rcReleasing, rcRefcount, rcInvalid );
375 }
376 }
377 return 0;
378 }
379
380
KNgcObjPrint(const KNgcObj * self,char * buffer,size_t buffer_size,size_t * written)381 LIB_EXPORT rc_t CC KNgcObjPrint ( const KNgcObj *self, char * buffer, size_t buffer_size, size_t * written )
382 {
383 rc_t rc = 0;
384 if ( self == NULL )
385 rc = RC ( rcKFG, rcFile, rcFormatting, rcSelf, rcNull );
386 else if ( buffer == NULL )
387 rc = RC ( rcKFG, rcFile, rcFormatting, rcParam, rcNull );
388 else
389 rc = string_printf( buffer, buffer_size, written,
390 "Vers: '%S', ID:'%u', Key:'%S', Ticket:'%S', Desc:'%S'",
391 &self -> version, self -> projectId, &self -> encryptionKey,
392 &self -> downloadTicket, &self -> description );
393 return rc;
394 }
395
396
KNgcObjWriteToFile(const KNgcObj * self,struct KFile * dst)397 LIB_EXPORT rc_t CC KNgcObjWriteToFile ( const KNgcObj *self, struct KFile * dst )
398 {
399 rc_t rc = 0;
400 if ( self == NULL )
401 rc = RC ( rcKFG, rcFile, rcWriting, rcSelf, rcNull );
402 else if ( dst == NULL )
403 rc = RC ( rcKFG, rcFile, rcWriting, rcParam, rcNull );
404 else
405 {
406 size_t written_to_hdr;
407 char hdr [ 10 ];
408 rc = string_printf( hdr, sizeof hdr, &written_to_hdr, "ncbi_gap" );
409 if ( rc == 0 )
410 {
411 size_t written_to_file;
412 rc = KFileWriteAll ( dst, 0, hdr, written_to_hdr, &written_to_file );
413 if ( rc == 0 && written_to_hdr == written_to_file )
414 {
415 struct KFile * sub;
416 rc = KFileMakeSubUpdate ( &sub, dst, written_to_file, 4096 );
417 if ( rc == 0 )
418 {
419 struct KFile * gzip;
420 rc = KFileMakeGzipForWrite ( &gzip, sub );
421 if ( rc == 0 )
422 {
423 size_t written_to_buffer;
424 char buffer[ 1024 ];
425 rc = string_printf( buffer, sizeof buffer, &written_to_buffer,
426 "version %S\n%u|%S|%S|%S",
427 &self -> version, self -> projectId, &self -> encryptionKey,
428 &self -> downloadTicket, &self -> description );
429 if ( rc == 0 )
430 {
431 size_t written_to_gzip;
432 rc = KFileWriteAll ( gzip, 0, buffer, written_to_buffer, &written_to_gzip );
433 }
434 KFileRelease ( gzip );
435 }
436 KFileRelease ( sub );
437 }
438 }
439 }
440 }
441 return rc;
442 }
443
444
KNgcObjWriteKeyToFile(const KNgcObj * self,struct KFile * dst)445 LIB_EXPORT rc_t CC KNgcObjWriteKeyToFile ( const KNgcObj *self, struct KFile * dst )
446 {
447 rc_t rc = 0;
448 if ( self == NULL )
449 rc = RC ( rcKFG, rcFile, rcWriting, rcSelf, rcNull );
450 else if ( dst == NULL )
451 rc = RC ( rcKFG, rcFile, rcWriting, rcParam, rcNull );
452 else if ( self -> encryptionKey . addr == NULL || self -> encryptionKey . len < 1 )
453 rc = RC ( rcKFG, rcFile, rcWriting, rcParam, rcInvalid );
454 else
455 {
456 size_t written_to_file;
457 rc = KFileWriteAll ( dst, 0, self -> encryptionKey . addr, self -> encryptionKey . len, &written_to_file );
458 }
459 return rc;
460 }
461
462
KNgcObjGetProjectId(const KNgcObj * self,uint32_t * id)463 LIB_EXPORT rc_t CC KNgcObjGetProjectId ( const KNgcObj *self, uint32_t * id )
464 {
465 rc_t rc;
466 if ( id == NULL )
467 rc = RC ( rcKFG, rcFile, rcFormatting, rcParam, rcNull );
468 else
469 {
470 if ( self == NULL )
471 rc = RC ( rcKFG, rcFile, rcFormatting, rcSelf, rcNull );
472 else
473 {
474 * id = self -> projectId;
475 return 0;
476 }
477
478 * id = 0;
479 }
480 return rc;
481 }
482
KNgcObjGetProjectName(const KNgcObj * self,char * buffer,size_t buffer_size,size_t * written)483 LIB_EXPORT rc_t CC KNgcObjGetProjectName ( const KNgcObj *self, char * buffer, size_t buffer_size, size_t * written )
484 {
485 rc_t rc = 0;
486 if ( self == NULL )
487 rc = RC ( rcKFG, rcFile, rcFormatting, rcSelf, rcNull );
488 else if ( buffer == NULL )
489 rc = RC ( rcKFG, rcFile, rcFormatting, rcParam, rcNull );
490 else
491 rc = string_printf( buffer, buffer_size, written, "dbGaP-%u", self -> projectId );
492 return rc;
493 }
494
KNgcObjGetTicket(const KNgcObj * self,char * buffer,size_t buffer_size,size_t * written)495 LIB_EXPORT rc_t CC KNgcObjGetTicket(const KNgcObj *self,
496 char * buffer, size_t buffer_size, size_t * written)
497 {
498 rc_t rc = 0;
499
500 if (self == NULL)
501 rc = RC(rcKFG, rcFile, rcFormatting, rcSelf, rcNull);
502 else if (buffer == NULL)
503 rc = RC(rcKFG, rcFile, rcFormatting, rcParam, rcNull);
504 else
505 rc = string_printf(buffer, buffer_size, written, "%S",
506 &self->downloadTicket);
507
508 return rc;
509 }
510
KNgcObjGetEncryptionKey(const KNgcObj * self,char * buffer,size_t buffer_size,size_t * written)511 rc_t KNgcObjGetEncryptionKey(const KNgcObj *self,
512 char * buffer, size_t buffer_size, size_t * written)
513 {
514 rc_t rc = 0;
515
516 if (self == NULL)
517 rc = RC(rcKFG, rcFile, rcFormatting, rcSelf, rcNull);
518 else if (buffer == NULL)
519 rc = RC(rcKFG, rcFile, rcFormatting, rcParam, rcNull);
520 else
521 rc = string_printf(buffer, buffer_size, written, "%S",
522 &self->encryptionKey);
523
524 return rc;
525 }
526
KNgcObjMakeFromCmdLine(const KNgcObj ** self)527 rc_t KNgcObjMakeFromCmdLine(const KNgcObj ** self) {
528 const char * ngc_file = NULL;
529
530 assert(self);
531
532 *self = NULL;
533
534 ngc_file = KConfigGetNgcFile();
535
536 if (ngc_file == NULL)
537 return 0;
538 else {
539 KDirectory * dir = NULL;
540 const KFile * f = NULL;
541
542 rc_t rc = KDirectoryNativeDir(&dir);
543
544 if (rc == 0)
545 rc = KDirectoryOpenFileRead(dir, &f, "%s", ngc_file);
546
547 if (rc == 0)
548 rc = KNgcObjMakeFromFile(self, f);
549
550 RELEASE(KFile, f);
551
552 RELEASE(KDirectory, dir);
553
554 return rc;
555 }
556 }
557