1/*
2 This file is part of Mtproto-proxy Library.
3
4 Mtproto-proxy Library is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Mtproto-proxy Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2009-2013 Vkontakte Ltd
18 2008-2013 Nikolai Durov
19 2008-2013 Andrey Lopatin
20 2011-2013 Oleg Davydov
21 2012-2013 Arseny Smirnov
22 2012-2013 Aliaksei Levin
23 2012-2013 Anton Maydell
24 2013 Vitaliy Valtman
25
26 Copyright 2014-2018 Telegram Messenger Inc
27 2014-2018 Vitaly Valtman
28*/
29
30
31#define _FILE_OFFSET_BITS 64
32
33#define _GNU_SOURCE 1
34
35#include <arpa/inet.h>
36#include <assert.h>
37#include <errno.h>
38#include <execinfo.h>
39#include <fcntl.h>
40#include <getopt.h>
41#include <grp.h>
42#include <netinet/in.h>
43#include <pwd.h>
44#include <signal.h>
45#include <stdarg.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <sys/resource.h>
50#include <sys/wait.h>
51#include <unistd.h>
52#include <pthread.h>
53
54#include "common/kprintf.h"
55#include "net/net-connections.h"
56#include "net/net-events.h"
57#include "net/net-msg-buffers.h"
58
59#include "server-functions.h"
60
61#define STR_HELPER(x) #x
62#define STR(x) STR_HELPER(x)
63
64
65long long max_allocated_buffer_bytes __attribute__ ((weak));
66
67int engine_options_num;
68char *engine_options[MAX_ENGINE_OPTIONS];
69
70
71int start_time;
72
73int daemonize = 0;
74const char *username, *progname, *groupname;
75
76int change_user_group (const char *username, const char *groupname) {
77 struct passwd *pw;
78 /* lose root privileges if we have them */
79 if (getuid() == 0 || geteuid() == 0) {
80 if (username == 0 || *username == '\0') {
81 username = DEFAULT_ENGINE_USER;
82 }
83 if ((pw = getpwnam (username)) == 0) {
84 kprintf ("change_user_group: can't find the user %s to switch to\n", username);
85 return -1;
86 }
87 gid_t gid = pw->pw_gid;
88 if (setgroups (1, &gid) < 0) {
89 kprintf ("change_user_group: failed to clear supplementary groups list: %m\n");
90 return -1;
91 }
92
93 if (groupname) {
94 struct group *g = getgrnam (groupname);
95 if (g == NULL) {
96 kprintf ("change_user_group: can't find the group %s to switch to\n", groupname);
97 return -1;
98 }
99 gid = g->gr_gid;
100 }
101
102 if (setgid (gid) < 0) {
103 kprintf ("change_user_group: setgid (%d) failed. %m\n", (int) gid);
104 return -1;
105 }
106
107 if (setuid (pw->pw_uid) < 0) {
108 kprintf ("change_user_group: failed to assume identity of user %s\n", username);
109 return -1;
110 }
111 }
112 return 0;
113}
114
115int change_user (const char *username) {
116 struct passwd *pw;
117 /* lose root privileges if we have them */
118 if (getuid() == 0 || geteuid() == 0) {
119 if (username == 0 || *username == '\0') {
120 username = DEFAULT_ENGINE_USER;
121// fprintf (stderr, "can't run as root without the -u switch\n");
122// return -1;
123 }
124 if ((pw = getpwnam (username)) == 0) {
125 kprintf ("can't find the user %s to switch to\n", username);
126 return -1;
127 }
128 gid_t gid = pw->pw_gid;
129 if (setgroups(1, &gid) < 0) {
130 kprintf ("failed to clear supplementary groups list: %m\n");
131 return -1;
132 }
133 if (initgroups(username, gid) != 0) {
134 kprintf ("failed to load groups of user %s: %m\n", username);
135 return -1;
136 }
137 if (setgid (pw->pw_gid) < 0 || setuid (pw->pw_uid) < 0) {
138 kprintf ("failed to assume identity of user %s\n", username);
139 return -1;
140 }
141 }
142 return 0;
143}
144
145int raise_file_rlimit (int maxfiles) {
146 struct rlimit rlim;
147
148 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
149 kprintf ("failed to getrlimit number of files\n");
150 return -1;
151 } else {
152 if (rlim.rlim_cur < maxfiles)
153 rlim.rlim_cur = maxfiles + 3;
154 if (rlim.rlim_max < rlim.rlim_cur)
155 rlim.rlim_max = rlim.rlim_cur;
156 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
157 kprintf ("failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.\n");
158 return -1;
159 }
160 }
161 return 0;
162}
163
164
165const char *get_version_string (void) __attribute__ ((weak));
166const char *get_version_string (void) {
167 return "unknown compiled at " __DATE__ " " __TIME__ " by gcc " __VERSION__;
168}
169
170void print_backtrace (void) {
171 void *buffer[64];
172 int nptrs = backtrace (buffer, 64);
173 kwrite (2, "\n------- Stack Backtrace -------\n", 33);
174 backtrace_symbols_fd (buffer, nptrs, 2);
175 kwrite (2, "-------------------------------\n", 32);
176 const char *s = get_version_string ();
177 if (s) {
178 kwrite (2, s, strlen (s));
179 kwrite (2, "\n", 1);
180 }
181}
182
183pthread_t debug_main_pthread_id;
184
185void kill_main (void) {
186 if (debug_main_pthread_id && debug_main_pthread_id != pthread_self ()) {
187 pthread_kill (debug_main_pthread_id, SIGABRT);
188 }
189}
190
191//can be called inside signal handler
192void ksignal (int sig, void (*handler) (int)) {
193 struct sigaction act;
194 sigemptyset (&act.sa_mask);
195 act.sa_flags = SA_ONSTACK | SA_RESTART;
196 act.sa_handler = handler;
197
198 if (sigaction (sig, &act, NULL) != 0) {
199 kwrite (2, "failed sigaction\n", 17);
200 //_exit (EXIT_FAILURE);
201 }
202}
203
204void ksignal_ex (int sig, void (*handler) (int, siginfo_t *, void *)) {
205 struct sigaction act;
206 sigemptyset (&act.sa_mask);
207 act.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
208 act.sa_sigaction = handler;
209
210 if (sigaction (sig, &act, NULL) != 0) {
211 kwrite (2, "failed sigaction\n", 17);
212 _exit (EXIT_FAILURE);
213 }
214}
215
216void queries_log_store (void *N, int limit, int max_size, int max_entry_size, int plain) __attribute__ ((weak));
217void queries_log_store (void *N, int limit, int max_size, int max_entry_size, int plain) {}
218
219void engine_set_terminal_attributes (void) __attribute__ ((weak));
220void engine_set_terminal_attributes (void) {}
221
222void extended_debug_handler (int sig, siginfo_t *info, void *cont) {
223 ksignal (sig, SIG_DFL);
224
225 print_backtrace ();
226
227 kill_main ();
228
229 _exit (EXIT_FAILURE);
230}
231
232void set_debug_handlers (void) {
233 ksignal_ex (SIGSEGV, extended_debug_handler);
234 ksignal_ex (SIGABRT, extended_debug_handler);
235 ksignal_ex (SIGFPE, extended_debug_handler);
236 ksignal_ex (SIGBUS, extended_debug_handler);
237 debug_main_pthread_id = pthread_self ();
238}
239
240void usage (void) __attribute ((weak));
241
242void usage (void) {
243 printf ("usage: %s <args>\n",
244 progname ? progname : "SOMETHING");
245 exit (2);
246}
247
248long long parse_memory_limit (const char *s) {
249 long long x;
250 char c = 0;
251 if (sscanf (s, "%lld%c", &x, &c) < 1) {
252 kprintf ("Parsing limit for option fail: %s\n", s);
253 usage ();
254 exit (1);
255 }
256 switch (c | 0x20) {
257 case ' ': break;
258 case 'k': x <<= 10; break;
259 case 'm': x <<= 20; break;
260 case 'g': x <<= 30; break;
261 case 't': x <<= 40; break;
262 default:
263 kprintf ("Parsing limit fail. Unknown suffix '%c'.\n", c);
264 usage ();
265 exit (1);
266 }
267 return x;
268}
269
270struct engine_parse_option *engine_parse_options;
271int engine_parse_options_size;
272int engine_parse_options_num;
273
274int find_parse_option (int val) {
275 int i;
276 for (i = 0; i < engine_parse_options_num; i++) {
277 struct engine_parse_option *P = &engine_parse_options[i];
278 int j;
279 for (j = 0; j < P->val_cnt; j++) {
280 if (P->vals[j] == val) {
281 return i;
282 }
283 }
284 }
285 return -1;
286}
287
288int find_parse_option_name (const char *name) {
289 int i;
290 for (i = 0; i < engine_parse_options_num; i++) {
291 struct engine_parse_option *P = &engine_parse_options[i];
292 int j;
293 for (j = 0; j < P->longopts_cnt; j++) {
294 if (!strcmp (P->longopts[j], name)) {
295 return i;
296 }
297 }
298 }
299 return -1;
300}
301
302int default_parse_option_func (int a) __attribute__ ((weak));
303int default_parse_option_func (int a) { return -1; }
304
305void parse_option_up (struct engine_parse_option *P) {
306 struct engine_parse_option *Q = P - 1;
307 while (Q >= engine_parse_options && Q->smallest_val > P->smallest_val) {
308 Q --;
309 }
310 Q ++;
311 if (Q != P) {
312 struct engine_parse_option T;
313 T = *P;
314 memmove (Q + 1, Q, (P - Q) * sizeof (struct engine_parse_option));
315 *Q = T;
316 }
317}
318
319void parse_option_down (struct engine_parse_option *P) {
320 struct engine_parse_option *Q = P + 1;
321 while (Q < engine_parse_options + engine_parse_options_num && Q->smallest_val < P->smallest_val) {
322 Q ++;
323 }
324 Q --;
325 if (Q != P) {
326 struct engine_parse_option T;
327 T = *Q;
328 memmove (P + 1, P, (P - Q) * sizeof (struct engine_parse_option));
329 *P = T;
330 }
331}
332
333void parse_option_internal (const char *name, int arg, int *var, int val, unsigned flags, int (*func)(int), char *help) {
334 int p = find_parse_option (val);
335 if (p >= 0) {
336 kprintf ("duplicate parse option %d\n", val);
337 usage ();
338 }
339 assert (engine_parse_options_num <= engine_parse_options_size);
340 if (engine_parse_options_num == engine_parse_options_size) {
341 engine_parse_options_size = 10 + 2 * engine_parse_options_size;
342 engine_parse_options = realloc (engine_parse_options, sizeof (struct engine_parse_option) * engine_parse_options_size);
343 }
344 assert (engine_parse_options_num < engine_parse_options_size);
345 struct engine_parse_option *P = &engine_parse_options[engine_parse_options_num ++];
346 P->arg = arg;
347 P->flags = flags;
348 P->func = func ? func : default_parse_option_func;
349 P->help = help;
350
351
352 P->longopts = malloc (sizeof (void *));
353 P->longopts[0] = name;
354 P->longopts_cnt = 1;
355
356 P->vals = malloc (sizeof (int));
357 P->vals[0] = val;
358 P->val_cnt = 1;
359 P->smallest_val = val;
360 P->base_val = val;
361
362 parse_option_up (P);
363}
364
365void parse_option_ex (const char *name, int arg, int *var, int val, unsigned flags, int (*func)(int), const char *help, ...) {
366 char *h;
367 va_list ap;
368 va_start (ap, help);
369 assert (vasprintf (&h, help, ap) >= 0);
370 va_end (ap);
371
372 parse_option_internal (name, arg, var, val, flags, func, h);
373}
374
375void parse_option (const char *name, int arg, int *var, int val, const char *help, ...) {
376 char *h;
377 va_list ap;
378 va_start (ap, help);
379 assert (vasprintf (&h, help, ap) >= 0);
380 va_end (ap);
381
382 parse_option_internal (name, arg, var, val, LONGOPT_CUSTOM_SET, NULL, h);
383}
384
385int builtin_parse_option (int val);
386void parse_option_builtin (const char *name, int arg, int *var, int val, unsigned flags, const char *help, ...) {
387 parse_option_internal (name, arg, var, val, flags, builtin_parse_option, help ? strdup (help) : NULL);
388}
389
390
391void remove_parse_option_completely (int val) {
392 int t = find_parse_option (val);
393 assert (t >= 0);
394
395 struct engine_parse_option *P = &engine_parse_options[t];
396
397 assert (P->vals[0] == val);
398 if (P->help) {
399 free (P->help);
400 }
401 free (P->vals);
402 free (P->longopts);
403 memmove (engine_parse_options + t, engine_parse_options + t + 1, (engine_parse_options_num - t - 1) * sizeof (struct engine_parse_option));
404 engine_parse_options_num --;
405 return;
406}
407
408void remove_parse_option (int val) {
409 int t = find_parse_option (val);
410 if (t < 0) {
411 kprintf ("Can not remove unknown option %d\n", val);
412 usage ();
413 }
414
415 struct engine_parse_option *P = &engine_parse_options[t];
416
417 if (P->val_cnt == 1) {
418 assert (P->vals[0] == val);
419 free (P->help);
420 free (P->vals);
421 free (P->longopts);
422 memmove (engine_parse_options + t, engine_parse_options + t + 1, (engine_parse_options_num - t - 1) * sizeof (struct engine_parse_option));
423 engine_parse_options_num --;
424 return;
425 }
426
427 int *new_vals = malloc (4 * (P->val_cnt - 1));
428 int i;
429 int p = 0;
430 for (i = 0; i < P->val_cnt; i++) {
431 if (P->vals[i] != val) {
432 new_vals[p ++] = P->vals[i];
433 }
434 }
435 free (P->vals);
436 P->vals = new_vals;
437 P->val_cnt --;
438
439 if (P->smallest_val == val) {
440 P->smallest_val = 0x7fffffff;
441 int i;
442 for (i = 0; i < P->val_cnt; i++) {
443 if (P->vals[i] < P->smallest_val) {
444 P->smallest_val = P->vals[i];
445 }
446 }
447 parse_option_down (P);
448 }
449 if (P->base_val == val) {
450 P->base_val = P->smallest_val;
451 }
452}
453
454void parse_option_alias (const char *name, int val) {
455 int l = find_parse_option (val);
456 if (l >= 0) {
457 if (val >= 33 && val <= 127) {
458 kprintf ("Duplicate option `%c`\n", (char)val);
459 } else {
460 kprintf ("Duplicate option %d\n", val);
461 }
462 usage ();
463 }
464 l = find_parse_option_name (name);
465 if (l < 0) {
466 kprintf ("can't find option '%s'\n", name);
467 usage ();
468 }
469
470 struct engine_parse_option *P = &engine_parse_options[l];
471 P->val_cnt ++;
472 P->vals = realloc (P->vals, 4 * P->val_cnt);
473 P->vals[P->val_cnt - 1] = val;
474 if (val < P->smallest_val) {
475 P->smallest_val = val;
476 parse_option_up (P);
477 }
478}
479
480void parse_option_long_alias (const char *name, const char *alias_name) {
481 int l = find_parse_option_name (alias_name);
482 if (l >= 0) {
483 kprintf ("Duplicate option %s\n", alias_name);
484 usage ();
485 }
486 l = find_parse_option_name (name);
487 if (l < 0) {
488 kprintf ("can't find option '%s'\n", name);
489 usage ();
490 }
491
492 struct engine_parse_option *P = &engine_parse_options[l];
493 P->longopts_cnt ++;
494 P->longopts = realloc (P->longopts, sizeof (void *) * P->longopts_cnt);
495 P->longopts[P->longopts_cnt - 1] = alias_name;
496}
497
498int parse_usage (void) {
499 int max = 0;
500
501 int i;
502 for (i = 0; i < engine_parse_options_num; i++) {
503 struct engine_parse_option *P = &engine_parse_options[i];
504 int cur = 0;
505 int j;
506 for (j = 0; j < P->val_cnt; j++) {
507 if (P->vals[j] <= 127) {
508 cur += 3;
509 }
510 }
511 for (j = 0; j < P->longopts_cnt; j++) {
512 cur += strlen (P->longopts[j]) + 3;
513 }
514
515 if (P->arg == required_argument) {
516 cur += 6;
517 } else if (P->arg == optional_argument) {
518 cur += 6;
519 }
520 if (cur > max) {
521 max = cur;
522 }
523 }
524
525 for (i = 0; i < engine_parse_options_num; i++) {
526 struct engine_parse_option *P = &engine_parse_options[i];
527 int cur = 0;
528 printf ("\t");
529 int j;
530 for (j = 0; j < P->longopts_cnt; j++) {
531 if (cur) {
532 printf ("/");
533 cur ++;
534 }
535 cur += strlen (P->longopts[j]) + 2;
536 printf ("--%s", P->longopts[j]);
537 }
538 for (j = 0; j < P->val_cnt; j++) {
539 if (P->vals[j] <= 127) {
540 if (cur) {
541 printf ("/");
542 cur ++;
543 }
544 printf ("-%c", (char)P->vals[j]);
545 cur += 2;
546 }
547 }
548 if (P->arg == required_argument) {
549 printf (" <arg>");
550 cur += 6;
551 } else if (P->arg == optional_argument) {
552 printf (" {arg}");
553 cur += 6;
554 }
555 while (cur < max) {
556 printf (" ");
557 cur ++;
558 }
559 printf ("\t");
560 if (P->help) {
561 char *e = P->help;
562 while (*e) {
563 printf ("%c", *e);
564 if (*e == '\n') {
565 printf ("\t");
566 int i;
567 for (i = 0; i < max; i++) {
568 printf (" ");
569 }
570 printf ("\t");
571 }
572 e ++;
573 }
574 printf ("\n");
575// printf ("%s\n", global_longopts_help[s]);
576 } else {
577 printf ("no help provided\n");
578 }
579 }
580 return 0;
581}
582
583int builtin_parse_option (int val) {
584 switch (val) {
585 case 'v':
586 if (!optarg) {
587 verbosity++;
588 } else {
589 verbosity = atoi (optarg);
590 }
591 break;
592 case 'h':
593 usage ();
594 exit (2);
595 case 'u':
596 if (username) {
597 kprintf ("wrong option -u%s, username is already defined as '%s'.\n", optarg, username);
598 exit (1);
599 }
600 username = optarg;
601 break;
602 case 'l':
603 logname = optarg;
604 break;
605 case 'd':
606 if (!optarg) {
607 daemonize ^= 1;
608 } else {
609 daemonize = atoi (optarg) != 0;
610 }
611 break;
612 case 202:
613 errno = 0;
614 if (nice (atoi (optarg)) == -1 && errno) {
615 perror ("nice");
616 }
617 break;
618 case 208:
619 max_allocated_buffer_bytes = parse_memory_limit (optarg);
620 break;
621 default:
622 return -1;
623 }
624 return 0;
625}
626
627int parse_one_option (int val) {
628 int t = find_parse_option (val);
629 if (t < 0) {
630 return -1;
631 }
632 struct engine_parse_option *P = &engine_parse_options[t];
633 return P->func (P->base_val);
634}
635
636int parse_engine_options_long (int argc, char **argv) {
637 engine_options_num = argc;
638 memcpy ((void *)engine_options, argv, sizeof (void *) * argc);
639
640 int total_longopts = 0;
641 int total_shortopts_len = 0;
642 int i;
643 for (i = 0; i < engine_parse_options_num; i++) {
644 struct engine_parse_option *P = &engine_parse_options[i];
645 total_longopts += P->longopts_cnt;
646 int j;
647 for (j = 0; j < P->val_cnt; j++) {
648 if (P->vals[j] <= 127) {
649 total_shortopts_len += (P->arg == required_argument) ? 2 : 1;
650 }
651 }
652 }
653
654 char *shortopts = malloc (total_shortopts_len + 1);
655 assert (shortopts);
656 struct option *longopts = malloc ((total_longopts + 1) * sizeof (struct option));
657 int lpos = 0;
658 int spos = 0;
659
660 for (i = 0; i < engine_parse_options_num; i++) {
661 struct engine_parse_option *P = &engine_parse_options[i];
662 int j;
663
664 for (j = 0; j < P->longopts_cnt; j++) {
665 assert (lpos < total_longopts);
666 longopts[lpos].flag = NULL;
667 longopts[lpos].has_arg = P->arg;
668 longopts[lpos].name = P->longopts[j];
669 longopts[lpos].val = P->base_val;
670 lpos ++;
671 }
672
673 for (j = 0; j < P->val_cnt; j++) {
674 if (P->vals[j] <= 127) {
675 assert (spos < total_shortopts_len);
676 shortopts[spos ++] = P->vals[j];
677 if (P->arg == required_argument) {
678 assert (spos < total_shortopts_len);
679 shortopts[spos ++] = ':';
680 }
681 }
682 }
683 }
684
685 assert (lpos == total_longopts);
686 memset (&longopts[lpos], 0, sizeof (struct option));
687 assert (spos == total_shortopts_len);
688 shortopts[spos] = 0;
689
690 while (1) {
691 int option_index = -1;
692 int c = getopt_long (argc, argv, shortopts, longopts, &option_index);
693 if (c == -1) { break; }
694 if (!c) { continue; }
695 if (c == '?') {
696 kprintf ("Unrecognized option\n");
697 usage ();
698 }
699 if (parse_one_option (c) < 0) {
700 if (option_index >= 0) {
701 assert (option_index < total_longopts);
702 kprintf ("Can not parse option %s\n", longopts[option_index].name);
703 usage ();
704 } else if (c <= 127) {
705 kprintf ("Can not parse option '%c'\n", (char)c);
706 usage ();
707 } else {
708 kprintf ("Can not parse option %d\n", c);
709 usage ();
710 }
711 }
712 }
713 return 0;
714}
715
716int in_keep_options_list (const unsigned *list, unsigned num) {
717 if (!list) { return 0; }
718 const unsigned *a = list;
719 while (*a) {
720 if (*a == num) { return 1; }
721 a ++;
722 }
723 return 0;
724}
725
726void engine_add_net_parse_options (void) __attribute__ ((weak));
727void engine_add_net_parse_options (void) {}
728void engine_add_engine_parse_options (void) __attribute__ ((weak));
729void engine_add_engine_parse_options (void) {}
730
731void add_builtin_parse_options (void) {
732 parse_option_builtin ("verbosity", optional_argument, 0, 'v', LONGOPT_COMMON_SET, "sets or increases verbosity level");
733 parse_option_builtin ("help", no_argument, 0, 'h', LONGOPT_COMMON_SET, "prints help and exits");
734 parse_option_builtin ("user", required_argument, 0, 'u', LONGOPT_COMMON_SET, "sets user name to make setuid");
735 parse_option_builtin ("log", required_argument, 0, 'l', LONGOPT_COMMON_SET, "sets log file name");
736 parse_option_builtin ("daemonize", optional_argument, 0, 'd', LONGOPT_COMMON_SET, "changes between daemonize/not daemonize mode");
737 parse_option_builtin ("nice", required_argument, 0, 202, LONGOPT_COMMON_SET, "sets niceness");
738 parse_option_ex ("msg-buffers-size", required_argument, 0, 208, LONGOPT_COMMON_SET, builtin_parse_option, "sets maximal buffers size (default %lld)", (long long)MSG_DEFAULT_MAX_ALLOCATED_BYTES);
739 //parse_option_builtin ("tl-history", optional_argument, 0, 210, LONGOPT_NET_SET, "long },
740 //parse_option_builtin ("tl-op-stat", no_argument, 0, 211, LONGOPT_NET_SET, "enabled stat about op usage");
741 //{ "rwm-peak-recovery", no_argument, 0, 213},
742
743 engine_add_net_parse_options ();
744 engine_add_engine_parse_options ();
745}
746
747