1 /* $OpenBSD: getpeereid_test.c,v 1.1 2006/10/23 15:18:47 espie 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, 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 		unlink(path);
89 		rmdir(dir);
90 		err(1, "listen");
91 	}
92 	fd = accept(s, (struct sockaddr *)&client_addr, &client_len);
93 	if (fd == -1) {
94 		unlink(path);
95 		rmdir(dir);
96 		err(1, "accept");
97 	}
98 	problem = check_id(fd);
99 	if (problem)  {
100 		unlink(path);
101 		rmdir(dir);
102 		errx(1, problem);
103 	}
104 	unlink(path);
105 	rmdir(dir);
106 }
107 
108 
109 
110 int
111 main()
112 {
113 	pid_t pid;
114 	struct sockaddr_un sun;
115 	char dir_template[] = "/tmp/peer.XXXXXX";
116 
117 	dir = mkdtemp(dir_template);
118 	if (!dir)
119 		err(1, "mkdtemp");
120 	snprintf(path, sizeof path, "%s/%s", dir, "socket");
121 
122 	memset(&sun, 0, sizeof(struct sockaddr_un));
123 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
124 	    sizeof(sun.sun_path))
125 		errx(1, "Memory error");
126 	sun.sun_len = sizeof(sun);
127 	sun.sun_family = AF_UNIX;
128 
129 	/* let's make those two rendez-vous, a bit artificial */
130 	pid = fork();
131 	if (pid == -1)
132 		err(1, "can't fork");
133 	if (pid == 0) {
134 		client(&sun);
135 		exit(0);
136 	} else {
137 		int status;
138 
139 		server(&sun);
140 		waitpid(pid, &status, 0);
141 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
142 			printf("getpeereid test okay\n");
143 			exit(0);
144 		} else
145 			errx(1, "Problem with child\n");
146 	}
147 }
148