summaryrefslogtreecommitdiff
path: root/content/projects/C_environ.md
blob: 46bf12f4675cb8be8076d30c50301e42c557c65b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
+++
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 <stdio.h>
#include <stdlib.h>

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 <stdio.h>
#include <string.h>

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 <stdio.h>
#include <string.h>

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.