f5fa6f60f1322e1dd8eb5a391c79aca7b991de06
[strongswan.git] / src / libcharon / plugins / whitelist / whitelist.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "whitelist_msg.h"
17
18 #include <sys/socket.h>
19 #include <sys/un.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <arpa/inet.h>
26
27 /**
28 * Connect to the daemon, return FD
29 */
30 static int make_connection()
31 {
32 union {
33 struct sockaddr_un un;
34 struct sockaddr_in in;
35 struct sockaddr sa;
36 } addr;
37 int fd, len;
38
39 if (getenv("TCP_PORT"))
40 {
41 addr.in.sin_family = AF_INET;
42 addr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
43 addr.in.sin_port = htons(atoi(getenv("TCP_PORT")));
44 len = sizeof(addr.in);
45 }
46 else
47 {
48 addr.un.sun_family = AF_UNIX;
49 strcpy(addr.un.sun_path, WHITELIST_SOCKET);
50
51 len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.un.sun_path);
52 }
53 fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
54 if (fd < 0)
55 {
56 fprintf(stderr, "opening socket failed: %s\n", strerror(errno));
57 return -1;
58 }
59 if (connect(fd, &addr.sa, len) < 0)
60 {
61 fprintf(stderr, "connecting failed: %s\n", strerror(errno));
62 close(fd);
63 return -1;
64 }
65 return fd;
66 }
67
68 static int read_all(int fd, void *buf, size_t len)
69 {
70 ssize_t ret, done = 0;
71
72 while (done < len)
73 {
74 ret = read(fd, buf, len - done);
75 if (ret == -1 && errno == EINTR)
76 { /* interrupted, try again */
77 continue;
78 }
79 if (ret < 0)
80 {
81 return -1;
82 }
83 done += ret;
84 buf += ret;
85 }
86 return len;
87 }
88
89 static int write_all(int fd, void *buf, size_t len)
90 {
91 ssize_t ret, done = 0;
92
93 while (done < len)
94 {
95 ret = write(fd, buf, len - done);
96 if (ret == -1 && errno == EINTR)
97 { /* interrupted, try again */
98 continue;
99 }
100 if (ret < 0)
101 {
102 return -1;
103 }
104 done += ret;
105 buf += ret;
106 }
107 return len;
108 }
109
110 /**
111 * Send a single message
112 */
113 static int send_msg(int type, char *id)
114 {
115 whitelist_msg_t msg = {
116 .type = htonl(type),
117 };
118 int fd;
119
120 fd = make_connection();
121 if (fd == -1)
122 {
123 return 2;
124 }
125 snprintf(msg.id, sizeof(msg.id), "%s", id);
126 if (write_all(fd, &msg, sizeof(msg)) != sizeof(msg))
127 {
128 fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
129 close(fd);
130 return 2;
131 }
132 if (type == WHITELIST_LIST)
133 {
134 while (1)
135 {
136 if (read_all(fd, &msg, sizeof(msg)) != sizeof(msg))
137 {
138 fprintf(stderr, "reading failed: %s\n", strerror(errno));
139 close(fd);
140 return 2;
141 }
142 if (ntohl(msg.type) != WHITELIST_LIST)
143 {
144 break;
145 }
146 msg.id[sizeof(msg.id) - 1] = '\0';
147 printf("%s\n", msg.id);
148 }
149 }
150 close(fd);
151 return 0;
152 }
153
154 /**
155 * Send a batch of messages, reading identities from a file
156 */
157 static int send_batch(int type, char *file)
158 {
159 whitelist_msg_t msg = {
160 .type = htonl(type),
161 };
162 FILE *f = stdin;
163 int fd, len;
164
165 fd = make_connection();
166 if (fd == -1)
167 {
168 return 2;
169 }
170 if (file)
171 {
172 f = fopen(file, "r");
173 if (f == NULL)
174 {
175 fprintf(stderr, "opening %s failed: %s\n", file, strerror(errno));
176 close(fd);
177 return 3;
178 }
179 }
180 while (fgets(msg.id, sizeof(msg.id), f))
181 {
182 len = strlen(msg.id);
183 if (len == 0)
184 {
185 continue;
186 }
187 if (msg.id[len-1] == '\n')
188 {
189 msg.id[len-1] = '\0';
190 }
191 if (write_all(fd, &msg, sizeof(msg)) != sizeof(msg))
192 {
193 fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
194 if (f != stdin)
195 {
196 fclose(f);
197 }
198 close(fd);
199 return 2;
200 }
201 }
202 if (f != stdin)
203 {
204 fclose(f);
205 }
206 close(fd);
207 return 0;
208 }
209
210 int main(int argc, char *argv[])
211 {
212 if (argc == 3 && strcmp(argv[1], "add") == 0)
213 {
214 return send_msg(WHITELIST_ADD, argv[2]);
215 }
216 if (argc == 3 && strcmp(argv[1], "remove") == 0)
217 {
218 return send_msg(WHITELIST_REMOVE, argv[2]);
219 }
220 if ((argc == 2 || argc == 3) && strcmp(argv[1], "add-from") == 0)
221 {
222 return send_batch(WHITELIST_ADD, argc == 3 ? argv[2] : NULL);
223 }
224 if ((argc == 2 || argc == 3) && strcmp(argv[1], "remove-from") == 0)
225 {
226 return send_batch(WHITELIST_REMOVE, argc == 3 ? argv[2] : NULL);
227 }
228 if ((argc == 2 || argc == 3) && strcmp(argv[1], "flush") == 0)
229 {
230 return send_msg(WHITELIST_FLUSH, argc == 3 ? argv[2] : "%any");
231 }
232 if ((argc == 2 || argc == 3) && strcmp(argv[1], "list") == 0)
233 {
234 return send_msg(WHITELIST_LIST, argc == 3 ? argv[2] : "%any");
235 }
236 if (argc == 2 && strcmp(argv[1], "enable") == 0)
237 {
238 return send_msg(WHITELIST_ENABLE, "");
239 }
240 if (argc == 2 && strcmp(argv[1], "disable") == 0)
241 {
242 return send_msg(WHITELIST_DISABLE, "");
243 }
244 fprintf(stderr, "Usage:\n");
245 fprintf(stderr, " %s add <identity>\n", argv[0]);
246 fprintf(stderr, " %s remove <identity>\n", argv[0]);
247 fprintf(stderr, " %s add-from <file>\n", argv[0]);
248 fprintf(stderr, " %s remove-from <file>\n", argv[0]);
249 fprintf(stderr, " %s flush [<pattern>]\n", argv[0]);
250 fprintf(stderr, " %s list [<pattern>]\n", argv[0]);
251 fprintf(stderr, " %s enable\n", argv[0]);
252 fprintf(stderr, " %s disable\n", argv[0]);
253 return 1;
254 }