aws_imds_client.c 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/auth/aws_imds_client.h>
  6. #include <aws/auth/private/credentials_utils.h>
  7. #include <aws/common/clock.h>
  8. #include <aws/common/condition_variable.h>
  9. #include <aws/common/mutex.h>
  10. #include <aws/common/string.h>
  11. #include <aws/http/connection.h>
  12. #include <aws/http/request_response.h>
  13. #include <aws/http/status_code.h>
  14. #include <aws/io/channel_bootstrap.h>
  15. #include <aws/io/socket.h>
  16. #include <ctype.h>
  17. #include <aws/common/json.h>
  18. #if defined(_MSC_VER)
  19. # pragma warning(disable : 4204)
  20. # pragma warning(disable : 4232)
  21. #endif /* _MSC_VER */
  22. /* instance role credentials body response is currently ~ 1300 characters + name length */
  23. #define IMDS_RESPONSE_SIZE_INITIAL 2048
  24. #define IMDS_RESPONSE_TOKEN_SIZE_INITIAL 64
  25. #define IMDS_RESPONSE_SIZE_LIMIT 65535
  26. #define IMDS_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS 2
  27. #define IMDS_DEFAULT_RETRIES 1
  28. enum imds_token_state {
  29. AWS_IMDS_TS_INVALID,
  30. AWS_IMDS_TS_VALID,
  31. AWS_IMDS_TS_UPDATE_IN_PROGRESS,
  32. };
  33. enum imds_token_copy_result {
  34. /* Token is valid and copied to requester */
  35. AWS_IMDS_TCR_SUCCESS,
  36. /* Token is updating, so requester is added in waiting queue */
  37. AWS_IMDS_TCR_WAITING_IN_QUEUE,
  38. /* unexpected error,like mem allocation error */
  39. AWS_IMDS_TCR_UNEXPECTED_ERROR,
  40. };
  41. struct imds_token_query {
  42. struct aws_linked_list_node node;
  43. void *user_data;
  44. };
  45. struct aws_imds_client {
  46. struct aws_allocator *allocator;
  47. struct aws_http_connection_manager *connection_manager;
  48. struct aws_retry_strategy *retry_strategy;
  49. const struct aws_auth_http_system_vtable *function_table;
  50. struct aws_imds_client_shutdown_options shutdown_options;
  51. /* will be set to true by default, means using IMDS V2 */
  52. bool token_required;
  53. struct aws_byte_buf cached_token;
  54. enum imds_token_state token_state;
  55. struct aws_linked_list pending_queries;
  56. struct aws_mutex token_lock;
  57. struct aws_condition_variable token_signal;
  58. struct aws_atomic_var ref_count;
  59. };
  60. static void s_aws_imds_client_destroy(struct aws_imds_client *client) {
  61. if (!client) {
  62. return;
  63. }
  64. /**
  65. * s_aws_imds_client_destroy is only called after all in-flight requests are finished,
  66. * thus nothing is going to try and access retry_strategy again at this point.
  67. */
  68. aws_retry_strategy_release(client->retry_strategy);
  69. aws_condition_variable_clean_up(&client->token_signal);
  70. aws_mutex_clean_up(&client->token_lock);
  71. aws_byte_buf_clean_up(&client->cached_token);
  72. client->function_table->aws_http_connection_manager_release(client->connection_manager);
  73. /* freeing the client takes place in the shutdown callback below */
  74. }
  75. static void s_on_connection_manager_shutdown(void *user_data) {
  76. struct aws_imds_client *client = user_data;
  77. if (client && client->shutdown_options.shutdown_callback) {
  78. client->shutdown_options.shutdown_callback(client->shutdown_options.shutdown_user_data);
  79. }
  80. aws_mem_release(client->allocator, client);
  81. }
  82. void aws_imds_client_release(struct aws_imds_client *client) {
  83. if (!client) {
  84. return;
  85. }
  86. size_t old_value = aws_atomic_fetch_sub(&client->ref_count, 1);
  87. if (old_value == 1) {
  88. s_aws_imds_client_destroy(client);
  89. }
  90. }
  91. void aws_imds_client_acquire(struct aws_imds_client *client) {
  92. aws_atomic_fetch_add(&client->ref_count, 1);
  93. }
  94. struct aws_imds_client *aws_imds_client_new(
  95. struct aws_allocator *allocator,
  96. const struct aws_imds_client_options *options) {
  97. if (!options->bootstrap) {
  98. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Client bootstrap is required for querying IMDS");
  99. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  100. return NULL;
  101. }
  102. struct aws_imds_client *client = aws_mem_calloc(allocator, 1, sizeof(struct aws_imds_client));
  103. if (!client) {
  104. return NULL;
  105. }
  106. if (aws_mutex_init(&client->token_lock)) {
  107. goto on_error;
  108. }
  109. if (aws_condition_variable_init(&client->token_signal)) {
  110. goto on_error;
  111. }
  112. if (aws_byte_buf_init(&client->cached_token, allocator, IMDS_RESPONSE_TOKEN_SIZE_INITIAL)) {
  113. goto on_error;
  114. }
  115. aws_linked_list_init(&client->pending_queries);
  116. aws_atomic_store_int(&client->ref_count, 1);
  117. client->allocator = allocator;
  118. client->function_table =
  119. options->function_table ? options->function_table : g_aws_credentials_provider_http_function_table;
  120. client->token_required = options->imds_version == IMDS_PROTOCOL_V1 ? false : true;
  121. client->shutdown_options = options->shutdown_options;
  122. struct aws_socket_options socket_options;
  123. AWS_ZERO_STRUCT(socket_options);
  124. socket_options.type = AWS_SOCKET_STREAM;
  125. socket_options.domain = AWS_SOCKET_IPV4;
  126. socket_options.connect_timeout_ms = (uint32_t)aws_timestamp_convert(
  127. IMDS_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL);
  128. struct aws_http_connection_manager_options manager_options;
  129. AWS_ZERO_STRUCT(manager_options);
  130. manager_options.bootstrap = options->bootstrap;
  131. manager_options.initial_window_size = IMDS_RESPONSE_SIZE_LIMIT;
  132. manager_options.socket_options = &socket_options;
  133. manager_options.tls_connection_options = NULL;
  134. manager_options.host = aws_byte_cursor_from_c_str("169.254.169.254");
  135. manager_options.port = 80;
  136. manager_options.max_connections = 10;
  137. manager_options.shutdown_complete_callback = s_on_connection_manager_shutdown;
  138. manager_options.shutdown_complete_user_data = client;
  139. struct aws_http_connection_monitoring_options monitor_options;
  140. AWS_ZERO_STRUCT(monitor_options);
  141. monitor_options.allowable_throughput_failure_interval_seconds = 1;
  142. monitor_options.minimum_throughput_bytes_per_second = 1;
  143. manager_options.monitoring_options = &monitor_options;
  144. client->connection_manager = client->function_table->aws_http_connection_manager_new(allocator, &manager_options);
  145. if (!client->connection_manager) {
  146. goto on_error;
  147. }
  148. if (options->retry_strategy) {
  149. client->retry_strategy = options->retry_strategy;
  150. aws_retry_strategy_acquire(client->retry_strategy);
  151. } else {
  152. struct aws_exponential_backoff_retry_options retry_options = {
  153. .el_group = options->bootstrap->event_loop_group,
  154. .max_retries = IMDS_DEFAULT_RETRIES,
  155. };
  156. /* exponential backoff is plenty here. We're hitting a local endpoint and do not run the risk of bringing
  157. * down more than the local VM. */
  158. client->retry_strategy = aws_retry_strategy_new_exponential_backoff(allocator, &retry_options);
  159. }
  160. if (!client->retry_strategy) {
  161. goto on_error;
  162. }
  163. return client;
  164. on_error:
  165. s_aws_imds_client_destroy(client);
  166. return NULL;
  167. }
  168. /*
  169. * Tracking structure for each outstanding async query to an imds client
  170. */
  171. struct imds_user_data {
  172. /* immutable post-creation */
  173. struct aws_allocator *allocator;
  174. struct aws_imds_client *client;
  175. aws_imds_client_on_get_resource_callback_fn *original_callback;
  176. void *original_user_data;
  177. /* mutable */
  178. struct aws_http_connection *connection;
  179. struct aws_http_message *request;
  180. struct aws_byte_buf current_result;
  181. struct aws_byte_buf imds_token;
  182. struct aws_string *resource_path;
  183. struct aws_retry_token *retry_token;
  184. /*
  185. * initial value is copy of client->token_required,
  186. * will be adapted according to response.
  187. */
  188. bool imds_token_required;
  189. bool is_imds_token_request;
  190. int status_code;
  191. int error_code;
  192. struct aws_atomic_var ref_count;
  193. };
  194. static void s_user_data_destroy(struct imds_user_data *user_data) {
  195. if (user_data == NULL) {
  196. return;
  197. }
  198. struct aws_imds_client *client = user_data->client;
  199. if (user_data->connection) {
  200. client->function_table->aws_http_connection_manager_release_connection(
  201. client->connection_manager, user_data->connection);
  202. }
  203. aws_byte_buf_clean_up(&user_data->current_result);
  204. aws_byte_buf_clean_up(&user_data->imds_token);
  205. aws_string_destroy(user_data->resource_path);
  206. if (user_data->request) {
  207. aws_http_message_destroy(user_data->request);
  208. }
  209. aws_retry_token_release(user_data->retry_token);
  210. aws_imds_client_release(client);
  211. aws_mem_release(user_data->allocator, user_data);
  212. }
  213. static struct imds_user_data *s_user_data_new(
  214. struct aws_imds_client *client,
  215. struct aws_byte_cursor resource_path,
  216. aws_imds_client_on_get_resource_callback_fn *callback,
  217. void *user_data) {
  218. struct imds_user_data *wrapped_user_data = aws_mem_calloc(client->allocator, 1, sizeof(struct imds_user_data));
  219. if (!wrapped_user_data) {
  220. goto on_error;
  221. }
  222. wrapped_user_data->allocator = client->allocator;
  223. wrapped_user_data->client = client;
  224. aws_imds_client_acquire(client);
  225. wrapped_user_data->original_user_data = user_data;
  226. wrapped_user_data->original_callback = callback;
  227. if (aws_byte_buf_init(&wrapped_user_data->current_result, client->allocator, IMDS_RESPONSE_SIZE_INITIAL)) {
  228. goto on_error;
  229. }
  230. if (aws_byte_buf_init(&wrapped_user_data->imds_token, client->allocator, IMDS_RESPONSE_TOKEN_SIZE_INITIAL)) {
  231. goto on_error;
  232. }
  233. wrapped_user_data->resource_path =
  234. aws_string_new_from_array(client->allocator, resource_path.ptr, resource_path.len);
  235. if (!wrapped_user_data->resource_path) {
  236. goto on_error;
  237. }
  238. wrapped_user_data->imds_token_required = client->token_required;
  239. aws_atomic_store_int(&wrapped_user_data->ref_count, 1);
  240. return wrapped_user_data;
  241. on_error:
  242. s_user_data_destroy(wrapped_user_data);
  243. return NULL;
  244. }
  245. static void s_user_data_acquire(struct imds_user_data *user_data) {
  246. if (user_data == NULL) {
  247. return;
  248. }
  249. aws_atomic_fetch_add(&user_data->ref_count, 1);
  250. }
  251. static void s_user_data_release(struct imds_user_data *user_data) {
  252. if (!user_data) {
  253. return;
  254. }
  255. size_t old_value = aws_atomic_fetch_sub(&user_data->ref_count, 1);
  256. if (old_value == 1) {
  257. s_user_data_destroy(user_data);
  258. }
  259. }
  260. static void s_reset_scratch_user_data(struct imds_user_data *user_data) {
  261. user_data->current_result.len = 0;
  262. user_data->status_code = 0;
  263. if (user_data->request) {
  264. aws_http_message_destroy(user_data->request);
  265. user_data->request = NULL;
  266. }
  267. }
  268. static enum imds_token_copy_result s_copy_token_safely(struct imds_user_data *user_data);
  269. static void s_invalidate_cached_token_safely(struct imds_user_data *user_data);
  270. static bool s_update_token_safely(struct aws_imds_client *client, struct aws_byte_buf *token, bool token_required);
  271. static void s_query_complete(struct imds_user_data *user_data);
  272. static void s_on_acquire_connection(struct aws_http_connection *connection, int error_code, void *user_data);
  273. static void s_on_retry_token_acquired(struct aws_retry_strategy *, int, struct aws_retry_token *, void *);
  274. static int s_on_incoming_body_fn(struct aws_http_stream *stream, const struct aws_byte_cursor *data, void *user_data) {
  275. (void)stream;
  276. (void)data;
  277. struct imds_user_data *imds_user_data = user_data;
  278. struct aws_imds_client *client = imds_user_data->client;
  279. if (data->len + imds_user_data->current_result.len > IMDS_RESPONSE_SIZE_LIMIT) {
  280. client->function_table->aws_http_connection_close(imds_user_data->connection);
  281. AWS_LOGF_ERROR(
  282. AWS_LS_IMDS_CLIENT, "(id=%p) IMDS client query response exceeded maximum allowed length", (void *)client);
  283. return AWS_OP_ERR;
  284. }
  285. if (aws_byte_buf_append_dynamic(&imds_user_data->current_result, data)) {
  286. client->function_table->aws_http_connection_close(imds_user_data->connection);
  287. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "(id=%p) IMDS client query error appending response", (void *)client);
  288. return AWS_OP_ERR;
  289. }
  290. return AWS_OP_SUCCESS;
  291. }
  292. static int s_on_incoming_headers_fn(
  293. struct aws_http_stream *stream,
  294. enum aws_http_header_block header_block,
  295. const struct aws_http_header *header_array,
  296. size_t num_headers,
  297. void *user_data) {
  298. (void)header_array;
  299. (void)num_headers;
  300. if (header_block != AWS_HTTP_HEADER_BLOCK_MAIN) {
  301. return AWS_OP_SUCCESS;
  302. }
  303. struct imds_user_data *imds_user_data = user_data;
  304. struct aws_imds_client *client = imds_user_data->client;
  305. if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) {
  306. if (imds_user_data->status_code == 0) {
  307. if (client->function_table->aws_http_stream_get_incoming_response_status(
  308. stream, &imds_user_data->status_code)) {
  309. AWS_LOGF_ERROR(
  310. AWS_LS_IMDS_CLIENT, "(id=%p) IMDS client failed to get http status code", (void *)client);
  311. return AWS_OP_ERR;
  312. }
  313. AWS_LOGF_DEBUG(
  314. AWS_LS_IMDS_CLIENT,
  315. "(id=%p) IMDS client query received http status code %d for requester %p.",
  316. (void *)client,
  317. imds_user_data->status_code,
  318. user_data);
  319. }
  320. }
  321. return AWS_OP_SUCCESS;
  322. }
  323. AWS_STATIC_STRING_FROM_LITERAL(s_imds_accept_header, "Accept");
  324. AWS_STATIC_STRING_FROM_LITERAL(s_imds_accept_header_value, "*/*");
  325. AWS_STATIC_STRING_FROM_LITERAL(s_imds_user_agent_header, "User-Agent");
  326. AWS_STATIC_STRING_FROM_LITERAL(s_imds_user_agent_header_value, "aws-sdk-crt/aws-imds-client");
  327. AWS_STATIC_STRING_FROM_LITERAL(s_imds_h1_0_keep_alive_header, "Connection");
  328. AWS_STATIC_STRING_FROM_LITERAL(s_imds_h1_0_keep_alive_header_value, "keep-alive");
  329. AWS_STATIC_STRING_FROM_LITERAL(s_imds_token_resource_path, "/latest/api/token");
  330. AWS_STATIC_STRING_FROM_LITERAL(s_imds_token_ttl_header, "x-aws-ec2-metadata-token-ttl-seconds");
  331. AWS_STATIC_STRING_FROM_LITERAL(s_imds_token_header, "x-aws-ec2-metadata-token");
  332. AWS_STATIC_STRING_FROM_LITERAL(s_imds_token_ttl_default_value, "21600");
  333. static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data);
  334. static int s_make_imds_http_query(
  335. struct imds_user_data *user_data,
  336. const struct aws_byte_cursor *verb,
  337. const struct aws_byte_cursor *uri,
  338. const struct aws_http_header *headers,
  339. size_t header_count) {
  340. AWS_FATAL_ASSERT(user_data->connection);
  341. struct aws_imds_client *client = user_data->client;
  342. struct aws_http_stream *stream = NULL;
  343. struct aws_http_message *request = aws_http_message_new_request(user_data->allocator);
  344. if (request == NULL) {
  345. return AWS_OP_ERR;
  346. }
  347. if (headers && aws_http_message_add_header_array(request, headers, header_count)) {
  348. goto on_error;
  349. }
  350. struct aws_http_header accept_header = {
  351. .name = aws_byte_cursor_from_string(s_imds_accept_header),
  352. .value = aws_byte_cursor_from_string(s_imds_accept_header_value),
  353. };
  354. if (aws_http_message_add_header(request, accept_header)) {
  355. goto on_error;
  356. }
  357. struct aws_http_header user_agent_header = {
  358. .name = aws_byte_cursor_from_string(s_imds_user_agent_header),
  359. .value = aws_byte_cursor_from_string(s_imds_user_agent_header_value),
  360. };
  361. if (aws_http_message_add_header(request, user_agent_header)) {
  362. goto on_error;
  363. }
  364. struct aws_http_header keep_alive_header = {
  365. .name = aws_byte_cursor_from_string(s_imds_h1_0_keep_alive_header),
  366. .value = aws_byte_cursor_from_string(s_imds_h1_0_keep_alive_header_value),
  367. };
  368. if (aws_http_message_add_header(request, keep_alive_header)) {
  369. goto on_error;
  370. }
  371. if (aws_http_message_set_request_method(request, *verb)) {
  372. goto on_error;
  373. }
  374. if (aws_http_message_set_request_path(request, *uri)) {
  375. goto on_error;
  376. }
  377. user_data->request = request;
  378. struct aws_http_make_request_options request_options = {
  379. .self_size = sizeof(request_options),
  380. .on_response_headers = s_on_incoming_headers_fn,
  381. .on_response_header_block_done = NULL,
  382. .on_response_body = s_on_incoming_body_fn,
  383. .on_complete = s_on_stream_complete_fn,
  384. .user_data = user_data,
  385. .request = request,
  386. };
  387. /* for test with mocking http stack where make request finishes
  388. immediately and releases client before stream activate call */
  389. s_user_data_acquire(user_data);
  390. stream = client->function_table->aws_http_connection_make_request(user_data->connection, &request_options);
  391. if (!stream || client->function_table->aws_http_stream_activate(stream)) {
  392. goto on_error;
  393. }
  394. s_user_data_release(user_data);
  395. return AWS_OP_SUCCESS;
  396. on_error:
  397. user_data->client->function_table->aws_http_stream_release(stream);
  398. aws_http_message_destroy(request);
  399. user_data->request = NULL;
  400. s_user_data_release(user_data);
  401. return AWS_OP_ERR;
  402. }
  403. /*
  404. * Process the http response from the token put request.
  405. */
  406. static void s_client_on_token_response(struct imds_user_data *user_data) {
  407. /* Gets 400 means token is required but the request itself failed. */
  408. if (user_data->status_code == AWS_HTTP_STATUS_CODE_400_BAD_REQUEST) {
  409. s_update_token_safely(user_data->client, NULL, true);
  410. return;
  411. }
  412. /*
  413. * Other than that, if meets any error, then token is not required,
  414. * we should fall back to insecure request. Otherwise, we should use
  415. * token in following requests.
  416. */
  417. if (user_data->status_code != AWS_HTTP_STATUS_CODE_200_OK || user_data->current_result.len == 0) {
  418. s_update_token_safely(user_data->client, NULL, false);
  419. } else {
  420. struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(&(user_data->current_result));
  421. aws_byte_cursor_trim_pred(&cursor, aws_char_is_space);
  422. aws_byte_buf_reset(&user_data->imds_token, true /*zero contents*/);
  423. if (aws_byte_buf_append_and_update(&user_data->imds_token, &cursor)) {
  424. s_update_token_safely(user_data->client, NULL, true);
  425. return;
  426. }
  427. s_update_token_safely(user_data->client, cursor.len == 0 ? NULL : &user_data->imds_token, cursor.len != 0);
  428. }
  429. }
  430. static int s_client_start_query_token(struct aws_imds_client *client) {
  431. struct imds_user_data *user_data = s_user_data_new(client, aws_byte_cursor_from_c_str(""), NULL, (void *)client);
  432. if (!user_data) {
  433. AWS_LOGF_ERROR(
  434. AWS_LS_IMDS_CLIENT,
  435. "(id=%p) IMDS client failed to query token with error: %s.",
  436. (void *)client,
  437. aws_error_str(aws_last_error()));
  438. return AWS_OP_ERR;
  439. }
  440. user_data->is_imds_token_request = true;
  441. if (aws_retry_strategy_acquire_retry_token(
  442. client->retry_strategy, NULL, s_on_retry_token_acquired, user_data, 100)) {
  443. s_user_data_release(user_data);
  444. return AWS_OP_ERR;
  445. }
  446. return AWS_OP_SUCCESS;
  447. }
  448. /* Make an http request to put a ttl and hopefully get a token back. */
  449. static void s_client_do_query_token(struct imds_user_data *user_data) {
  450. /* start query token for imds client */
  451. struct aws_byte_cursor uri = aws_byte_cursor_from_string(s_imds_token_resource_path);
  452. struct aws_http_header token_ttl_header = {
  453. .name = aws_byte_cursor_from_string(s_imds_token_ttl_header),
  454. .value = aws_byte_cursor_from_string(s_imds_token_ttl_default_value),
  455. };
  456. struct aws_http_header headers[] = {
  457. token_ttl_header,
  458. };
  459. struct aws_byte_cursor verb = aws_byte_cursor_from_c_str("PUT");
  460. if (s_make_imds_http_query(user_data, &verb, &uri, headers, AWS_ARRAY_SIZE(headers))) {
  461. user_data->error_code = aws_last_error();
  462. if (user_data->error_code == AWS_ERROR_SUCCESS) {
  463. user_data->error_code = AWS_ERROR_UNKNOWN;
  464. }
  465. s_query_complete(user_data);
  466. }
  467. }
  468. /*
  469. * Make the http request to fetch the resource
  470. */
  471. static void s_do_query_resource(struct imds_user_data *user_data) {
  472. struct aws_http_header token_header = {
  473. .name = aws_byte_cursor_from_string(s_imds_token_header),
  474. .value = aws_byte_cursor_from_buf(&user_data->imds_token),
  475. };
  476. struct aws_http_header headers[] = {
  477. token_header,
  478. };
  479. size_t headers_count = 0;
  480. struct aws_http_header *headers_array_ptr = NULL;
  481. if (user_data->imds_token_required) {
  482. headers_count = 1;
  483. headers_array_ptr = headers;
  484. }
  485. struct aws_byte_cursor verb = aws_byte_cursor_from_c_str("GET");
  486. struct aws_byte_cursor path_cursor = aws_byte_cursor_from_string(user_data->resource_path);
  487. if (s_make_imds_http_query(user_data, &verb, &path_cursor, headers_array_ptr, headers_count)) {
  488. user_data->error_code = aws_last_error();
  489. if (user_data->error_code == AWS_ERROR_SUCCESS) {
  490. user_data->error_code = AWS_ERROR_UNKNOWN;
  491. }
  492. s_query_complete(user_data);
  493. }
  494. }
  495. int s_get_resource_async_with_imds_token(struct imds_user_data *user_data);
  496. static void s_query_complete(struct imds_user_data *user_data) {
  497. if (user_data->is_imds_token_request) {
  498. s_client_on_token_response(user_data);
  499. s_user_data_release(user_data);
  500. return;
  501. }
  502. /* In this case we fallback to the secure imds flow. */
  503. if (user_data->status_code == AWS_HTTP_STATUS_CODE_401_UNAUTHORIZED) {
  504. s_invalidate_cached_token_safely(user_data);
  505. s_reset_scratch_user_data(user_data);
  506. aws_retry_token_release(user_data->retry_token);
  507. if (s_get_resource_async_with_imds_token(user_data)) {
  508. s_user_data_release(user_data);
  509. }
  510. return;
  511. }
  512. user_data->original_callback(
  513. user_data->error_code ? NULL : &user_data->current_result,
  514. user_data->error_code,
  515. user_data->original_user_data);
  516. s_user_data_release(user_data);
  517. }
  518. static void s_on_acquire_connection(struct aws_http_connection *connection, int error_code, void *user_data) {
  519. struct imds_user_data *imds_user_data = user_data;
  520. imds_user_data->connection = connection;
  521. if (!connection) {
  522. AWS_LOGF_WARN(
  523. AWS_LS_IMDS_CLIENT,
  524. "id=%p: IMDS Client failed to acquire a connection, error code %d(%s)",
  525. (void *)imds_user_data->client,
  526. error_code,
  527. aws_error_str(error_code));
  528. imds_user_data->error_code = error_code;
  529. s_query_complete(imds_user_data);
  530. return;
  531. }
  532. if (imds_user_data->is_imds_token_request) {
  533. s_client_do_query_token(imds_user_data);
  534. } else {
  535. s_do_query_resource(imds_user_data);
  536. }
  537. }
  538. static void s_on_retry_ready(struct aws_retry_token *token, int error_code, void *user_data) {
  539. (void)token;
  540. struct imds_user_data *imds_user_data = user_data;
  541. struct aws_imds_client *client = imds_user_data->client;
  542. if (!error_code) {
  543. client->function_table->aws_http_connection_manager_acquire_connection(
  544. client->connection_manager, s_on_acquire_connection, user_data);
  545. } else {
  546. AWS_LOGF_WARN(
  547. AWS_LS_IMDS_CLIENT,
  548. "id=%p: IMDS Client failed to retry the request with error code %d(%s)",
  549. (void *)client,
  550. error_code,
  551. aws_error_str(error_code));
  552. imds_user_data->error_code = error_code;
  553. s_query_complete(imds_user_data);
  554. }
  555. }
  556. static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data) {
  557. struct imds_user_data *imds_user_data = user_data;
  558. struct aws_imds_client *client = imds_user_data->client;
  559. aws_http_message_destroy(imds_user_data->request);
  560. imds_user_data->request = NULL;
  561. imds_user_data->connection = NULL;
  562. struct aws_http_connection *connection = client->function_table->aws_http_stream_get_connection(stream);
  563. client->function_table->aws_http_stream_release(stream);
  564. client->function_table->aws_http_connection_manager_release_connection(client->connection_manager, connection);
  565. /* on encountering error, see if we could try again */
  566. if (error_code) {
  567. AWS_LOGF_WARN(
  568. AWS_LS_IMDS_CLIENT,
  569. "id=%p: Stream completed with error code %d(%s)",
  570. (void *)client,
  571. error_code,
  572. aws_error_str(error_code));
  573. if (!aws_retry_strategy_schedule_retry(
  574. imds_user_data->retry_token, AWS_RETRY_ERROR_TYPE_TRANSIENT, s_on_retry_ready, user_data)) {
  575. AWS_LOGF_DEBUG(
  576. AWS_LS_IMDS_CLIENT,
  577. "id=%p: Stream completed, retrying the last request on a new connection.",
  578. (void *)client);
  579. return;
  580. } else {
  581. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "id=%p: Stream completed, retries have been exhausted.", (void *)client);
  582. imds_user_data->error_code = error_code;
  583. }
  584. } else if (aws_retry_token_record_success(imds_user_data->retry_token)) {
  585. AWS_LOGF_ERROR(
  586. AWS_LS_IMDS_CLIENT,
  587. "id=%p: Error while recording successful retry: %s",
  588. (void *)client,
  589. aws_error_str(aws_last_error()));
  590. }
  591. s_query_complete(imds_user_data);
  592. }
  593. static void s_on_retry_token_acquired(
  594. struct aws_retry_strategy *strategy,
  595. int error_code,
  596. struct aws_retry_token *token,
  597. void *user_data) {
  598. (void)strategy;
  599. struct imds_user_data *imds_user_data = user_data;
  600. struct aws_imds_client *client = imds_user_data->client;
  601. if (!error_code) {
  602. AWS_LOGF_DEBUG(AWS_LS_IMDS_CLIENT, "id=%p: IMDS Client successfully acquired retry token.", (void *)client);
  603. imds_user_data->retry_token = token;
  604. client->function_table->aws_http_connection_manager_acquire_connection(
  605. client->connection_manager, s_on_acquire_connection, imds_user_data);
  606. } else {
  607. AWS_LOGF_WARN(
  608. AWS_LS_IMDS_CLIENT,
  609. "id=%p: IMDS Client failed to acquire retry token, error code %d(%s)",
  610. (void *)client,
  611. error_code,
  612. aws_error_str(error_code));
  613. imds_user_data->error_code = error_code;
  614. s_query_complete(imds_user_data);
  615. }
  616. }
  617. static void s_complete_pending_queries(
  618. struct aws_imds_client *client,
  619. struct aws_linked_list *queries,
  620. bool token_required,
  621. struct aws_byte_buf *token) {
  622. /* poll swapped out pending queries if there is any */
  623. while (!aws_linked_list_empty(queries)) {
  624. struct aws_linked_list_node *node = aws_linked_list_pop_back(queries);
  625. struct imds_token_query *query = AWS_CONTAINER_OF(node, struct imds_token_query, node);
  626. struct imds_user_data *requester = query->user_data;
  627. aws_mem_release(client->allocator, query);
  628. requester->imds_token_required = token_required;
  629. bool should_continue = true;
  630. if (token) {
  631. aws_byte_buf_reset(&requester->imds_token, true);
  632. struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(token);
  633. if (aws_byte_buf_append_dynamic(&requester->imds_token, &cursor)) {
  634. AWS_LOGF_ERROR(
  635. AWS_LS_IMDS_CLIENT,
  636. "(id=%p) IMDS client failed to copy IMDS token for requester %p.",
  637. (void *)client,
  638. (void *)requester);
  639. should_continue = false;
  640. }
  641. } else if (token_required) {
  642. should_continue = false;
  643. }
  644. if (should_continue && aws_retry_strategy_acquire_retry_token(
  645. client->retry_strategy, NULL, s_on_retry_token_acquired, requester, 100)) {
  646. AWS_LOGF_ERROR(
  647. AWS_LS_IMDS_CLIENT,
  648. "(id=%p) IMDS client failed to allocate retry token for requester %p to send resource request.",
  649. (void *)client,
  650. (void *)requester);
  651. should_continue = false;
  652. }
  653. if (!should_continue) {
  654. requester->error_code = aws_last_error();
  655. if (requester->error_code == AWS_ERROR_SUCCESS) {
  656. requester->error_code = AWS_ERROR_UNKNOWN;
  657. }
  658. s_query_complete(requester);
  659. }
  660. }
  661. }
  662. static enum imds_token_copy_result s_copy_token_safely(struct imds_user_data *user_data) {
  663. struct aws_imds_client *client = user_data->client;
  664. enum imds_token_copy_result ret = AWS_IMDS_TCR_UNEXPECTED_ERROR;
  665. struct aws_linked_list pending_queries;
  666. aws_linked_list_init(&pending_queries);
  667. aws_mutex_lock(&client->token_lock);
  668. if (client->token_state == AWS_IMDS_TS_VALID) {
  669. aws_byte_buf_reset(&user_data->imds_token, true);
  670. struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(&client->cached_token);
  671. if (aws_byte_buf_append_dynamic(&user_data->imds_token, &cursor)) {
  672. ret = AWS_IMDS_TCR_UNEXPECTED_ERROR;
  673. } else {
  674. ret = AWS_IMDS_TCR_SUCCESS;
  675. }
  676. } else {
  677. ret = AWS_IMDS_TCR_WAITING_IN_QUEUE;
  678. struct imds_token_query *query = aws_mem_calloc(client->allocator, 1, sizeof(struct imds_token_query));
  679. if (query != NULL) {
  680. query->user_data = user_data;
  681. aws_linked_list_push_back(&client->pending_queries, &query->node);
  682. } else {
  683. ret = AWS_IMDS_TCR_UNEXPECTED_ERROR;
  684. }
  685. if (client->token_state == AWS_IMDS_TS_INVALID) {
  686. if (s_client_start_query_token(client)) {
  687. ret = AWS_IMDS_TCR_UNEXPECTED_ERROR;
  688. aws_linked_list_swap_contents(&pending_queries, &client->pending_queries);
  689. } else {
  690. client->token_state = AWS_IMDS_TS_UPDATE_IN_PROGRESS;
  691. }
  692. }
  693. }
  694. aws_mutex_unlock(&client->token_lock);
  695. s_complete_pending_queries(client, &pending_queries, true, NULL);
  696. switch (ret) {
  697. case AWS_IMDS_TCR_SUCCESS:
  698. AWS_LOGF_DEBUG(
  699. AWS_LS_IMDS_CLIENT,
  700. "(id=%p) IMDS client copied token to requester %p successfully.",
  701. (void *)client,
  702. (void *)user_data);
  703. break;
  704. case AWS_IMDS_TCR_WAITING_IN_QUEUE:
  705. AWS_LOGF_DEBUG(
  706. AWS_LS_IMDS_CLIENT, "(id=%p) IMDS client's token is invalid and is now updating.", (void *)client);
  707. break;
  708. case AWS_IMDS_TCR_UNEXPECTED_ERROR:
  709. AWS_LOGF_DEBUG(
  710. AWS_LS_IMDS_CLIENT,
  711. "(id=%p) IMDS client encountered unexpected error when processing token query for requester %p, error: "
  712. "%s.",
  713. (void *)client,
  714. (void *)user_data,
  715. aws_error_str(aws_last_error()));
  716. break;
  717. }
  718. return ret;
  719. }
  720. static void s_invalidate_cached_token_safely(struct imds_user_data *user_data) {
  721. bool invalidated = false;
  722. struct aws_imds_client *client = user_data->client;
  723. aws_mutex_lock(&client->token_lock);
  724. if (aws_byte_buf_eq(&user_data->imds_token, &client->cached_token)) {
  725. client->token_state = AWS_IMDS_TS_INVALID;
  726. invalidated = true;
  727. }
  728. aws_mutex_unlock(&client->token_lock);
  729. if (invalidated) {
  730. AWS_LOGF_DEBUG(
  731. AWS_LS_IMDS_CLIENT,
  732. "(id=%p) IMDS client's cached token is set to be invalid by requester %p.",
  733. (void *)client,
  734. (void *)user_data);
  735. }
  736. }
  737. /**
  738. * Once a requseter returns from token request, it should call this function to unblock all other
  739. * waiting requesters. When the token parameter is NULL, means the token request failed. Now we need
  740. * a new requester to acquire the token again.
  741. */
  742. static bool s_update_token_safely(struct aws_imds_client *client, struct aws_byte_buf *token, bool token_required) {
  743. AWS_FATAL_ASSERT(client);
  744. bool updated = false;
  745. struct aws_linked_list pending_queries;
  746. aws_linked_list_init(&pending_queries);
  747. aws_mutex_lock(&client->token_lock);
  748. client->token_required = token_required;
  749. if (token) {
  750. aws_byte_buf_reset(&client->cached_token, true);
  751. struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(token);
  752. if (aws_byte_buf_append_dynamic(&client->cached_token, &cursor) == AWS_OP_SUCCESS) {
  753. client->token_state = AWS_IMDS_TS_VALID;
  754. updated = true;
  755. }
  756. } else {
  757. client->token_state = AWS_IMDS_TS_INVALID;
  758. }
  759. aws_linked_list_swap_contents(&pending_queries, &client->pending_queries);
  760. aws_mutex_unlock(&client->token_lock);
  761. s_complete_pending_queries(client, &pending_queries, token_required, token);
  762. if (updated) {
  763. AWS_LOGF_DEBUG(
  764. AWS_LS_IMDS_CLIENT, "(id=%p) IMDS client updated the cached token successfully.", (void *)client);
  765. } else {
  766. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "(id=%p) IMDS client failed to update the token from IMDS.", (void *)client);
  767. }
  768. return updated;
  769. }
  770. int s_get_resource_async_with_imds_token(struct imds_user_data *user_data) {
  771. enum imds_token_copy_result res = s_copy_token_safely(user_data);
  772. if (res == AWS_IMDS_TCR_UNEXPECTED_ERROR) {
  773. return AWS_OP_ERR;
  774. }
  775. if (res == AWS_IMDS_TCR_WAITING_IN_QUEUE) {
  776. return AWS_OP_SUCCESS;
  777. }
  778. if (aws_retry_strategy_acquire_retry_token(
  779. user_data->client->retry_strategy, NULL, s_on_retry_token_acquired, user_data, 100)) {
  780. return AWS_OP_ERR;
  781. }
  782. return AWS_OP_SUCCESS;
  783. }
  784. int aws_imds_client_get_resource_async(
  785. struct aws_imds_client *client,
  786. struct aws_byte_cursor resource_path,
  787. aws_imds_client_on_get_resource_callback_fn callback,
  788. void *user_data) {
  789. struct imds_user_data *wrapped_user_data = s_user_data_new(client, resource_path, callback, user_data);
  790. if (wrapped_user_data == NULL) {
  791. goto error;
  792. }
  793. if (!wrapped_user_data->imds_token_required) {
  794. if (aws_retry_strategy_acquire_retry_token(
  795. client->retry_strategy, NULL, s_on_retry_token_acquired, wrapped_user_data, 100)) {
  796. goto error;
  797. }
  798. } else if (s_get_resource_async_with_imds_token(wrapped_user_data)) {
  799. goto error;
  800. }
  801. return AWS_OP_SUCCESS;
  802. error:
  803. s_user_data_release(wrapped_user_data);
  804. return AWS_OP_ERR;
  805. }
  806. /**
  807. * Higher level API definitions to get specific IMDS info
  808. * Reference:
  809. * https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html
  810. * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/util/EC2MetadataUtils.html
  811. * https://github.com/aws/aws-sdk-java-v2/blob/25f640c3b4f2e339c93a7da1494ab3310e128248/core/regions/src/main/java/software/amazon/awssdk/regions/internal/util/EC2MetadataUtils.java
  812. * IMDS client only implements resource acquisition that needs one resource request.
  813. * Complicated resource like network interface information defined in Java V2 SDK is not implemented here.
  814. * To get a full map of network interface information, we need more than ten requests, but sometimes we only care about
  815. * one or two of them.
  816. */
  817. static struct aws_byte_cursor s_instance_identity_document =
  818. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("instance-identity/document");
  819. static struct aws_byte_cursor s_instance_identity_signature =
  820. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("instance-identity/signature");
  821. static struct aws_byte_cursor s_ec2_metadata_root = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/latest/meta-data");
  822. static struct aws_byte_cursor s_ec2_credentials_root =
  823. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/latest/meta-data/iam/security-credentials/");
  824. static struct aws_byte_cursor s_ec2_userdata_root = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/latest/user-data/");
  825. static struct aws_byte_cursor s_ec2_dynamicdata_root = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/latest/dynamic/");
  826. struct imds_get_array_user_data {
  827. struct aws_allocator *allocator;
  828. aws_imds_client_on_get_array_callback_fn *callback;
  829. void *user_data;
  830. };
  831. struct imds_get_credentials_user_data {
  832. struct aws_allocator *allocator;
  833. aws_imds_client_on_get_credentials_callback_fn *callback;
  834. void *user_data;
  835. };
  836. struct imds_get_iam_user_data {
  837. struct aws_allocator *allocator;
  838. aws_imds_client_on_get_iam_profile_callback_fn *callback;
  839. void *user_data;
  840. };
  841. struct imds_get_instance_user_data {
  842. struct aws_allocator *allocator;
  843. aws_imds_client_on_get_instance_info_callback_fn *callback;
  844. void *user_data;
  845. };
  846. static void s_process_array_resource(const struct aws_byte_buf *resource, int error_code, void *user_data) {
  847. struct imds_get_array_user_data *wrapped_user_data = user_data;
  848. struct aws_array_list resource_array;
  849. AWS_ZERO_STRUCT(resource_array);
  850. if (resource && !error_code) {
  851. struct aws_byte_cursor resource_cursor = aws_byte_cursor_from_buf(resource);
  852. if (aws_array_list_init_dynamic(
  853. &resource_array, wrapped_user_data->allocator, 10, sizeof(struct aws_byte_cursor))) {
  854. goto on_finish;
  855. }
  856. aws_byte_cursor_split_on_char(&resource_cursor, '\n', &resource_array);
  857. }
  858. on_finish:
  859. wrapped_user_data->callback(&resource_array, error_code, wrapped_user_data->user_data);
  860. aws_array_list_clean_up_secure(&resource_array);
  861. aws_mem_release(wrapped_user_data->allocator, wrapped_user_data);
  862. }
  863. static void s_process_credentials_resource(const struct aws_byte_buf *resource, int error_code, void *user_data) {
  864. struct imds_get_credentials_user_data *wrapped_user_data = user_data;
  865. struct aws_credentials *credentials = NULL;
  866. struct aws_byte_buf json_data;
  867. AWS_ZERO_STRUCT(json_data);
  868. if (!resource || error_code) {
  869. goto on_finish;
  870. }
  871. if (aws_byte_buf_init_copy(&json_data, wrapped_user_data->allocator, resource)) {
  872. goto on_finish;
  873. }
  874. if (aws_byte_buf_append_null_terminator(&json_data)) {
  875. goto on_finish;
  876. }
  877. struct aws_parse_credentials_from_json_doc_options parse_options = {
  878. .access_key_id_name = "AccessKeyId",
  879. .secret_access_key_name = "SecretAccessKey",
  880. .token_name = "Token",
  881. .expiration_name = "Expiration",
  882. .token_required = true,
  883. .expiration_required = true,
  884. };
  885. credentials = aws_parse_credentials_from_json_document(
  886. wrapped_user_data->allocator, (const char *)json_data.buffer, &parse_options);
  887. on_finish:
  888. wrapped_user_data->callback(credentials, error_code, wrapped_user_data->user_data);
  889. aws_credentials_release(credentials);
  890. aws_byte_buf_clean_up_secure(&json_data);
  891. aws_mem_release(wrapped_user_data->allocator, wrapped_user_data);
  892. }
  893. /**
  894. * {
  895. "LastUpdated" : "2020-06-03T20:42:19Z",
  896. "InstanceProfileArn" : "arn:aws:iam::030535792909:instance-profile/CloudWatchAgentServerRole",
  897. "InstanceProfileId" : "AIPAQOHATHEGTGNQ5THQB"
  898. }
  899. */
  900. static int s_parse_iam_profile(struct aws_json_value *document_root, struct aws_imds_iam_profile *dest) {
  901. bool success = false;
  902. struct aws_byte_cursor last_updated_cursor;
  903. struct aws_json_value *last_updated =
  904. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("LastUpdated"));
  905. if (last_updated == NULL) {
  906. last_updated = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("lastupdated"));
  907. }
  908. if (!aws_json_value_is_string(last_updated) ||
  909. (aws_json_value_get_string(last_updated, &last_updated_cursor) == AWS_OP_ERR)) {
  910. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse LastUpdated from Json document for iam profile.");
  911. goto done;
  912. }
  913. struct aws_byte_cursor profile_arn_cursor;
  914. struct aws_json_value *profile_arn =
  915. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("InstanceProfileArn"));
  916. if (profile_arn == NULL) {
  917. profile_arn = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("instanceprofilearn"));
  918. }
  919. if (!aws_json_value_is_string(profile_arn) ||
  920. (aws_json_value_get_string(profile_arn, &profile_arn_cursor) == AWS_OP_ERR)) {
  921. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse InstanceProfileArn from Json document for iam profile.");
  922. goto done;
  923. }
  924. struct aws_byte_cursor profile_id_cursor;
  925. struct aws_json_value *profile_id =
  926. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("InstanceProfileId"));
  927. if (profile_id == NULL) {
  928. profile_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("instanceprofileid"));
  929. }
  930. if (!aws_json_value_is_string(profile_id) ||
  931. (aws_json_value_get_string(profile_id, &profile_id_cursor) == AWS_OP_ERR)) {
  932. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse InstanceProfileId from Json document for iam profile.");
  933. goto done;
  934. }
  935. if (last_updated_cursor.len == 0 || profile_arn_cursor.len == 0 || profile_id_cursor.len == 0) {
  936. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Parsed an unexpected Json document fro iam profile.");
  937. goto done;
  938. }
  939. if (aws_date_time_init_from_str_cursor(&dest->last_updated, &last_updated_cursor, AWS_DATE_FORMAT_ISO_8601)) {
  940. AWS_LOGF_ERROR(
  941. AWS_LS_IMDS_CLIENT, "LastUpdate in iam profile Json document is not a valid ISO_8601 date string.");
  942. goto done;
  943. }
  944. dest->instance_profile_arn = profile_arn_cursor;
  945. dest->instance_profile_id = profile_id_cursor;
  946. success = true;
  947. done:
  948. return success ? AWS_OP_ERR : AWS_OP_SUCCESS;
  949. }
  950. static void s_process_iam_profile(const struct aws_byte_buf *resource, int error_code, void *user_data) {
  951. struct imds_get_iam_user_data *wrapped_user_data = user_data;
  952. struct aws_json_value *document_root = NULL;
  953. struct aws_imds_iam_profile iam;
  954. AWS_ZERO_STRUCT(iam);
  955. struct aws_byte_buf json_data;
  956. AWS_ZERO_STRUCT(json_data);
  957. if (!resource || error_code) {
  958. goto on_finish;
  959. }
  960. if (aws_byte_buf_init_copy(&json_data, wrapped_user_data->allocator, resource)) {
  961. goto on_finish;
  962. }
  963. if (aws_byte_buf_append_null_terminator(&json_data)) {
  964. goto on_finish;
  965. }
  966. struct aws_byte_cursor json_data_cursor = aws_byte_cursor_from_buf(&json_data);
  967. document_root = aws_json_value_new_from_string(aws_default_allocator(), json_data_cursor);
  968. if (document_root == NULL) {
  969. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse document as Json document for iam profile.");
  970. goto on_finish;
  971. }
  972. if (s_parse_iam_profile(document_root, &iam)) {
  973. goto on_finish;
  974. }
  975. on_finish:
  976. wrapped_user_data->callback(&iam, error_code, wrapped_user_data->user_data);
  977. aws_byte_buf_clean_up_secure(&json_data);
  978. aws_mem_release(wrapped_user_data->allocator, wrapped_user_data);
  979. if (document_root != NULL) {
  980. aws_json_value_destroy(document_root);
  981. }
  982. }
  983. /**
  984. * {
  985. "accountId" : "030535792909",
  986. "architecture" : "x86_64",
  987. "availabilityZone" : "us-west-2a",
  988. "billingProducts" : null, ------------>array
  989. "devpayProductCodes" : null, ----------->deprecated
  990. "marketplaceProductCodes" : null, -------->array
  991. "imageId" : "ami-5b70e323",
  992. "instanceId" : "i-022a93b5e640c0248",
  993. "instanceType" : "c4.8xlarge",
  994. "kernelId" : null,
  995. "pendingTime" : "2020-05-27T08:41:17Z",
  996. "privateIp" : "172.31.22.164",
  997. "ramdiskId" : null,
  998. "region" : "us-west-2",
  999. "version" : "2017-09-30"
  1000. }
  1001. */
  1002. static int s_parse_instance_info(struct aws_json_value *document_root, struct aws_imds_instance_info *dest) {
  1003. bool success = false;
  1004. struct aws_byte_cursor account_id_cursor;
  1005. struct aws_json_value *account_id =
  1006. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("accountId"));
  1007. if (account_id == NULL) {
  1008. account_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("accountid"));
  1009. if (account_id == NULL) {
  1010. account_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("AccountId"));
  1011. }
  1012. }
  1013. if (!aws_json_value_is_string(account_id) ||
  1014. (aws_json_value_get_string(account_id, &account_id_cursor) == AWS_OP_ERR)) {
  1015. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse accountId from Json document for ec2 instance info.");
  1016. goto done;
  1017. }
  1018. dest->account_id = account_id_cursor;
  1019. struct aws_byte_cursor architecture_cursor;
  1020. struct aws_json_value *architecture =
  1021. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("architecture"));
  1022. if (architecture == NULL) {
  1023. architecture = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("Architecture"));
  1024. }
  1025. if (!aws_json_value_is_string(architecture) ||
  1026. (aws_json_value_get_string(architecture, &architecture_cursor) == AWS_OP_ERR)) {
  1027. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse architecture from Json document for ec2 instance info.");
  1028. goto done;
  1029. }
  1030. dest->architecture = architecture_cursor;
  1031. struct aws_byte_cursor availability_zone_cursor;
  1032. struct aws_json_value *availability_zone =
  1033. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("availabilityZone"));
  1034. if (availability_zone == NULL) {
  1035. availability_zone =
  1036. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("availabilityzone"));
  1037. if (availability_zone == NULL) {
  1038. availability_zone =
  1039. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("AvailabilityZone"));
  1040. }
  1041. }
  1042. if (!aws_json_value_is_string(availability_zone) ||
  1043. (aws_json_value_get_string(availability_zone, &availability_zone_cursor) == AWS_OP_ERR)) {
  1044. AWS_LOGF_ERROR(
  1045. AWS_LS_IMDS_CLIENT, "Failed to parse availabilityZone from Json document for ec2 instance info.");
  1046. goto done;
  1047. }
  1048. dest->availability_zone = availability_zone_cursor;
  1049. struct aws_byte_cursor billing_products_cursor;
  1050. struct aws_json_value *billing_products =
  1051. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("billingProducts"));
  1052. if (billing_products == NULL) {
  1053. billing_products = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("billingproducts"));
  1054. if (billing_products == NULL) {
  1055. billing_products =
  1056. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("BillingProducts"));
  1057. }
  1058. }
  1059. if (aws_json_value_is_array(billing_products)) {
  1060. struct aws_json_value *element;
  1061. for (size_t i = 0; i < aws_json_get_array_size(billing_products); i++) {
  1062. element = aws_json_get_array_element(billing_products, i);
  1063. if (aws_json_value_is_string(element) &&
  1064. aws_json_value_get_string(element, &billing_products_cursor) != AWS_OP_ERR) {
  1065. struct aws_byte_cursor item = billing_products_cursor;
  1066. aws_array_list_push_back(&dest->billing_products, (const void *)&item);
  1067. }
  1068. }
  1069. }
  1070. struct aws_byte_cursor marketplace_product_codes_cursor;
  1071. struct aws_json_value *marketplace_product_codes =
  1072. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("marketplaceProductCodes"));
  1073. if (marketplace_product_codes == NULL) {
  1074. marketplace_product_codes =
  1075. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("marketplaceproductcodes"));
  1076. if (marketplace_product_codes == NULL) {
  1077. marketplace_product_codes =
  1078. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("MarketplaceProductCodes"));
  1079. }
  1080. }
  1081. if (aws_json_value_is_array(marketplace_product_codes)) {
  1082. struct aws_json_value *element;
  1083. for (size_t i = 0; i < aws_json_get_array_size(marketplace_product_codes); i++) {
  1084. element = aws_json_get_array_element(marketplace_product_codes, i);
  1085. if (aws_json_value_is_string(element) &&
  1086. aws_json_value_get_string(element, &marketplace_product_codes_cursor) != AWS_OP_ERR) {
  1087. struct aws_byte_cursor item = marketplace_product_codes_cursor;
  1088. aws_array_list_push_back(&dest->billing_products, (const void *)&item);
  1089. }
  1090. }
  1091. }
  1092. struct aws_byte_cursor image_id_cursor;
  1093. struct aws_json_value *image_id =
  1094. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("imageId"));
  1095. if (image_id == NULL) {
  1096. image_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("imageid"));
  1097. if (image_id == NULL) {
  1098. image_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("ImageId"));
  1099. }
  1100. }
  1101. if (aws_json_value_is_string(image_id) && (aws_json_value_get_string(image_id, &image_id_cursor) != AWS_OP_ERR)) {
  1102. dest->image_id = image_id_cursor;
  1103. }
  1104. struct aws_byte_cursor instance_id_cursor;
  1105. struct aws_json_value *instance_id =
  1106. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("instanceId"));
  1107. if (instance_id == NULL) {
  1108. instance_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("instanceid"));
  1109. if (instance_id == NULL) {
  1110. instance_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("InstanceId"));
  1111. }
  1112. }
  1113. if (!aws_json_value_is_string(instance_id) ||
  1114. (aws_json_value_get_string(instance_id, &instance_id_cursor) == AWS_OP_ERR)) {
  1115. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse instanceId from Json document for ec2 instance info.");
  1116. goto done;
  1117. }
  1118. dest->instance_id = instance_id_cursor;
  1119. struct aws_byte_cursor instance_type_cursor;
  1120. struct aws_json_value *instance_type =
  1121. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("instanceType"));
  1122. if (instance_type == NULL) {
  1123. instance_type = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("instancetype"));
  1124. if (instance_type == NULL) {
  1125. instance_type = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("InstanceType"));
  1126. }
  1127. }
  1128. if (!aws_json_value_is_string(instance_type) ||
  1129. (aws_json_value_get_string(instance_type, &instance_type_cursor) == AWS_OP_ERR)) {
  1130. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse instanceType from Json document for ec2 instance info.");
  1131. goto done;
  1132. }
  1133. dest->instance_type = instance_type_cursor;
  1134. struct aws_byte_cursor kernel_id_cursor;
  1135. struct aws_json_value *kernel_id =
  1136. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("kernelId"));
  1137. if (kernel_id == NULL) {
  1138. kernel_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("kernelid"));
  1139. if (kernel_id == NULL) {
  1140. kernel_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("KernelId"));
  1141. }
  1142. }
  1143. if (aws_json_value_is_string(kernel_id) &&
  1144. (aws_json_value_get_string(kernel_id, &kernel_id_cursor) != AWS_OP_ERR)) {
  1145. dest->kernel_id = kernel_id_cursor;
  1146. }
  1147. struct aws_byte_cursor private_ip_cursor;
  1148. struct aws_json_value *private_ip =
  1149. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("privateIp"));
  1150. if (private_ip == NULL) {
  1151. private_ip = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("privateip"));
  1152. if (private_ip == NULL) {
  1153. private_ip = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("PrivateIp"));
  1154. }
  1155. }
  1156. if (aws_json_value_is_string(private_ip) &&
  1157. (aws_json_value_get_string(private_ip, &private_ip_cursor) != AWS_OP_ERR)) {
  1158. dest->private_ip = private_ip_cursor;
  1159. }
  1160. struct aws_byte_cursor ramdisk_id_cursor;
  1161. struct aws_json_value *ramdisk_id =
  1162. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("ramdiskId"));
  1163. if (ramdisk_id == NULL) {
  1164. ramdisk_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("ramdiskid"));
  1165. if (ramdisk_id == NULL) {
  1166. ramdisk_id = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("RamdiskId"));
  1167. }
  1168. }
  1169. if (aws_json_value_is_string(ramdisk_id) &&
  1170. (aws_json_value_get_string(ramdisk_id, &ramdisk_id_cursor) != AWS_OP_ERR)) {
  1171. dest->ramdisk_id = ramdisk_id_cursor;
  1172. }
  1173. struct aws_byte_cursor region_cursor;
  1174. struct aws_json_value *region = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("region"));
  1175. if (region == NULL) {
  1176. region = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("Region"));
  1177. }
  1178. if (!aws_json_value_is_string(region) || (aws_json_value_get_string(region, &region_cursor) == AWS_OP_ERR)) {
  1179. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse region from Json document for ec2 instance info.");
  1180. goto done;
  1181. }
  1182. dest->region = region_cursor;
  1183. struct aws_byte_cursor version_cursor;
  1184. struct aws_json_value *version =
  1185. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("version"));
  1186. if (version == NULL) {
  1187. version = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("Version"));
  1188. }
  1189. if (!aws_json_value_is_string(version) || (aws_json_value_get_string(version, &version_cursor) == AWS_OP_ERR)) {
  1190. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse version from Json document for ec2 instance info.");
  1191. goto done;
  1192. }
  1193. dest->version = version_cursor;
  1194. struct aws_byte_cursor pending_time_cursor;
  1195. struct aws_json_value *pending_time =
  1196. aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("pendingTime"));
  1197. if (pending_time == NULL) {
  1198. pending_time = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("pendingtime"));
  1199. if (pending_time == NULL) {
  1200. pending_time = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("PendingTime"));
  1201. }
  1202. }
  1203. if (!aws_json_value_is_string(pending_time) ||
  1204. (aws_json_value_get_string(pending_time, &pending_time_cursor) == AWS_OP_ERR)) {
  1205. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse pendingTime from Json document for ec2 instance info.");
  1206. goto done;
  1207. }
  1208. if (aws_date_time_init_from_str_cursor(&dest->pending_time, &pending_time_cursor, AWS_DATE_FORMAT_ISO_8601)) {
  1209. AWS_LOGF_ERROR(
  1210. AWS_LS_IMDS_CLIENT, "pendingTime in instance info Json document is not a valid ISO_8601 date string.");
  1211. goto done;
  1212. }
  1213. success = true;
  1214. done:
  1215. return success ? AWS_OP_ERR : AWS_OP_SUCCESS;
  1216. }
  1217. static void s_process_instance_info(const struct aws_byte_buf *resource, int error_code, void *user_data) {
  1218. struct imds_get_instance_user_data *wrapped_user_data = user_data;
  1219. struct aws_imds_instance_info instance_info;
  1220. AWS_ZERO_STRUCT(instance_info);
  1221. struct aws_byte_buf json_data;
  1222. AWS_ZERO_STRUCT(json_data);
  1223. struct aws_json_value *document_root = NULL;
  1224. if (aws_array_list_init_dynamic(
  1225. &instance_info.billing_products, wrapped_user_data->allocator, 10, sizeof(struct aws_byte_cursor))) {
  1226. goto on_finish;
  1227. }
  1228. if (aws_array_list_init_dynamic(
  1229. &instance_info.marketplace_product_codes,
  1230. wrapped_user_data->allocator,
  1231. 10,
  1232. sizeof(struct aws_byte_cursor))) {
  1233. goto on_finish;
  1234. }
  1235. if (!resource || error_code) {
  1236. goto on_finish;
  1237. }
  1238. if (aws_byte_buf_init_copy(&json_data, wrapped_user_data->allocator, resource)) {
  1239. goto on_finish;
  1240. }
  1241. if (aws_byte_buf_append_null_terminator(&json_data)) {
  1242. goto on_finish;
  1243. }
  1244. struct aws_byte_cursor json_data_cursor = aws_byte_cursor_from_buf(&json_data);
  1245. document_root = aws_json_value_new_from_string(aws_default_allocator(), json_data_cursor);
  1246. if (document_root == NULL) {
  1247. AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to parse document as Json document for ec2 instance info.");
  1248. goto on_finish;
  1249. }
  1250. if (s_parse_instance_info(document_root, &instance_info)) {
  1251. goto on_finish;
  1252. }
  1253. on_finish:
  1254. wrapped_user_data->callback(&instance_info, error_code, wrapped_user_data->user_data);
  1255. aws_array_list_clean_up_secure(&instance_info.billing_products);
  1256. aws_array_list_clean_up_secure(&instance_info.marketplace_product_codes);
  1257. aws_byte_buf_clean_up_secure(&json_data);
  1258. aws_mem_release(wrapped_user_data->allocator, wrapped_user_data);
  1259. if (document_root != NULL) {
  1260. aws_json_value_destroy(document_root);
  1261. }
  1262. }
  1263. static int s_aws_imds_get_resource(
  1264. struct aws_imds_client *client,
  1265. struct aws_byte_cursor path,
  1266. struct aws_byte_cursor name,
  1267. aws_imds_client_on_get_resource_callback_fn callback,
  1268. void *user_data) {
  1269. struct aws_byte_buf resource;
  1270. if (aws_byte_buf_init_copy_from_cursor(&resource, client->allocator, path)) {
  1271. return AWS_OP_ERR;
  1272. }
  1273. if (aws_byte_buf_append_dynamic(&resource, &name)) {
  1274. goto error;
  1275. }
  1276. if (aws_imds_client_get_resource_async(client, aws_byte_cursor_from_buf(&resource), callback, user_data)) {
  1277. goto error;
  1278. }
  1279. aws_byte_buf_clean_up(&resource);
  1280. return AWS_OP_SUCCESS;
  1281. error:
  1282. aws_byte_buf_clean_up(&resource);
  1283. return AWS_OP_ERR;
  1284. }
  1285. int s_aws_imds_get_converted_resource(
  1286. struct aws_imds_client *client,
  1287. struct aws_byte_cursor path,
  1288. struct aws_byte_cursor name,
  1289. aws_imds_client_on_get_resource_callback_fn conversion_fn,
  1290. void *user_data) {
  1291. return s_aws_imds_get_resource(client, path, name, conversion_fn, user_data);
  1292. }
  1293. int aws_imds_client_get_ami_id(
  1294. struct aws_imds_client *client,
  1295. aws_imds_client_on_get_resource_callback_fn callback,
  1296. void *user_data) {
  1297. return s_aws_imds_get_resource(
  1298. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/ami-id"), callback, user_data);
  1299. }
  1300. int aws_imds_client_get_ami_launch_index(
  1301. struct aws_imds_client *client,
  1302. aws_imds_client_on_get_resource_callback_fn callback,
  1303. void *user_data) {
  1304. return s_aws_imds_get_resource(
  1305. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/ami-launch-index"), callback, user_data);
  1306. }
  1307. int aws_imds_client_get_ami_manifest_path(
  1308. struct aws_imds_client *client,
  1309. aws_imds_client_on_get_resource_callback_fn callback,
  1310. void *user_data) {
  1311. return s_aws_imds_get_resource(
  1312. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/ami-manifest-path"), callback, user_data);
  1313. }
  1314. int aws_imds_client_get_ancestor_ami_ids(
  1315. struct aws_imds_client *client,
  1316. aws_imds_client_on_get_array_callback_fn callback,
  1317. void *user_data) {
  1318. struct imds_get_array_user_data *wrapped_user_data =
  1319. aws_mem_calloc(client->allocator, 1, sizeof(struct imds_get_array_user_data));
  1320. if (!wrapped_user_data) {
  1321. return AWS_OP_ERR;
  1322. }
  1323. wrapped_user_data->allocator = client->allocator;
  1324. wrapped_user_data->callback = callback;
  1325. wrapped_user_data->user_data = user_data;
  1326. return s_aws_imds_get_converted_resource(
  1327. client,
  1328. s_ec2_metadata_root,
  1329. aws_byte_cursor_from_c_str("/ancestor-ami-ids"),
  1330. s_process_array_resource,
  1331. wrapped_user_data);
  1332. }
  1333. int aws_imds_client_get_instance_action(
  1334. struct aws_imds_client *client,
  1335. aws_imds_client_on_get_resource_callback_fn callback,
  1336. void *user_data) {
  1337. return s_aws_imds_get_resource(
  1338. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/instance-action"), callback, user_data);
  1339. }
  1340. int aws_imds_client_get_instance_id(
  1341. struct aws_imds_client *client,
  1342. aws_imds_client_on_get_resource_callback_fn callback,
  1343. void *user_data) {
  1344. return s_aws_imds_get_resource(
  1345. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/instance-id"), callback, user_data);
  1346. }
  1347. int aws_imds_client_get_instance_type(
  1348. struct aws_imds_client *client,
  1349. aws_imds_client_on_get_resource_callback_fn callback,
  1350. void *user_data) {
  1351. return s_aws_imds_get_resource(
  1352. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/instance-type"), callback, user_data);
  1353. }
  1354. int aws_imds_client_get_mac_address(
  1355. struct aws_imds_client *client,
  1356. aws_imds_client_on_get_resource_callback_fn callback,
  1357. void *user_data) {
  1358. return s_aws_imds_get_resource(
  1359. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/mac"), callback, user_data);
  1360. }
  1361. int aws_imds_client_get_private_ip_address(
  1362. struct aws_imds_client *client,
  1363. aws_imds_client_on_get_resource_callback_fn callback,
  1364. void *user_data) {
  1365. return s_aws_imds_get_resource(
  1366. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/local-ipv4"), callback, user_data);
  1367. }
  1368. int aws_imds_client_get_availability_zone(
  1369. struct aws_imds_client *client,
  1370. aws_imds_client_on_get_resource_callback_fn callback,
  1371. void *user_data) {
  1372. return s_aws_imds_get_resource(
  1373. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/placement/availability-zone"), callback, user_data);
  1374. }
  1375. int aws_imds_client_get_product_codes(
  1376. struct aws_imds_client *client,
  1377. aws_imds_client_on_get_resource_callback_fn callback,
  1378. void *user_data) {
  1379. return s_aws_imds_get_resource(
  1380. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/product-codes"), callback, user_data);
  1381. }
  1382. int aws_imds_client_get_public_key(
  1383. struct aws_imds_client *client,
  1384. aws_imds_client_on_get_resource_callback_fn callback,
  1385. void *user_data) {
  1386. return s_aws_imds_get_resource(
  1387. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/public-keys/0/openssh-key"), callback, user_data);
  1388. }
  1389. int aws_imds_client_get_ramdisk_id(
  1390. struct aws_imds_client *client,
  1391. aws_imds_client_on_get_resource_callback_fn callback,
  1392. void *user_data) {
  1393. return s_aws_imds_get_resource(
  1394. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/ramdisk-id"), callback, user_data);
  1395. }
  1396. int aws_imds_client_get_reservation_id(
  1397. struct aws_imds_client *client,
  1398. aws_imds_client_on_get_resource_callback_fn callback,
  1399. void *user_data) {
  1400. return s_aws_imds_get_resource(
  1401. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/reservation-id"), callback, user_data);
  1402. }
  1403. int aws_imds_client_get_security_groups(
  1404. struct aws_imds_client *client,
  1405. aws_imds_client_on_get_array_callback_fn callback,
  1406. void *user_data) {
  1407. struct imds_get_array_user_data *wrapped_user_data =
  1408. aws_mem_calloc(client->allocator, 1, sizeof(struct imds_get_array_user_data));
  1409. if (!wrapped_user_data) {
  1410. return AWS_OP_ERR;
  1411. }
  1412. wrapped_user_data->allocator = client->allocator;
  1413. wrapped_user_data->callback = callback;
  1414. wrapped_user_data->user_data = user_data;
  1415. return s_aws_imds_get_converted_resource(
  1416. client,
  1417. s_ec2_metadata_root,
  1418. aws_byte_cursor_from_c_str("/security-groups"),
  1419. s_process_array_resource,
  1420. wrapped_user_data);
  1421. }
  1422. int aws_imds_client_get_block_device_mapping(
  1423. struct aws_imds_client *client,
  1424. aws_imds_client_on_get_array_callback_fn callback,
  1425. void *user_data) {
  1426. struct imds_get_array_user_data *wrapped_user_data =
  1427. aws_mem_calloc(client->allocator, 1, sizeof(struct imds_get_array_user_data));
  1428. if (!wrapped_user_data) {
  1429. return AWS_OP_ERR;
  1430. }
  1431. wrapped_user_data->allocator = client->allocator;
  1432. wrapped_user_data->callback = callback;
  1433. wrapped_user_data->user_data = user_data;
  1434. return s_aws_imds_get_converted_resource(
  1435. client,
  1436. s_ec2_metadata_root,
  1437. aws_byte_cursor_from_c_str("/block-device-mapping"),
  1438. s_process_array_resource,
  1439. wrapped_user_data);
  1440. }
  1441. int aws_imds_client_get_attached_iam_role(
  1442. struct aws_imds_client *client,
  1443. aws_imds_client_on_get_resource_callback_fn callback,
  1444. void *user_data) {
  1445. return s_aws_imds_get_resource(
  1446. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/iam/security-credentials/"), callback, user_data);
  1447. }
  1448. int aws_imds_client_get_credentials(
  1449. struct aws_imds_client *client,
  1450. struct aws_byte_cursor iam_role_name,
  1451. aws_imds_client_on_get_credentials_callback_fn callback,
  1452. void *user_data) {
  1453. struct imds_get_credentials_user_data *wrapped_user_data =
  1454. aws_mem_calloc(client->allocator, 1, sizeof(struct imds_get_credentials_user_data));
  1455. if (!wrapped_user_data) {
  1456. return AWS_OP_ERR;
  1457. }
  1458. wrapped_user_data->allocator = client->allocator;
  1459. wrapped_user_data->callback = callback;
  1460. wrapped_user_data->user_data = user_data;
  1461. return s_aws_imds_get_converted_resource(
  1462. client, s_ec2_credentials_root, iam_role_name, s_process_credentials_resource, wrapped_user_data);
  1463. }
  1464. int aws_imds_client_get_iam_profile(
  1465. struct aws_imds_client *client,
  1466. aws_imds_client_on_get_iam_profile_callback_fn callback,
  1467. void *user_data) {
  1468. struct imds_get_iam_user_data *wrapped_user_data =
  1469. aws_mem_calloc(client->allocator, 1, sizeof(struct imds_get_iam_user_data));
  1470. if (!wrapped_user_data) {
  1471. return AWS_OP_ERR;
  1472. }
  1473. wrapped_user_data->allocator = client->allocator;
  1474. wrapped_user_data->callback = callback;
  1475. wrapped_user_data->user_data = user_data;
  1476. return s_aws_imds_get_converted_resource(
  1477. client, s_ec2_metadata_root, aws_byte_cursor_from_c_str("/iam/info"), s_process_iam_profile, wrapped_user_data);
  1478. }
  1479. int aws_imds_client_get_user_data(
  1480. struct aws_imds_client *client,
  1481. aws_imds_client_on_get_resource_callback_fn callback,
  1482. void *user_data) {
  1483. return s_aws_imds_get_resource(client, s_ec2_userdata_root, aws_byte_cursor_from_c_str(""), callback, user_data);
  1484. }
  1485. int aws_imds_client_get_instance_signature(
  1486. struct aws_imds_client *client,
  1487. aws_imds_client_on_get_resource_callback_fn callback,
  1488. void *user_data) {
  1489. return s_aws_imds_get_resource(client, s_ec2_dynamicdata_root, s_instance_identity_signature, callback, user_data);
  1490. }
  1491. int aws_imds_client_get_instance_info(
  1492. struct aws_imds_client *client,
  1493. aws_imds_client_on_get_instance_info_callback_fn callback,
  1494. void *user_data) {
  1495. struct imds_get_instance_user_data *wrapped_user_data =
  1496. aws_mem_calloc(client->allocator, 1, sizeof(struct imds_get_instance_user_data));
  1497. if (!wrapped_user_data) {
  1498. return AWS_OP_ERR;
  1499. }
  1500. wrapped_user_data->allocator = client->allocator;
  1501. wrapped_user_data->callback = callback;
  1502. wrapped_user_data->user_data = user_data;
  1503. return s_aws_imds_get_converted_resource(
  1504. client, s_ec2_dynamicdata_root, s_instance_identity_document, s_process_instance_info, wrapped_user_data);
  1505. }