1 /* $OpenBSD: getpeereid_test.c,v 1.4 2017/03/08 19:28:47 deraadt Exp $ */
2 /* Written by Marc Espie in 2006 */
3 /* Public domain */
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/stat.h>
7 #include <sys/un.h>
8 #include <sys/wait.h>
9 #include <err.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <errno.h>
15 
16 char path[1024];
17 char *dir;
18 
19 char *
20 check_id(int fd)
21 {
22 	uid_t sockuid, myuid;
23 	gid_t sockgid, mygid;
24 	static char problem[1024];
25 
26 	if (getpeereid(fd, &sockuid, &sockgid) == -1) {
27 		snprintf(problem, sizeof problem, "getpeereid: %s",
28 		    strerror(errno));
29 		return problem;
30 	}
31 	myuid = geteuid();
32 	mygid = getgid();
33 	if (myuid != sockuid) {
34 		snprintf(problem, sizeof problem, "uid discrepancy %ld vs %ld",
35 			(long)myuid, (long)sockuid);
36 		return problem;
37 	}
38 	if (mygid != sockgid) {
39 		snprintf(problem, sizeof problem, "gid discrepancy %ld vs %ld",
40 			(long)mygid, (long)sockgid);
41 		return problem;
42 	}
43 	return NULL;
44 }
45 
46 void
47 client(struct sockaddr_un *sun)
48 {
49 	int s;
50 	int i;
51 	int r;
52 	char *problem;
53 
54 	s = socket(AF_UNIX, SOCK_STREAM, 0);
55 	if (s == -1)
56 		err(1, "Bad socket");
57 
58 	/* XXX make sure the server started alright */
59 	for (i = 0; i < 10; i++) {
60 		r = connect(s, (struct sockaddr *)sun, sizeof(*sun));
61 		if (r == 0) {
62 			problem = check_id(s);
63 			if (problem)
64 				errx(1, "%s", problem);
65 			exit(0);
66 		}
67 		sleep(5);
68 	}
69 	errx(1, "Could not connect after 10 tries");
70 }
71 
72 
73 void
74 server(struct sockaddr_un *sun)
75 {
76 	int s, fd;
77 	struct sockaddr_storage client_addr;
78 	socklen_t client_len;
79 	char *problem;
80 
81 	s = socket(AF_UNIX, SOCK_STREAM, 0);
82 	if (s == -1)
83 		err(1, "Bad socket");
84 
85 	if (bind(s, (struct sockaddr *)sun, sizeof(*sun)) != 0)
86 		err(1, "bind");
87 	if (listen(s, 5) != 0) {
88 		int saved_errno = errno;
89 		unlink(path);
90 		rmdir(dir);
91 		errc(1, saved_errno, "listen");
92 	}
93 	fd = accept(s, (struct sockaddr *)&client_addr, &client_len);
94 	if (fd == -1) {
95 		int saved_errno = errno;
96 		unlink(path);
97 		rmdir(dir);
98 		errc(1, saved_errno, "accept");
99 	}
100 	problem = check_id(fd);
101 	if (problem)  {
102 		unlink(path);
103 		rmdir(dir);
104 		errx(1, "%s", problem);
105 	}
106 	unlink(path);
107 	rmdir(dir);
108 }
109 
110 
111 
112 int
113 main()
114 {
115 	pid_t pid;
116 	struct sockaddr_un sun;
117 	char dir_template[] = "/tmp/peer.XXXXXX";
118 
119 	dir = mkdtemp(dir_template);
120 	if (!dir)
121 		err(1, "mkdtemp");
122 	snprintf(path, sizeof path, "%s/%s", dir, "socket");
123 
124 	memset(&sun, 0, sizeof(struct sockaddr_un));
125 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
126 	    sizeof(sun.sun_path))
127 		errx(1, "Memory error");
128 	sun.sun_family = AF_UNIX;
129 
130 	/* let's make those two rendez-vous, a bit artificial */
131 	pid = fork();
132 	if (pid == -1)
133 		err(1, "can't fork");
134 	if (pid == 0) {
135 		client(&sun);
136 		exit(0);
137 	} else {
138 		int status;
139 
140 		server(&sun);
141 		waitpid(pid, &status, 0);
142 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
143 			printf("getpeereid test okay\n");
144 			exit(0);
145 		} else
146 			errx(1, "Problem with child\n");
147 	}
148 }
149