+++ title = "C: interaction with shell variables" date = 2024-04-29 +++ --- ### Fetch shell environment variables through `C` main declaration In the last couple of days, we can see people [talking](https://twitter.com/wangzhr4/status/1783775497492529349) about the security aspect of this behaviour. In `C`, we can in fact easily interact with shell variables with the `char *getenv(const char *name)` standard function: ```C #include #include int main(void) { printf("PATH: %s\r\n", getenv("PATH")); return (0); } ``` But the `C` offers a way to access them directly as passing argument into the main function, just like `**argv`. The definition of `main` can indeed have 0, 2 or 3 arguments: * `int main(void)` * `int main(int argc, char **argv)` * `int main(int argc, char **argv, char **envp)` The third and option argument is then our way to access shell variables, e.g.: ```C #include #include int main(int argc, char **argv, char **envp) { unsigned short timeout = 0; while ((*envp != NULL) && (timeout++ < (1 << 15))) { if (strncmp(*(envp++), "PATH", 4) == 0) { printf("%s\r\n", *(envp - 1)); return (0); } } printf("Timeout error\r\n"); return (1); } ``` Note that this third definition of `main` is **not** part of the [C99 Standard](https://www.open-std.org/JTC1/sc22/wg14/www/docs/n1256.pdf) (par. 5.1.2.2.1), making it de facto POSIX-specific though widely supported. You could however achieve the same result by overflowing the `**argv` parameter: ```C #include #include int main(int argc, char **argv) { unsigned short timeout = 0; argv += argc + 1; while ((*argv != NULL) && (timeout++ < (1 << 15))) { if (strncmp(*(argv++), "PATH", 4) == 0) { printf("%s\r\n", *(argv - 1)); return (0); } } printf("Timeout error\r\n"); return (1); } ``` You can find many examples and applications of this *new* `main` argument online, sometimes with another name (e.g. `**environ`) as, again, it is not standard.