1 /**************************************************************************
2 * Copyright (C) 2005-2020 by Oleksandr Shneyder *
3 * <o.shneyder@phoca-gmbh.de> *
4 * Copyright (C) 2015-2020 by Mihai Moldovan <ionic@ionic.de> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 #include <iostream>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include <cstring>
23 #include <cerrno>
24 #include <cstdlib>
25 #include <string>
26 #include <algorithm>
27 #include <cctype>
28 #include <vector>
29 #include <csignal>
30
31 #include "unixhelper.h"
32 #include "ongetpass.h"
33 #include "compat.h"
34
wrap_x2go_main(int argc,char ** argv)35 int wrap_x2go_main (int argc, char **argv) {
36 return (x2goMain (argc, argv));
37 }
38
39 #ifdef Q_OS_UNIX
fork_helper(int argc,char ** argv)40 int fork_helper (int argc, char **argv) {
41 /* Fork off to start helper process. */
42 pid_t tmp_pid = fork ();
43
44 /* Child. */
45 if (0 == tmp_pid) {
46 /* Starting unixhelper. */
47 std::vector<std::string> new_argv;
48 new_argv.push_back (std::string (argv[0]));
49 new_argv.push_back ("--unixhelper");
50
51 std::vector<char *> new_argv_c_str;
52 for (std::vector<std::string>::iterator it = new_argv.begin (); it != new_argv.end (); ++it) {
53 const char *elem = (*it).c_str ();
54 new_argv_c_str.push_back (strndup (elem, std::strlen (elem)));
55 }
56
57 /* Add null pointer as last element. */
58 new_argv_c_str.push_back (0);
59
60 if (0 != execvp (new_argv_c_str.front (), &(new_argv_c_str.front ()))) {
61 const int saved_errno = errno;
62 std::cerr << "Failed to re-execute process as UNIX cleanup helper tool: " << std::strerror (saved_errno) << "\n"
63 << "Terminating and killing parent." << "\n"
64 << "Please report a bug, refer to this documentation: https://wiki.x2go.org/doku.php/wiki:bugs" << std::endl;
65
66 pid_t parent_pid = getppid ();
67 if (0 != kill (parent_pid, SIGTERM)) {
68 const int saved_errno = errno;
69 std::cerr << "Failed to kill parent process: " << std::strerror (saved_errno) << std::endl;
70 }
71
72 std::exit (EXIT_FAILURE);
73 }
74
75 /* Anything here shall be unreachable. */
76 return (0);
77 }
78 /* Error. */
79 else if (-1 == tmp_pid) {
80 const int saved_errno = errno;
81 std::cerr << "Unable to create a new process for the UNIX cleanup watchdog: " << std::strerror (saved_errno) << "\n";
82 std::cerr << "Terminating. Please report a bug, refer to this documentation: https://wiki.x2go.org/doku.php/wiki:bugs" << std::endl;
83
84 std::exit (EXIT_FAILURE);
85 }
86 /* Parent. */
87 else {
88 /* Start real X2Go Client. */
89 return (wrap_x2go_main (argc, argv));
90 }
91 }
92 #endif /* defined (Q_OS_UNIX) */
93
main(int argc,char ** argv)94 int main (int argc, char **argv) {
95 #ifdef Q_OS_UNIX
96 /*
97 * Flags we don't need a cleanup helper for, since we know that X2Go Client
98 * will never spawn other processes.
99 *
100 * FIXME: What we'd actually want to have at this point (instead of a
101 * hardcoded list of parameters, anyway) is to use the argument parser
102 * from ONMainWindow (parseParameter). If this function returns false
103 * for any parameter, we know that we won't ever need the UNIX cleanup
104 * helper tool. Sadly, ONMainWindow is only started/available later,
105 * so we can't use any of its functionality here. We'd also need to
106 * make the function side-effect free. It should probably be
107 * refactored into a special options parser class.
108 */
109 const std::string bypass_flags[] = {
110 "--bypass-cleanup-helper",
111 "--help",
112 "--help-pack",
113 "--version",
114 "-v",
115 "--changelog",
116 "--git-info"
117 };
118
119 bool bypass_unix_helper = 0;
120 bool unix_helper_request = 0;
121 for (int i = 0; i < argc; ++i) {
122 /* No need to continue scanning if we got the information we were looking for. */
123 if ((bypass_unix_helper) && (unix_helper_request)) {
124 break;
125 }
126
127 std::string cur_arg (argv[i]);
128
129 /* Make the current argument lowercase. */
130 std::transform (cur_arg.begin (), cur_arg.end (), cur_arg.begin (), ::tolower);
131
132 if (!(cur_arg.empty ())) {
133 /* Scan program arguments for --unixhelper flag. */
134 if ((!(unix_helper_request)) && (0 == cur_arg.compare ("--unixhelper"))) {
135 unix_helper_request = 1;
136 }
137
138 /* Scan for flags bypassing the unix helper. */
139 if (!(bypass_unix_helper)) {
140 for (std::size_t y = 0; y < (sizeof (bypass_flags) / sizeof (*bypass_flags)); ++y) {
141 if (0 == cur_arg.compare (bypass_flags[y])) {
142 bypass_unix_helper = 1;
143 }
144 }
145 }
146 }
147 }
148
149 /* Sanity checks! */
150 if ((unix_helper_request) && (bypass_unix_helper)) {
151 std::cerr << "Re-execution in UNIX cleanup helper mode was requested, but a command line parameter that is supposed to "
152 << "disable the UNIX cleanup helper was found.\n"
153 << "Terminating. Please report a bug, refer to this documentation: https://wiki.x2go.org/doku.php/wiki:bugs" << std::endl;
154
155 return (EXIT_FAILURE);
156 }
157
158 if (bypass_unix_helper) {
159 return (wrap_x2go_main (argc, argv));
160 }
161 else {
162 if (unix_helper_request) {
163 /* We were instructed to start as the UNIX cleanup helper tool. */
164 return (unixhelper::unix_cleanup (getppid ()));
165 }
166 else {
167 /*
168 * setsid() may succeed and we become a session and process
169 * group leader, or it may fail indicating that we already
170 * are a process group leader. Either way is fine.
171 */
172 setsid ();
173
174 /* We should be process group leader by now. */
175 return (fork_helper (argc, argv));
176 }
177 }
178 #else /* defined (Q_OS_UNIX) */
179 return (wrap_x2go_main (argc, argv));
180 #endif /* defined (Q_OS_UNIX) */
181 }
182