iptables-test: Fix builtin chain rule addition
[platform/upstream/connman.git] / tools / wispr.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <signal.h>
32 #include <termios.h>
33
34 #include <gweb/gweb.h>
35
36 #define DEFAULT_URL  "http://www.connman.net/online/status.html"
37
38 static GTimer *timer;
39
40 static GMainLoop *main_loop;
41
42 static void web_debug(const char *str, void *data)
43 {
44         g_print("%s: %s\n", (const char *) data, str);
45 }
46
47 static void sig_term(int sig)
48 {
49         g_main_loop_quit(main_loop);
50 }
51
52 static const char *message_type_to_string(int message_type)
53 {
54         switch (message_type) {
55         case 100:
56                 return "Initial redirect message";
57         case 110:
58                 return "Proxy notification";
59         case 120:
60                 return "Authentication notification";
61         case 130:
62                 return "Logoff notification";
63         case 140:
64                 return "Response to Authentication Poll";
65         case 150:
66                 return "Response to Abort Login";
67         }
68
69         return NULL;
70 }
71
72 static const char *response_code_to_string(int response_code)
73 {
74         switch (response_code) {
75         case 0:
76                 return "No error";
77         case 50:
78                 return "Login succeeded";
79         case 100:
80                 return "Login failed";
81         case 102:
82                 return "RADIUS server error/timeout";
83         case 105:
84                 return "RADIUS server not enabled";
85         case 150:
86                 return "Logoff succeeded";
87         case 151:
88                 return "Login aborted";
89         case 200:
90                 return "Proxy detection/repeat operation";
91         case 201:
92                 return "Authentication pending";
93         case 255:
94                 return "Access gateway internal error";
95         }
96
97         return NULL;
98 }
99
100 struct wispr_msg {
101         gboolean has_error;
102         const char *current_element;
103         int message_type;
104         int response_code;
105         char *login_url;
106         char *logoff_url;
107         char *access_procedure;
108         char *access_location;
109         char *location_name;
110 };
111
112 static inline void wispr_msg_init(struct wispr_msg *msg)
113 {
114         msg->has_error = FALSE;
115         msg->current_element = NULL;
116
117         msg->message_type = -1;
118         msg->response_code = -1;
119
120         g_free(msg->login_url);
121         msg->login_url = NULL;
122
123         g_free(msg->logoff_url);
124         msg->logoff_url = NULL;
125
126         g_free(msg->access_procedure);
127         msg->access_procedure = NULL;
128
129         g_free(msg->access_location);
130         msg->access_location = NULL;
131
132         g_free(msg->location_name);
133         msg->location_name = NULL;
134 }
135
136 struct wispr_session {
137         GWeb *web;
138         GWebParser *parser;
139         guint request;
140         struct wispr_msg msg;
141         char *username;
142         char *password;
143         char *originurl;
144         char *formdata;
145 };
146
147 static void execute_login(struct wispr_session *wispr);
148
149 static struct {
150         const char *str;
151         enum {
152                 WISPR_ELEMENT_NONE,
153                 WISPR_ELEMENT_ACCESS_PROCEDURE,
154                 WISPR_ELEMENT_ACCESS_LOCATION,
155                 WISPR_ELEMENT_LOCATION_NAME,
156                 WISPR_ELEMENT_LOGIN_URL,
157                 WISPR_ELEMENT_ABORT_LOGIN_URL,
158                 WISPR_ELEMENT_MESSAGE_TYPE,
159                 WISPR_ELEMENT_RESPONSE_CODE,
160                 WISPR_ELEMENT_NEXT_URL,
161                 WISPR_ELEMENT_DELAY,
162                 WISPR_ELEMENT_REPLY_MESSAGE,
163                 WISPR_ELEMENT_LOGIN_RESULTS_URL,
164                 WISPR_ELEMENT_LOGOFF_URL,
165         } element;
166 } wispr_element_map[] = {
167         { "AccessProcedure",    WISPR_ELEMENT_ACCESS_PROCEDURE  },
168         { "AccessLocation",     WISPR_ELEMENT_ACCESS_LOCATION   },
169         { "LocationName",       WISPR_ELEMENT_LOCATION_NAME     },
170         { "LoginURL",           WISPR_ELEMENT_LOGIN_URL         },
171         { "AbortLoginURL",      WISPR_ELEMENT_ABORT_LOGIN_URL   },
172         { "MessageType",        WISPR_ELEMENT_MESSAGE_TYPE      },
173         { "ResponseCode",       WISPR_ELEMENT_RESPONSE_CODE     },
174         { "NextURL",            WISPR_ELEMENT_NEXT_URL          },
175         { "Delay",              WISPR_ELEMENT_DELAY             },
176         { "ReplyMessage",       WISPR_ELEMENT_REPLY_MESSAGE     },
177         { "LoginResultsURL",    WISPR_ELEMENT_LOGIN_RESULTS_URL },
178         { "LogoffURL",          WISPR_ELEMENT_LOGOFF_URL        },
179         { NULL,                 WISPR_ELEMENT_NONE              },
180 };
181
182 static void start_element_handler(GMarkupParseContext *context,
183                                         const gchar *element_name,
184                                         const gchar **attribute_names,
185                                         const gchar **attribute_values,
186                                         gpointer user_data, GError **error)
187 {
188         struct wispr_msg *msg = user_data;
189
190         msg->current_element = element_name;
191 }
192
193 static void end_element_handler(GMarkupParseContext *context,
194                                         const gchar *element_name,
195                                         gpointer user_data, GError **error)
196 {
197         struct wispr_msg *msg = user_data;
198
199         msg->current_element = NULL;
200 }
201
202 static void text_handler(GMarkupParseContext *context,
203                                         const gchar *text, gsize text_len,
204                                         gpointer user_data, GError **error)
205 {
206         struct wispr_msg *msg = user_data;
207         int i;
208
209         if (msg->current_element == NULL)
210                 return;
211
212         for (i = 0; wispr_element_map[i].str; i++) {
213                 if (g_str_equal(wispr_element_map[i].str,
214                                         msg->current_element) == FALSE)
215                         continue;
216
217                 switch (wispr_element_map[i].element) {
218                 case WISPR_ELEMENT_NONE:
219                 case WISPR_ELEMENT_ACCESS_PROCEDURE:
220                         g_free(msg->access_procedure);
221                         msg->access_procedure = g_strdup(text);
222                 case WISPR_ELEMENT_ACCESS_LOCATION:
223                         g_free(msg->access_location);
224                         msg->access_location = g_strdup(text);
225                 case WISPR_ELEMENT_LOCATION_NAME:
226                         g_free(msg->location_name);
227                         msg->location_name = g_strdup(text);
228                         break;
229                 case WISPR_ELEMENT_LOGIN_URL:
230                         g_free(msg->login_url);
231                         msg->login_url = g_strdup(text);
232                         break;
233                 case WISPR_ELEMENT_ABORT_LOGIN_URL:
234                         break;
235                 case WISPR_ELEMENT_MESSAGE_TYPE:
236                         msg->message_type = atoi(text);
237                         break;
238                 case WISPR_ELEMENT_RESPONSE_CODE:
239                         msg->response_code = atoi(text);
240                         break;
241                 case WISPR_ELEMENT_NEXT_URL:
242                 case WISPR_ELEMENT_DELAY:
243                 case WISPR_ELEMENT_REPLY_MESSAGE:
244                 case WISPR_ELEMENT_LOGIN_RESULTS_URL:
245                         break;
246                 case WISPR_ELEMENT_LOGOFF_URL:
247                         g_free(msg->logoff_url);
248                         msg->logoff_url = g_strdup(text);
249                         break;
250                 }
251         }
252 }
253
254 static void error_handler(GMarkupParseContext *context,
255                                         GError *error, gpointer user_data)
256 {
257         struct wispr_msg *msg = user_data;
258
259         msg->has_error = TRUE;
260 }
261
262 static const GMarkupParser wispr_parser = {
263         start_element_handler,
264         end_element_handler,
265         text_handler,
266         NULL,
267         error_handler,
268 };
269
270 static void parser_callback(const char *str, gpointer user_data)
271 {
272         struct wispr_session *wispr = user_data;
273         GMarkupParseContext *context;
274         gboolean result;
275
276         //printf("%s\n", str);
277
278         context = g_markup_parse_context_new(&wispr_parser,
279                         G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL);
280
281         result = g_markup_parse_context_parse(context, str, strlen(str), NULL);
282         if (result == TRUE)
283                 result = g_markup_parse_context_end_parse(context, NULL);
284
285         g_markup_parse_context_free(context);
286 }
287
288 typedef void (*user_input_cb)(const char *value, gpointer user_data);
289
290 struct user_input_data {
291         GString *str;
292         user_input_cb cb;
293         gpointer user_data;
294         gboolean hidden;
295         int fd;
296         struct termios saved_termios;
297 };
298
299 static void user_callback(struct user_input_data *data)
300 {
301         char *value;
302         int len;
303
304         if (data->hidden == TRUE)
305                 len = write(data->fd, "\n", 1);
306
307         tcsetattr(data->fd, TCSADRAIN, &data->saved_termios);
308
309         close(data->fd);
310
311         value = g_string_free(data->str, FALSE);
312
313         if (data->cb)
314                 data->cb(value, data->user_data);
315
316         g_free(value);
317
318         g_free(data);
319 }
320
321 static gboolean keyboard_input(GIOChannel *channel, GIOCondition condition,
322                                                         gpointer user_data)
323 {
324         struct user_input_data *data = user_data;
325         char buf[1];
326         int len;
327
328         len = read(data->fd, buf, 1);
329
330         if (len != 1)
331                 return TRUE;
332
333         if (buf[0] == '\n') {
334                 user_callback(data);
335                 return FALSE;
336         }
337
338         g_string_append_c(data->str, buf[0]);
339
340         if (data->hidden == TRUE)
341                 len = write(data->fd, "*", 1);
342
343         return TRUE;
344 }
345
346 static gboolean user_input(const char *label, gboolean hidden,
347                                 user_input_cb func, gpointer user_data)
348 {
349         struct user_input_data *data;
350         struct termios new_termios;
351         GIOChannel *channel;
352         guint watch;
353         int len;
354
355         data = g_try_new0(struct user_input_data, 1);
356         if (data == NULL)
357                 return FALSE;
358
359         data->str = g_string_sized_new(32);
360         data->cb = func;
361         data->user_data = user_data;
362         data->hidden = hidden;
363
364         data->fd = open("/dev/tty", O_RDWR | O_NOCTTY);
365         if (data->fd < 0)
366                 goto error;
367
368         if (tcgetattr(data->fd, &data->saved_termios) < 0) {
369                 close(data->fd);
370                 goto error;
371         }
372
373         new_termios = data->saved_termios;
374         if (data->hidden == TRUE)
375                 new_termios.c_lflag &= ~(ICANON|ECHO);
376         else
377                 new_termios.c_lflag &= ~ICANON;
378         new_termios.c_cc[VMIN] = 1;
379         new_termios.c_cc[VTIME] = 0;
380
381         tcsetattr(data->fd, TCSADRAIN, &new_termios);
382
383         channel = g_io_channel_unix_new(data->fd);
384         g_io_channel_set_encoding(channel, NULL, NULL);
385         g_io_channel_set_buffered(channel, FALSE);
386         watch = g_io_add_watch(channel, G_IO_IN, keyboard_input, data);
387         g_io_channel_unref(channel);
388
389         if (watch == 0)
390                 goto error;
391
392         len = write(data->fd, label, strlen(label));
393         len = write(data->fd, ": ", 2);
394
395         return TRUE;
396
397 error:
398         g_string_free(data->str, TRUE);
399         g_free(data);
400
401         return FALSE;
402 }
403
404 static void password_callback(const char *value, gpointer user_data)
405 {
406         struct wispr_session *wispr = user_data;
407
408         g_free(wispr->password);
409         wispr->password = g_strdup(value);
410
411         printf("\n");
412
413         execute_login(wispr);
414 }
415
416 static void username_callback(const char *value, gpointer user_data)
417 {
418         struct wispr_session *wispr = user_data;
419
420         g_free(wispr->username);
421         wispr->username = g_strdup(value);
422
423         if (wispr->password == NULL) {
424                 user_input("Password", TRUE, password_callback, wispr);
425                 return;
426         }
427
428         printf("\n");
429
430         execute_login(wispr);
431 }
432
433 static gboolean wispr_input(const guint8 **data, gsize *length,
434                                                 gpointer user_data)
435 {
436         struct wispr_session *wispr = user_data;
437         GString *buf;
438         gsize count;
439
440         buf = g_string_sized_new(100);
441
442         g_string_append(buf, "button=Login&UserName=");
443         g_string_append_uri_escaped(buf, wispr->username, NULL, FALSE);
444         g_string_append(buf, "&Password=");
445         g_string_append_uri_escaped(buf, wispr->password, NULL, FALSE);
446         g_string_append(buf, "&FNAME=0&OriginatingServer=");
447         g_string_append_uri_escaped(buf, wispr->originurl, NULL, FALSE);
448
449         count = buf->len;
450
451         g_free(wispr->formdata);
452         wispr->formdata = g_string_free(buf, FALSE);
453
454         *data = (guint8 *) wispr->formdata;
455         *length = count;
456
457         return FALSE;
458 }
459
460 static gboolean wispr_result(GWebResult *result, gpointer user_data)
461 {
462         struct wispr_session *wispr = user_data;
463         const guint8 *chunk;
464         gsize length;
465         guint16 status;
466         gdouble elapsed;
467
468         g_web_result_get_chunk(result, &chunk, &length);
469
470         if (length > 0) {
471                 //printf("%s\n", (char *) chunk);
472                 g_web_parser_feed_data(wispr->parser, chunk, length);
473                 return TRUE;
474         }
475
476         g_web_parser_end_data(wispr->parser);
477
478         status = g_web_result_get_status(result);
479
480         g_print("status: %03u\n", status);
481
482         elapsed = g_timer_elapsed(timer, NULL);
483
484         g_print("elapse: %f seconds\n", elapsed);
485
486         if (wispr->msg.message_type < 0)
487                 goto done;
488
489         printf("Message type: %s (%d)\n",
490                         message_type_to_string(wispr->msg.message_type),
491                                                 wispr->msg.message_type);
492         printf("Response code: %s (%d)\n",
493                         response_code_to_string(wispr->msg.response_code),
494                                                 wispr->msg.response_code);
495         if (wispr->msg.access_procedure != NULL)
496                 printf("Access procedure: %s\n", wispr->msg.access_procedure);
497         if (wispr->msg.access_location != NULL)
498                 printf("Access location: %s\n", wispr->msg.access_location);
499         if (wispr->msg.location_name != NULL)
500                 printf("Location name: %s\n", wispr->msg.location_name);
501         if (wispr->msg.login_url != NULL)
502                 printf("Login URL: %s\n", wispr->msg.login_url);
503         if (wispr->msg.logoff_url != NULL)
504                 printf("Logoff URL: %s\n", wispr->msg.logoff_url);
505         printf("\n");
506
507         if (status == 302 && wispr->msg.message_type == 100) {
508                 if (wispr->username == NULL) {
509                         user_input("Username", FALSE, username_callback, wispr);
510                         return FALSE;
511                 }
512
513                 if (wispr->password == NULL) {
514                         user_input("Password", TRUE, password_callback, wispr);
515                         return FALSE;
516                 }
517
518                 execute_login(wispr);
519                 return FALSE;
520         } else if (status == 200 && wispr->msg.message_type == 120) {
521                 int code = wispr->msg.response_code;
522                 printf("Login process: %s\n",
523                                         code == 50 ? "SUCCESS" : "FAILURE");
524         }
525
526 done:
527         g_main_loop_quit(main_loop);
528
529         return FALSE;
530 }
531
532 static void execute_login(struct wispr_session *wispr)
533 {
534         wispr->request = g_web_request_post(wispr->web, wispr->msg.login_url,
535                                         "application/x-www-form-urlencoded",
536                                         wispr_input, wispr_result, wispr);
537
538         wispr_msg_init(&wispr->msg);
539 }
540
541 static gboolean option_debug = FALSE;
542 static gchar *option_nameserver = NULL;
543 static gchar *option_username = NULL;
544 static gchar *option_password = NULL;
545 static gchar *option_url = NULL;
546
547 static GOptionEntry options[] = {
548         { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
549                                         "Enable debug output" },
550         { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver,
551                                         "Specify nameserver", "ADDRESS" },
552         { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
553                                         "Specify username", "USERNAME" },
554         { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password,
555                                         "Specify password", "PASSWORD" },
556         { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url,
557                                         "Specify arbitrary request", "URL" },
558         { NULL },
559 };
560
561 int main(int argc, char *argv[])
562 {
563         GOptionContext *context;
564         GError *error = NULL;
565         struct sigaction sa;
566         struct wispr_session wispr;
567         int index = 0;
568
569         context = g_option_context_new(NULL);
570         g_option_context_add_main_entries(context, options, NULL);
571
572         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
573                 if (error != NULL) {
574                         g_printerr("%s\n", error->message);
575                         g_error_free(error);
576                 } else
577                         g_printerr("An unknown error occurred\n");
578                 return 1;
579         }
580
581         g_option_context_free(context);
582
583         memset(&wispr, 0, sizeof(wispr));
584         wispr_msg_init(&wispr.msg);
585
586         wispr.web = g_web_new(index);
587         if (wispr.web == NULL) {
588                 fprintf(stderr, "Failed to create web service\n");
589                 return 1;
590         }
591
592         if (option_debug == TRUE)
593                 g_web_set_debug(wispr.web, web_debug, "WEB");
594
595         main_loop = g_main_loop_new(NULL, FALSE);
596
597         if (option_nameserver != NULL) {
598                 g_web_add_nameserver(wispr.web, option_nameserver);
599                 g_free(option_nameserver);
600         }
601
602         g_web_set_accept(wispr.web, NULL);
603         g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION);
604         g_web_set_close_connection(wispr.web, TRUE);
605
606         if (option_url == NULL)
607                 option_url = g_strdup(DEFAULT_URL);
608
609         wispr.username = option_username;
610         wispr.password = option_password;
611         wispr.originurl = option_url;
612
613         timer = g_timer_new();
614
615         wispr.parser = g_web_parser_new("<WISPAccessGatewayParam",
616                                                 "WISPAccessGatewayParam>",
617                                                 parser_callback, &wispr);
618
619         wispr.request = g_web_request_get(wispr.web, option_url,
620                                                         wispr_result, &wispr);
621
622         if (wispr.request == 0) {
623                 fprintf(stderr, "Failed to start request\n");
624                 return 1;
625         }
626
627         memset(&sa, 0, sizeof(sa));
628         sa.sa_handler = sig_term;
629         sigaction(SIGINT, &sa, NULL);
630         sigaction(SIGTERM, &sa, NULL);
631
632         g_main_loop_run(main_loop);
633
634         g_timer_destroy(timer);
635
636         if (wispr.request > 0)
637                 g_web_cancel_request(wispr.web, wispr.request);
638
639         g_web_parser_unref(wispr.parser);
640         g_web_unref(wispr.web);
641
642         g_main_loop_unref(main_loop);
643
644         g_free(wispr.username);
645         g_free(wispr.password);
646         g_free(wispr.originurl);
647
648         return 0;
649 }