blob: 902fcc074984d5e398e20065248982e2f4b72e4a [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{
Chia-chi Yeh79e62322009-06-02 08:49:55 +080061 int i;
62
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070063 for (i = 0; protocols[i]; ++i) {
64 struct protocol *p = protocols[i];
65 if (argc - 2 >= p->arguments && !strcmp(argv[1], p->name)) {
66 log_print(INFO, "Using protocol %s", p->name);
67 the_protocol = p;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080068 break;
69 }
70 }
71
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070072 if (!the_protocol) {
73 printf("Usages:\n");
Chia-chi Yeh79e62322009-06-02 08:49:55 +080074 for (i = 0; protocols[i]; ++i) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070075 struct protocol *p = protocols[i];
76 printf(" %s %s %s pppd-arguments\n", argv[0], p->name, p->usage);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080077 }
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070078 exit(0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080079 }
80
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070081 pppd_argc = argc - 2 - the_protocol->arguments;
82 pppd_argv = &argv[2 + the_protocol->arguments];
83 return the_protocol->connect(&argv[2]);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080084}
85
86static void stop_pppd()
87{
88 if (pppd_pid) {
89 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
90 kill(pppd_pid, SIGTERM);
91 sleep(5);
92 pppd_pid = 0;
93 }
94}
95
Chia-chi Yeh84e31952009-06-08 14:11:34 +080096#ifdef ANDROID_CHANGES
97
98static int get_control_and_arguments(int *argc, char ***argv)
99{
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700100 static char *args[32];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800101 int control;
102 int i;
103
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800104 if ((i = android_get_control_socket("mtpd")) == -1) {
105 return -1;
106 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800107 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800108 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800109 log_print(FATAL, "Cannot get control socket");
110 exit(SYSTEM_ERROR);
111 }
112 close(i);
113 fcntl(control, F_SETFD, FD_CLOEXEC);
114
115 args[0] = (*argv)[0];
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700116 for (i = 1; i < 32; ++i) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800117 unsigned char length;
118 if (recv(control, &length, 1, 0) != 1) {
119 log_print(FATAL, "Cannot get argument length");
120 exit(SYSTEM_ERROR);
121 }
122 if (length == 0xFF) {
123 break;
124 } else {
125 int offset = 0;
126 args[i] = malloc(length + 1);
127 while (offset < length) {
128 int n = recv(control, &args[i][offset], length - offset, 0);
129 if (n > 0) {
130 offset += n;
131 } else {
132 log_print(FATAL, "Cannot get argument value");
133 exit(SYSTEM_ERROR);
134 }
135 }
136 args[i][length] = 0;
137 }
138 }
139 log_print(DEBUG, "Received %d arguments", i - 1);
140
Chia-chi Yehf1029202009-07-06 14:28:36 +0800141 /* L2TP secret is the only thing stored in keystore. We do the query here
142 * so other files are clean and free from android specific code. */
143 if (i > 4 && !strcmp("l2tp", args[1]) && args[4][0]) {
Chia-chi Yeh58c35fd2009-09-18 17:32:57 +0800144 char value[KEYSTORE_MESSAGE_SIZE];
Chia-chi Yehe01c9792010-03-08 17:22:47 +0800145 int length = keystore_get(args[4], strlen(args[4]), value);
Chia-chi Yeh58c35fd2009-09-18 17:32:57 +0800146 if (length == -1) {
Chia-chi Yehf1029202009-07-06 14:28:36 +0800147 log_print(FATAL, "Cannot get L2TP secret from keystore");
148 exit(SYSTEM_ERROR);
149 }
150 free(args[4]);
Chia-chi Yeh58c35fd2009-09-18 17:32:57 +0800151 args[4] = malloc(length + 1);
152 memcpy(args[4], value, length);
153 args[4][length] = 0;
Chia-chi Yehf1029202009-07-06 14:28:36 +0800154 }
155
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800156 *argc = i;
157 *argv = args;
158 return control;
159}
160
161#endif
162
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800163int main(int argc, char **argv)
164{
165 struct pollfd pollfds[2];
166 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800167 int status;
168#ifdef ANDROID_CHANGES
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800169 int control = get_control_and_arguments(&argc, &argv);
Chia-chi Yehfa04c312009-07-11 01:01:33 +0800170 unsigned char code = argc - 1;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800171 send(control, &code, 1, 0);
172#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800173
174 srandom(time(NULL));
175
176 if (pipe(signals) == -1) {
177 log_print(FATAL, "Pipe() %s", strerror(errno));
178 exit(SYSTEM_ERROR);
179 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800180 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
181 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800182
Chia-chi Yeha7776542009-06-19 16:36:32 +0800183 timeout = initialize(argc, argv);
184
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800185 signal(SIGHUP, interrupt);
186 signal(SIGINT, interrupt);
187 signal(SIGTERM, interrupt);
188 signal(SIGCHLD, interrupt);
189 signal(SIGPIPE, SIG_IGN);
190 atexit(stop_pppd);
191
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800192 pollfds[0].fd = signals[0];
193 pollfds[0].events = POLLIN;
194 pollfds[1].fd = the_socket;
195 pollfds[1].events = POLLIN;
196
197 while (timeout >= 0) {
198 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
199 log_print(FATAL, "Poll() %s", strerror(errno));
200 exit(SYSTEM_ERROR);
201 }
202 if (pollfds[0].revents) {
203 break;
204 }
205 timeout = pollfds[1].revents ?
206 the_protocol->process() : the_protocol->timeout();
207 }
208
209 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800210 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800211 } else {
212 int signal;
213 read(signals[0], &signal, sizeof(int));
214 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800215 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
216 && WIFEXITED(status)) {
217 status = WEXITSTATUS(status);
218 log_print(INFO, "Pppd is terminated (status = %d)", status);
219 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800220 pppd_pid = 0;
221 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800222 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800223 }
224 }
225
226 stop_pppd();
227 the_protocol->shutdown();
228
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800229#ifdef ANDROID_CHANGES
230 code = status;
231 send(control, &code, 1, 0);
232#endif
233 log_print(INFO, "Mtpd is terminated (status = %d)", status);
234 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800235}
236
237void log_print(int level, char *format, ...)
238{
239 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800240#ifdef ANDROID_CHANGES
241 static int levels[5] = {
242 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
243 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
244 };
245 va_list ap;
246 va_start(ap, format);
247 __android_log_vprint(levels[level], "mtpd", format, ap);
248 va_end(ap);
249#else
250 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800251 va_list ap;
252 fprintf(stderr, "%c: ", levels[level]);
253 va_start(ap, format);
254 vfprintf(stderr, format, ap);
255 va_end(ap);
256 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800257#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800258 }
259}
260
261void create_socket(int family, int type, char *server, char *port)
262{
263 struct addrinfo hints = {
264 .ai_flags = AI_NUMERICSERV,
265 .ai_family = family,
266 .ai_socktype = type,
267 };
268 struct addrinfo *records;
269 struct addrinfo *r;
270 int error;
271
272 log_print(INFO, "Connecting to %s port %s", server, port);
273
274 error = getaddrinfo(server, port, &hints, &records);
275 if (error) {
276 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
277 strerror(errno) : gai_strerror(error));
278 exit(NETWORK_ERROR);
279 }
280
281 for (r = records; r; r = r->ai_next) {
282 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
Chia-chi Yeha7776542009-06-19 16:36:32 +0800283 if (the_socket != -1) {
284 if (connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
285 break;
286 }
287 close(the_socket);
Chia-chi Yehfa04c312009-07-11 01:01:33 +0800288 the_socket = -1;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800289 }
290 }
291
292 freeaddrinfo(records);
293
294 if (the_socket == -1) {
295 log_print(FATAL, "Connect() %s", strerror(errno));
296 exit(NETWORK_ERROR);
297 }
298
299 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
300 log_print(INFO, "Connection established (socket = %d)", the_socket);
301}
302
303void start_pppd(int pppox)
304{
305 if (pppd_pid) {
306 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
307 close(pppox);
308 return;
309 }
310
311 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
312
313 pppd_pid = fork();
314 if (pppd_pid < 0) {
315 log_print(FATAL, "Fork() %s", strerror(errno));
316 exit(SYSTEM_ERROR);
317 }
318
319 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800320 char *args[pppd_argc + 5];
321 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800322
323 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800324 args[0] = "pppd";
325 args[1] = "nodetach";
326 args[2] = "pppox";
327 args[3] = number;
328 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
329 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800330
Chia-chi Yeh4a721df2009-12-15 03:53:47 +0800331#ifdef ANDROID_CHANGES
332 {
333 char envargs[65536];
334 char *tail = envargs;
335 int i;
336 /* Hex encode the arguments using [A-P] instead of [0-9A-F]. */
337 for (i = 0; args[i]; ++i) {
338 char *p = args[i];
339 do {
340 *tail++ = 'A' + ((*p >> 4) & 0x0F);
341 *tail++ = 'A' + (*p & 0x0F);
342 } while (*p++);
343 }
344 *tail = 0;
345 setenv("envargs", envargs, 1);
346 args[1] = NULL;
347 }
348#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800349 execvp("pppd", args);
350 log_print(FATAL, "Exec() %s", strerror(errno));
351 exit(1); /* Pretending a fatal error in pppd. */
352 }
353
354 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
355 close(pppox);
356}