blob: fd553be23fccd0d38e76bf7fcf8619f6766bda83 [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]) {
Chia-chi Yeh58c35fd2009-09-18 17:32:57 +0800153 char value[KEYSTORE_MESSAGE_SIZE];
Chia-chi Yehe01c9792010-03-08 17:22:47 +0800154 int length = keystore_get(args[4], strlen(args[4]), value);
Chia-chi Yeh58c35fd2009-09-18 17:32:57 +0800155 if (length == -1) {
Chia-chi Yehf1029202009-07-06 14:28:36 +0800156 log_print(FATAL, "Cannot get L2TP secret from keystore");
157 exit(SYSTEM_ERROR);
158 }
159 free(args[4]);
Chia-chi Yeh58c35fd2009-09-18 17:32:57 +0800160 args[4] = malloc(length + 1);
161 memcpy(args[4], value, length);
162 args[4][length] = 0;
Chia-chi Yehf1029202009-07-06 14:28:36 +0800163 }
164
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800165 *argc = i;
166 *argv = args;
167 return control;
168}
169
170#endif
171
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800172int main(int argc, char **argv)
173{
174 struct pollfd pollfds[2];
175 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800176 int status;
177#ifdef ANDROID_CHANGES
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800178 int control = get_control_and_arguments(&argc, &argv);
Chia-chi Yehfa04c312009-07-11 01:01:33 +0800179 unsigned char code = argc - 1;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800180 send(control, &code, 1, 0);
181#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800182
183 srandom(time(NULL));
184
185 if (pipe(signals) == -1) {
186 log_print(FATAL, "Pipe() %s", strerror(errno));
187 exit(SYSTEM_ERROR);
188 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800189 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
190 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800191
Chia-chi Yeha7776542009-06-19 16:36:32 +0800192 timeout = initialize(argc, argv);
193
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800194 signal(SIGHUP, interrupt);
195 signal(SIGINT, interrupt);
196 signal(SIGTERM, interrupt);
197 signal(SIGCHLD, interrupt);
198 signal(SIGPIPE, SIG_IGN);
199 atexit(stop_pppd);
200
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800201 pollfds[0].fd = signals[0];
202 pollfds[0].events = POLLIN;
203 pollfds[1].fd = the_socket;
204 pollfds[1].events = POLLIN;
205
206 while (timeout >= 0) {
207 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
208 log_print(FATAL, "Poll() %s", strerror(errno));
209 exit(SYSTEM_ERROR);
210 }
211 if (pollfds[0].revents) {
212 break;
213 }
214 timeout = pollfds[1].revents ?
215 the_protocol->process() : the_protocol->timeout();
216 }
217
218 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800219 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800220 } else {
221 int signal;
222 read(signals[0], &signal, sizeof(int));
223 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800224 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
225 && WIFEXITED(status)) {
226 status = WEXITSTATUS(status);
227 log_print(INFO, "Pppd is terminated (status = %d)", status);
228 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800229 pppd_pid = 0;
230 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800231 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800232 }
233 }
234
235 stop_pppd();
236 the_protocol->shutdown();
237
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800238#ifdef ANDROID_CHANGES
239 code = status;
240 send(control, &code, 1, 0);
241#endif
242 log_print(INFO, "Mtpd is terminated (status = %d)", status);
243 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800244}
245
246void log_print(int level, char *format, ...)
247{
248 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800249#ifdef ANDROID_CHANGES
250 static int levels[5] = {
251 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
252 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
253 };
254 va_list ap;
255 va_start(ap, format);
256 __android_log_vprint(levels[level], "mtpd", format, ap);
257 va_end(ap);
258#else
259 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800260 va_list ap;
261 fprintf(stderr, "%c: ", levels[level]);
262 va_start(ap, format);
263 vfprintf(stderr, format, ap);
264 va_end(ap);
265 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800266#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800267 }
268}
269
270void create_socket(int family, int type, char *server, char *port)
271{
272 struct addrinfo hints = {
273 .ai_flags = AI_NUMERICSERV,
274 .ai_family = family,
275 .ai_socktype = type,
276 };
277 struct addrinfo *records;
278 struct addrinfo *r;
279 int error;
280
281 log_print(INFO, "Connecting to %s port %s", server, port);
282
283 error = getaddrinfo(server, port, &hints, &records);
284 if (error) {
285 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
286 strerror(errno) : gai_strerror(error));
287 exit(NETWORK_ERROR);
288 }
289
290 for (r = records; r; r = r->ai_next) {
291 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
Chia-chi Yeha7776542009-06-19 16:36:32 +0800292 if (the_socket != -1) {
293 if (connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
294 break;
295 }
296 close(the_socket);
Chia-chi Yehfa04c312009-07-11 01:01:33 +0800297 the_socket = -1;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800298 }
299 }
300
301 freeaddrinfo(records);
302
303 if (the_socket == -1) {
304 log_print(FATAL, "Connect() %s", strerror(errno));
305 exit(NETWORK_ERROR);
306 }
307
308 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
309 log_print(INFO, "Connection established (socket = %d)", the_socket);
310}
311
312void start_pppd(int pppox)
313{
314 if (pppd_pid) {
315 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
316 close(pppox);
317 return;
318 }
319
320 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
321
322 pppd_pid = fork();
323 if (pppd_pid < 0) {
324 log_print(FATAL, "Fork() %s", strerror(errno));
325 exit(SYSTEM_ERROR);
326 }
327
328 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800329 char *args[pppd_argc + 5];
330 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800331
332 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800333 args[0] = "pppd";
334 args[1] = "nodetach";
335 args[2] = "pppox";
336 args[3] = number;
337 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
338 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800339
Chia-chi Yeh4a721df2009-12-15 03:53:47 +0800340#ifdef ANDROID_CHANGES
341 {
342 char envargs[65536];
343 char *tail = envargs;
344 int i;
345 /* Hex encode the arguments using [A-P] instead of [0-9A-F]. */
346 for (i = 0; args[i]; ++i) {
347 char *p = args[i];
348 do {
349 *tail++ = 'A' + ((*p >> 4) & 0x0F);
350 *tail++ = 'A' + (*p & 0x0F);
351 } while (*p++);
352 }
353 *tail = 0;
354 setenv("envargs", envargs, 1);
355 args[1] = NULL;
356 }
357#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800358 execvp("pppd", args);
359 log_print(FATAL, "Exec() %s", strerror(errno));
360 exit(1); /* Pretending a fatal error in pppd. */
361 }
362
363 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
364 close(pppox);
365}