@@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE. */
3838#include "htslib/kstring.h"
3939
4040#include <curl/curl.h>
41+ #include <regex.h>
4142
4243typedef struct {
4344 hFILE base ;
@@ -558,6 +559,100 @@ hFILE *hopen_libcurl(const char *url, const char *modes)
558559 return NULL ;
559560}
560561
562+
563+ struct MemoryStruct {
564+ char * memory ;
565+ size_t size ;
566+ };
567+
568+ static size_t WriteMemoryCallback (void * contents , size_t size , size_t nmemb , void * userp )
569+ {
570+ size_t realsize = size * nmemb ;
571+ struct MemoryStruct * mem = (struct MemoryStruct * )userp ;
572+
573+ mem -> memory = realloc (mem -> memory , mem -> size + realsize + 1 );
574+ if (mem -> memory == NULL )
575+ {
576+ return (size_t ) NULL ;
577+ }
578+
579+ memcpy (& (mem -> memory [mem -> size ]), contents , realsize );
580+ mem -> size += realsize ;
581+ mem -> memory [mem -> size ] = 0 ;
582+
583+ return realsize ;
584+ }
585+
586+ char * curl_as_string (char * url )
587+ {
588+ // Very simple function that given a URL, will return the response as a string, or NULL
589+
590+ struct MemoryStruct chunk ;
591+ chunk .memory = malloc (1 );
592+ chunk .size = 0 ;
593+ CURL * curl = curl_easy_init ();
594+
595+ if (!curl )
596+ {
597+ free (chunk .memory );
598+ return NULL ;
599+ }
600+
601+ char * role_name ;
602+ curl_easy_setopt (curl , CURLOPT_URL , url );
603+ curl_easy_setopt (curl , CURLOPT_WRITEFUNCTION , WriteMemoryCallback );
604+ curl_easy_setopt (curl , CURLOPT_WRITEDATA , (void * )& chunk );
605+ CURLcode res = curl_easy_perform (curl );
606+ if (res != CURLE_OK )
607+ {
608+ free (chunk .memory );
609+ curl_easy_cleanup (curl );
610+ return NULL ;
611+ }
612+ else
613+ {
614+ char * r_str = strdup (chunk .memory );
615+ int http_code = 0 ;
616+ curl_easy_getinfo (curl , CURLINFO_RESPONSE_CODE , & http_code );
617+ free (chunk .memory );
618+ curl_easy_cleanup (curl );
619+ if (http_code == 200 )
620+ {
621+ return r_str ;
622+ }
623+ else
624+ {
625+ return NULL ;
626+ }
627+ }
628+ }
629+
630+
631+ char * get_regex_group (char * regex_string , char * haystack )
632+ {
633+ regex_t regex_obj ;
634+
635+ regmatch_t secret_key_groups [2 ];
636+ regmatch_t groups [2 ];
637+
638+ regcomp (& regex_obj , regex_string , REG_NEWLINE |REG_EXTENDED );
639+
640+ if (regexec (& regex_obj , haystack , 2 , groups , 0 ) == 0 )
641+ {
642+ int g = 1 ;
643+ char sourceCopy [strlen (haystack ) + 1 ];
644+ strcpy (sourceCopy , haystack );
645+ sourceCopy [groups [g ].rm_eo ] = 0 ;
646+ return strdup (sourceCopy + groups [g ].rm_so );
647+ }
648+ else
649+ {
650+ return NULL ;
651+ }
652+ }
653+
654+
655+
561656int PLUGIN_GLOBAL (hfile_plugin_init ,_libcurl )(struct hFILE_plugin * self )
562657{
563658 static const struct hFILE_scheme_handler handler =
@@ -866,6 +961,45 @@ add_s3_settings(hFILE_libcurl *fp, const char *s3url, kstring_t *message)
866961 if (id .l == 0 )
867962 parse_simple ("~/.awssecret" , & id , & secret );
868963
964+ // If we fail to get credentials from all the above, then we attempt
965+ // to get the credential via IAM
966+ if (id .l == 0 )
967+ {
968+ char * aws_meta_url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/" ;
969+ char * role_name = curl_as_string (aws_meta_url );
970+ if (role_name )
971+ {
972+ // Append the IAM role name to the end of the aws_meta_url name
973+ char info_url [128 ];
974+ strcpy (info_url , aws_meta_url );
975+ strcat (info_url , role_name );
976+
977+ // Try and get the JSON object with the Metadata
978+ char * security_creds = curl_as_string (info_url );
979+
980+ if (security_creds )
981+ {
982+ // Here are three Regexes to pull out the tokens from the AWS APU
983+ char * access_key_id_regex_string = "\"AccessKeyId\".+?:.+?\"(.+?)\"" ;
984+ char * secret_access_key_regex_string = "\"SecretAccessKey\".+?:.+?\"(.+?)\"" ;
985+ char * token_regex_string = "\"Token\".+?:.+?\"(.+?)\"" ;
986+
987+ // Pull out the access key, secret, and token
988+ char * iam_key = get_regex_group (access_key_id_regex_string , security_creds );
989+ char * iam_secret = get_regex_group (secret_access_key_regex_string , security_creds );
990+ char * iam_token = get_regex_group (token_regex_string , security_creds );
991+
992+ // Only bother setting if all three exist
993+ if (iam_key && iam_secret && iam_token )
994+ {
995+ kputs (iam_key , & id );
996+ kputs (iam_secret , & secret );
997+ kputs (iam_token , & token );
998+ }
999+ }
1000+ }
1001+ }
1002+
8691003 if (token .l > 0 ) {
8701004 kputs ("x-amz-security-token:" , message );
8711005 kputs (token .s , message );
0 commit comments