blob: 197c525a4126e2b004cf8274666f35a8ab0ca963 [file] [log] [blame]
Chia-chi Yeh79e62322009-06-02 08:49:55 +08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <stdarg.h>
20#include <string.h>
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/poll.h>
25#include <sys/wait.h>
26#include <netdb.h>
27#include <signal.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <time.h>
31
Chia-chi Yeh84e31952009-06-08 14:11:34 +080032#ifdef ANDROID_CHANGES
33#include <android/log.h>
34#include <cutils/sockets.h>
Chia-chi Yehf1029202009-07-06 14:28:36 +080035#include "keystore_get.h"
Chia-chi Yeh84e31952009-06-08 14:11:34 +080036#endif
37
Chia-chi Yeh79e62322009-06-02 08:49:55 +080038#include "mtpd.h"
39
40int the_socket = -1;
41
42extern struct protocol l2tp;
Chia-chi Yeh063bb922009-06-15 14:43:38 +080043extern struct protocol pptp;
44static struct protocol *protocols[] = {&l2tp, &pptp, NULL};
Chia-chi Yeh79e62322009-06-02 08:49:55 +080045static struct protocol *the_protocol;
46
47static int pppd_argc;
48static char **pppd_argv;
49static pid_t pppd_pid;
50
51/* We redirect signals to a pipe in order to prevent race conditions. */
52static int signals[2];
53
54static void interrupt(int signal)
55{
56 write(signals[1], &signal, sizeof(int));
57}
58
59static int initialize(int argc, char **argv)
60{
61 int timeout = 0;
62 int i;
63
64 for (i = 2; i < argc; ++i) {
65 if (!argv[i][0]) {
66 pppd_argc = argc - i - 1;
67 pppd_argv = &argv[i + 1];
68 argc = i;
69 break;
70 }
71 }
72
73 if (argc >= 2) {
74 for (i = 0; protocols[i]; ++i) {
75 if (!strcmp(argv[1], protocols[i]->name)) {
76 log_print(INFO, "Using protocol %s", protocols[i]->name);
77 the_protocol = protocols[i];
78 timeout = the_protocol->connect(argc - 2, &argv[2]);
79 break;
80 }
81 }
82 }
83
84 if (!the_protocol || timeout == -USAGE_ERROR) {
85 printf("Usage: %s <protocol-args> '' <pppd-args>, "
86 "where protocol-args are one of:\n", argv[0]);
87 for (i = 0; protocols[i]; ++i) {
88 printf(" %s %s\n", protocols[i]->name, protocols[i]->usage);
89 }
90 exit(USAGE_ERROR);
91 }
92 return timeout;
93}
94
95static void stop_pppd()
96{
97 if (pppd_pid) {
98 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
99 kill(pppd_pid, SIGTERM);
100 sleep(5);
101 pppd_pid = 0;
102 }
103}
104
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800105#ifdef ANDROID_CHANGES
106
107static int get_control_and_arguments(int *argc, char ***argv)
108{
109 static char *args[256];
110 int control;
111 int i;
112
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800113 if ((i = android_get_control_socket("mtpd")) == -1) {
114 return -1;
115 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800116 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800117 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800118 log_print(FATAL, "Cannot get control socket");
119 exit(SYSTEM_ERROR);
120 }
121 close(i);
122 fcntl(control, F_SETFD, FD_CLOEXEC);
123
124 args[0] = (*argv)[0];
125 for (i = 1; i < 256; ++i) {
126 unsigned char length;
127 if (recv(control, &length, 1, 0) != 1) {
128 log_print(FATAL, "Cannot get argument length");
129 exit(SYSTEM_ERROR);
130 }
131 if (length == 0xFF) {
132 break;
133 } else {
134 int offset = 0;
135 args[i] = malloc(length + 1);
136 while (offset < length) {
137 int n = recv(control, &args[i][offset], length - offset, 0);
138 if (n > 0) {
139 offset += n;
140 } else {
141 log_print(FATAL, "Cannot get argument value");
142 exit(SYSTEM_ERROR);
143 }
144 }
145 args[i][length] = 0;
146 }
147 }
148 log_print(DEBUG, "Received %d arguments", i - 1);
149
Chia-chi Yehf1029202009-07-06 14:28:36 +0800150 /* L2TP secret is the only thing stored in keystore. We do the query here
151 * so other files are clean and free from android specific code. */
152 if (i > 4 && !strcmp("l2tp", args[1]) && args[4][0]) {
153 char *value = keystore_get(args[4], NULL);
154 if (!value) {
155 log_print(FATAL, "Cannot get L2TP secret from keystore");
156 exit(SYSTEM_ERROR);
157 }
158 free(args[4]);
159 args[4] = value;
160 }
161
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800162 *argc = i;
163 *argv = args;
164 return control;
165}
166
167#endif
168
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800169int main(int argc, char **argv)
170{
171 struct pollfd pollfds[2];
172 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800173 int status;
174#ifdef ANDROID_CHANGES
175 unsigned char code;
176 int control = get_control_and_arguments(&argc, &argv);
177 code = argc - 1;
178 send(control, &code, 1, 0);
179#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800180
181 srandom(time(NULL));
182
183 if (pipe(signals) == -1) {
184 log_print(FATAL, "Pipe() %s", strerror(errno));
185 exit(SYSTEM_ERROR);
186 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800187 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
188 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800189
Chia-chi Yeha7776542009-06-19 16:36:32 +0800190 timeout = initialize(argc, argv);
191
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800192 signal(SIGHUP, interrupt);
193 signal(SIGINT, interrupt);
194 signal(SIGTERM, interrupt);
195 signal(SIGCHLD, interrupt);
196 signal(SIGPIPE, SIG_IGN);
197 atexit(stop_pppd);
198
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800199 pollfds[0].fd = signals[0];
200 pollfds[0].events = POLLIN;
201 pollfds[1].fd = the_socket;
202 pollfds[1].events = POLLIN;
203
204 while (timeout >= 0) {
205 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
206 log_print(FATAL, "Poll() %s", strerror(errno));
207 exit(SYSTEM_ERROR);
208 }
209 if (pollfds[0].revents) {
210 break;
211 }
212 timeout = pollfds[1].revents ?
213 the_protocol->process() : the_protocol->timeout();
214 }
215
216 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800217 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800218 } else {
219 int signal;
220 read(signals[0], &signal, sizeof(int));
221 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800222 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
223 && WIFEXITED(status)) {
224 status = WEXITSTATUS(status);
225 log_print(INFO, "Pppd is terminated (status = %d)", status);
226 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800227 pppd_pid = 0;
228 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800229 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800230 }
231 }
232
233 stop_pppd();
234 the_protocol->shutdown();
235
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800236#ifdef ANDROID_CHANGES
237 code = status;
238 send(control, &code, 1, 0);
239#endif
240 log_print(INFO, "Mtpd is terminated (status = %d)", status);
241 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800242}
243
244void log_print(int level, char *format, ...)
245{
246 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800247#ifdef ANDROID_CHANGES
248 static int levels[5] = {
249 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
250 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
251 };
252 va_list ap;
253 va_start(ap, format);
254 __android_log_vprint(levels[level], "mtpd", format, ap);
255 va_end(ap);
256#else
257 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800258 va_list ap;
259 fprintf(stderr, "%c: ", levels[level]);
260 va_start(ap, format);
261 vfprintf(stderr, format, ap);
262 va_end(ap);
263 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800264#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800265 }
266}
267
268void create_socket(int family, int type, char *server, char *port)
269{
270 struct addrinfo hints = {
271 .ai_flags = AI_NUMERICSERV,
272 .ai_family = family,
273 .ai_socktype = type,
274 };
275 struct addrinfo *records;
276 struct addrinfo *r;
277 int error;
278
279 log_print(INFO, "Connecting to %s port %s", server, port);
280
281 error = getaddrinfo(server, port, &hints, &records);
282 if (error) {
283 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
284 strerror(errno) : gai_strerror(error));
285 exit(NETWORK_ERROR);
286 }
287
288 for (r = records; r; r = r->ai_next) {
289 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
Chia-chi Yeha7776542009-06-19 16:36:32 +0800290 if (the_socket != -1) {
291 if (connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
292 break;
293 }
294 close(the_socket);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800295 }
296 }
297
298 freeaddrinfo(records);
299
300 if (the_socket == -1) {
301 log_print(FATAL, "Connect() %s", strerror(errno));
302 exit(NETWORK_ERROR);
303 }
304
305 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
306 log_print(INFO, "Connection established (socket = %d)", the_socket);
307}
308
309void start_pppd(int pppox)
310{
311 if (pppd_pid) {
312 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
313 close(pppox);
314 return;
315 }
316
317 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
318
319 pppd_pid = fork();
320 if (pppd_pid < 0) {
321 log_print(FATAL, "Fork() %s", strerror(errno));
322 exit(SYSTEM_ERROR);
323 }
324
325 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800326 char *args[pppd_argc + 5];
327 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800328
329 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800330 args[0] = "pppd";
331 args[1] = "nodetach";
332 args[2] = "pppox";
333 args[3] = number;
334 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
335 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800336
337 execvp("pppd", args);
338 log_print(FATAL, "Exec() %s", strerror(errno));
339 exit(1); /* Pretending a fatal error in pppd. */
340 }
341
342 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
343 close(pppox);
344}