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 
28 #include <klib/text.h>
29 #include <klib/rc.h>
30 #include <klib/printf.h>
31 #include <kfs/file.h>
32 #include <kfs/directory.h>
33 
34 
35 #include <ctype.h>
36 #include <os-native.h>
37 #include <stdlib.h>
38 
39 #include <kfg/kfg-priv.h>
40 
41 static
aws_KConfigNodeUpdateChild(KConfigNode * self,String * name,String * value)42 rc_t aws_KConfigNodeUpdateChild ( KConfigNode *self, String *name, String *value )
43 {
44     KConfigNode * child;
45     rc_t rc = KConfigNodeOpenNodeUpdate ( self, & child, "%S", name );
46     if ( rc == 0 )
47     {
48         rc = KConfigNodeWrite ( child, value -> addr, value -> size );
49         KConfigNodeRelease ( child );
50     }
51 
52     return rc;
53 }
54 
55 static
aws_extract_key_value_pair(const String * source,String * key,String * val)56 rc_t aws_extract_key_value_pair ( const String *source, String *key, String *val )
57 {
58     String k, v;
59     const char *start = source -> addr;
60     const char *end = start + source -> size;
61 
62     char *eql = string_chr ( start, source -> size, '=' );
63     if ( eql == NULL )
64         return RC ( rcKFG, rcChar, rcSearching, rcFormat, rcInvalid );
65 
66     /* key */
67     StringInit ( &k, start, eql - start, string_len ( start, eql - start ) );
68     StringTrim ( &k, key );
69 
70     start = eql + 1;
71 
72     /* value */
73     StringInit ( &v, start, end - start,  string_len ( start, end - start ) );
74     StringTrim ( &v, val );
75     return 0;
76 }
77 
78 static
aws_parse_file(const KFile * self,KConfigNode * aws_node,char * buffer,size_t buf_size,bool isCredentialsFile)79 void aws_parse_file ( const KFile *self, KConfigNode *aws_node,
80                       char *buffer, size_t buf_size, bool isCredentialsFile )
81 {
82     char *sep;
83     const char *start = buffer;
84     const char *end = start + buf_size;
85 
86     for ( ; start < end; start = sep + 1 )
87     {
88         rc_t rc;
89         String string, trim;
90         String key, value;
91 
92         sep = string_chr ( start, end - start, '\n' );
93         if ( sep == NULL )
94             sep = ( char * ) end;
95 
96         StringInit ( &string, start, sep - start, string_len ( start, sep - start ) );
97 
98         StringTrim ( &string, &trim );
99 
100         /* check for comment line and skip */
101         if ( StringLength ( & trim ) != 0 && trim . addr [ 0 ] == '#' )
102             continue;
103 
104         /* check for [default] line */
105         if ( StringLength ( & trim ) != 0 && trim . addr [ 0 ] == '[' )
106             continue;
107 
108         /* check for key/value pairs and skip if none found */
109         rc = aws_extract_key_value_pair ( &trim, &key, &value );
110         if ( rc != 0 )
111             continue;
112 
113         /* now check keys we are looking for and populate the node*/
114         if ( isCredentialsFile )
115         {
116             String access_key_id, secret_access_key;
117             CONST_STRING ( &access_key_id, "aws_access_key_id" );
118             CONST_STRING ( &secret_access_key, "aws_secret_access_key" );
119 
120             if ( StringCaseEqual ( &key, &access_key_id ) )
121             {
122                 rc = aws_KConfigNodeUpdateChild ( aws_node, &key, &value );
123                 if ( rc != 0 )
124                     return;
125             }
126             if ( StringCaseEqual ( &key, &secret_access_key  ) )
127             {
128                 rc = aws_KConfigNodeUpdateChild ( aws_node, &key, &value );
129                 if ( rc != 0 )
130                     return;
131             }
132         }
133         else
134         {
135             String region, output;
136             CONST_STRING ( &region, "region" );
137             CONST_STRING ( &output, "output" );
138 
139             if ( StringCaseEqual ( &key, &region ) )
140             {
141                 rc = aws_KConfigNodeUpdateChild ( aws_node, &key, &value );
142                 if ( rc != 0 )
143                     return;
144             }
145             if ( StringCaseEqual ( &key, &output  ) )
146             {
147                 rc = aws_KConfigNodeUpdateChild ( aws_node, &key, &value );
148                 if ( rc != 0 )
149                     return;
150             }
151         }
152     }
153 }
154 
155 static
aws_find_nodes(KConfigNode * aws_node,const char * aws_path)156 rc_t aws_find_nodes ( KConfigNode *aws_node, const char *aws_path )
157 {
158     KDirectory *wd;
159 
160     rc_t rc = KDirectoryNativeDir ( &wd );
161     if ( rc == 0 )
162     {
163         char *buffer;
164         size_t num_read;
165         uint64_t buf_size;
166 
167         const KFile *credentials, *config;
168 
169         rc = KDirectoryOpenFileRead ( wd, &credentials, "%s%s", aws_path, "/credentials" );
170         if ( rc == 0 )
171         {
172             rc = KFileSize ( credentials, &buf_size );
173             if ( rc == 0 )
174             {
175                 buffer = malloc ( buf_size );
176                 if ( buffer != NULL )
177                 {
178                     rc = KFileReadAll ( credentials, 0, buffer, ( size_t ) buf_size, &num_read );
179 
180                     if ( rc == 0 )
181                         aws_parse_file ( credentials, aws_node, buffer, num_read, true );
182 
183                     free ( buffer );
184                 }
185 
186             }
187 
188             KFileRelease ( credentials );
189         }
190 
191         rc = KDirectoryOpenFileRead ( wd, &config, "%s%s", aws_path, "/config" );
192         if ( rc == 0 )
193         {
194             rc = KFileSize ( config, &buf_size );
195             if ( rc == 0 )
196             {
197                 buffer = malloc ( buf_size );
198                 if ( buffer != NULL )
199                 {
200                     rc = KFileReadAll ( config, 0, buffer, ( size_t ) buf_size, &num_read );
201 
202                     if ( rc == 0 )
203                         aws_parse_file ( config, aws_node, buffer, num_read, false );
204 
205                     free ( buffer );
206                 }
207             }
208 
209             KFileRelease ( config );
210         }
211 
212         KDirectoryRelease ( wd );
213     }
214 
215     return rc;
216 }
217 
218 
219 static
check_env(const KConfig * self,char * path,size_t path_size)220 void check_env ( const KConfig *self, char *path, size_t path_size )
221 {
222     size_t num_read;
223     const char *home;
224 
225     const KConfigNode *home_node;
226 
227     /* Check to see if home node exists */
228     rc_t rc = KConfigOpenNodeRead ( self, &home_node, "HOME" );
229     if ( home_node == NULL )
230     {
231         /* just grab the HOME env variable */
232         home = getenv ( "HOME" );
233         if ( home != NULL )
234         {
235             num_read = string_copy_measure ( path, path_size, home );
236             if ( num_read >= path_size )
237                 path [ 0 ] = 0;
238         }
239     }
240     else
241     {
242         /* if it exists check for a path */
243         rc = KConfigNodeRead ( home_node, 0, path, path_size, &num_read, NULL );
244         if ( rc != 0 )
245         {
246             home = getenv ( "HOME" );
247             if ( home != NULL )
248             {
249                 num_read = string_copy_measure ( path, path_size, home );
250                 if ( num_read >= path_size )
251                     path [ 0 ] = 0;
252             }
253 
254         }
255 
256         rc = KConfigNodeRelease ( home_node );
257     }
258 }
259 
260 extern
add_aws_nodes(KConfig * self)261 void add_aws_nodes ( KConfig *self )
262 {
263     char home [ 4096 ] = "";
264 
265     size_t num_writ;
266     char path [ 4096 ];
267     rc_t rc;
268 
269     check_env ( self, home, sizeof home );
270     /* if home environtment is found, create AWS root node */
271 
272     if ( home [ 0 ] != 0 )
273     {
274         rc = string_printf ( path, sizeof path, &num_writ, "%s/.aws", home );
275         if ( rc == 0 && num_writ != 0 )
276         {
277             KConfigNode *aws_node;
278 
279             /* create aws node */
280             rc = KConfigOpenNodeUpdate ( self, &aws_node, "AWS", NULL );
281             if ( rc == 0 )
282                 rc = aws_find_nodes ( aws_node, path );
283 
284             rc = KConfigNodeRelease ( aws_node );
285         }
286     }
287 }
288