@@ -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,97 @@ 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+ return NULL ;
598+ }
599+
600+ char * role_name ;
601+ curl_easy_setopt (curl , CURLOPT_URL , url );
602+ curl_easy_setopt (curl , CURLOPT_WRITEFUNCTION , WriteMemoryCallback );
603+ curl_easy_setopt (curl , CURLOPT_WRITEDATA , (void * )& chunk );
604+ CURLcode res = curl_easy_perform (curl );
605+ if (res != CURLE_OK )
606+ {
607+ return NULL ;
608+ }
609+ else
610+ {
611+ char * r_str = strdup (chunk .memory );
612+ int http_code = 0 ;
613+ curl_easy_getinfo (curl , CURLINFO_RESPONSE_CODE , & http_code );
614+ if (http_code == 200 )
615+ {
616+ free (chunk .memory );
617+ curl_easy_cleanup (curl );
618+ return r_str ;
619+ }
620+ else
621+ {
622+ return NULL ;
623+ }
624+ }
625+ }
626+
627+
628+ char * get_regex_group (char * regex_string , char * haystack )
629+ {
630+ regex_t regex_obj ;
631+
632+ regmatch_t secret_key_groups [2 ];
633+ regmatch_t groups [2 ];
634+
635+ regcomp (& regex_obj , regex_string , REG_NEWLINE |REG_EXTENDED );
636+
637+ if (regexec (& regex_obj , haystack , 2 , groups , 0 ) == 0 )
638+ {
639+ int g = 1 ;
640+ char sourceCopy [strlen (haystack ) + 1 ];
641+ strcpy (sourceCopy , haystack );
642+ sourceCopy [groups [g ].rm_eo ] = 0 ;
643+ return strdup (sourceCopy + groups [g ].rm_so );
644+ }
645+ else
646+ {
647+ return NULL ;
648+ }
649+ }
650+
651+
652+
561653int PLUGIN_GLOBAL (hfile_plugin_init ,_libcurl )(struct hFILE_plugin * self )
562654{
563655 static const struct hFILE_scheme_handler handler =
@@ -866,6 +958,45 @@ add_s3_settings(hFILE_libcurl *fp, const char *s3url, kstring_t *message)
866958 if (id .l == 0 )
867959 parse_simple ("~/.awssecret" , & id , & secret );
868960
961+ // If we fail to get credentials from all the above, then we attempt
962+ // to get the credential via IAM
963+ if (id .l == 0 )
964+ {
965+ char * aws_meta_url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/" ;
966+ char * role_name = curl_as_string (aws_meta_url );
967+ if (role_name )
968+ {
969+ // Append the IAM role name to the end of the aws_meta_url name
970+ char info_url [128 ];
971+ strcpy (info_url , aws_meta_url );
972+ strcat (info_url , role_name );
973+
974+ // Try and get the JSON object with the Metadata
975+ char * security_creds = curl_as_string (info_url );
976+
977+ if (security_creds )
978+ {
979+ // Here are three Regexes to pull out the tokens from the AWS APU
980+ char * access_key_id_regex_string = "\"AccessKeyId\".+?:.+?\"(.+?)\"" ;
981+ char * secret_access_key_regex_string = "\"SecretAccessKey\".+?:.+?\"(.+?)\"" ;
982+ char * token_regex_string = "\"Token\".+?:.+?\"(.+?)\"" ;
983+
984+ // Pull out the access key, secret, and token
985+ char * iam_key = get_regex_group (access_key_id_regex_string , security_creds );
986+ char * iam_secret = get_regex_group (secret_access_key_regex_string , security_creds );
987+ char * iam_token = get_regex_group (token_regex_string , security_creds );
988+
989+ // Only bother setting if all three exist
990+ if (iam_key && iam_secret && iam_token )
991+ {
992+ kputs (iam_key , & id );
993+ kputs (iam_secret , & secret );
994+ kputs (iam_token , & token );
995+ }
996+ }
997+ }
998+ }
999+
8691000 if (token .l > 0 ) {
8701001 kputs ("x-amz-security-token:" , message );
8711002 kputs (token .s , message );
0 commit comments