• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <grp.h>
17 #include <pwd.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include "daemon_common.h"
21 #if defined(SURPPORT_SELINUX)
22 #include "selinux/selinux.h"
23 #endif
24 using namespace Hdc;
25 
26 static bool g_enableUsb = false;
27 #ifdef HDC_SUPPORT_UART
28 static bool g_enableUart = false;
29 #endif
30 static bool g_enableTcp = false;
31 #ifdef HDC_EMULATOR
32 static bool g_enableBridge = false;
33 #endif
34 static bool g_backgroundRun = false;
35 namespace Hdc {
RestartDaemon(bool forkchild)36 bool RestartDaemon(bool forkchild)
37 {
38     char path[256] = "";
39     size_t nPathSize = 256;
40     uv_exepath(path, &nPathSize);
41     execl(path, "hdcd", forkchild ? "-forkchild" : nullptr, nullptr);
42     return true;
43 }
44 
CheckTcpAndUSBSwitch(void)45 void CheckTcpAndUSBSwitch(void)
46 {
47     string modeValue;
48     if (SystemDepend::GetDevItem("persist.hdc.mode.tcp", modeValue)) {
49         g_enableTcp = (modeValue == "enable");
50         WRITE_LOG(LOG_INFO, "Property %s TCP", modeValue.c_str());
51     }
52     modeValue.clear();
53     if (SystemDepend::GetDevItem("persist.hdc.mode.usb", modeValue)) {
54         g_enableUsb = (modeValue == "enable");
55         WRITE_LOG(LOG_INFO, "Property %s USB", modeValue.c_str());
56     }
57     return;
58 }
59 
DisableTcpAndUSB(void)60 void DisableTcpAndUSB(void)
61 {
62     g_enableTcp = false;
63     g_enableUsb = false;
64     WRITE_LOG(LOG_INFO, "Disable USB and TCP");
65 }
66 
ForkChildCheck(int argc,const char * argv[])67 bool ForkChildCheck(int argc, const char *argv[])
68 {
69     // hdcd        #service start foreground
70     // hdcd -b     #service start backgroundRun
71     // hdcd -fork  #fork
72     Base::PrintMessage("Background mode, persist.hdc.mode");
73     /*
74      * First, check persist.hdc.mode.tcp or persist.hdc.mode.usb to enable usb/tcp channel
75      * Second, check persist.hdc.mode to enable corresponding channels
76     */
77     CheckTcpAndUSBSwitch();
78     string workMode;
79     SystemDepend::GetDevItem("persist.hdc.mode", workMode);
80     workMode = Base::Trim(workMode);
81     WRITE_LOG(LOG_INFO, "persist.hdc.mode is %s", workMode.c_str());
82     if (workMode == "all") {
83         WRITE_LOG(LOG_DEBUG, "Property enable USB and TCP");
84         g_enableUsb = true;
85         g_enableTcp = true;
86 #ifdef HDC_SUPPORT_UART
87         g_enableUart = true;
88 #endif
89 #ifdef HDC_SUPPORT_UART
90     } else if (workMode == CMDSTR_TMODE_UART) {
91         WRITE_LOG(LOG_DEBUG, "Property enable UART");
92         g_enableUart = true;
93         DisableTcpAndUSB();
94 #endif
95 #ifdef HDC_EMULATOR
96     } else if (workMode == CMDSTR_TMODE_BRIDGE || workMode.empty()) {
97         WRITE_LOG(LOG_DEBUG, "Property enable Bridge");
98         g_enableBridge = true;
99         DisableTcpAndUSB();
100 #endif
101     } else {
102         if (workMode != CMDSTR_TMODE_USB && workMode != CMDSTR_TMODE_TCP) {
103 #ifdef HDC_SUPPORT_UART
104             WRITE_LOG(LOG_DEBUG, "Default UART mode");
105             g_enableUart = true;
106 #endif
107         }
108     }
109     if (argc == CMD_ARG1_COUNT) {
110         if (!strcmp(argv[1], "-forkchild")) {
111             g_backgroundRun = false;  // forkchild,Forced foreground
112         } else if (!strcmp(argv[1], "-b")) {
113             g_backgroundRun = true;
114         }
115     }
116     return true;
117 }
118 
CheckUvThreadConfig()119 static size_t CheckUvThreadConfig()
120 {
121     return SystemDepend::GetDevUint("persist.hdc.uv.threads", SIZE_THREAD_POOL);
122 }
123 
BackgroundRun()124 int BackgroundRun()
125 {
126     pid_t pc = fork();  // create process as daemon process
127     if (pc < 0) {
128         return -1;
129     } else if (!pc) {
130         int i;
131         const int MAX_NUM = 64;
132         for (i = 0; i < MAX_NUM; ++i) {
133             int fd = i;
134             Base::CloseFd(fd);
135         }
136         RestartDaemon(true);
137     } else {  // >0 orig process
138     }
139     return 0;
140 }
141 
DaemonUsage()142 string DaemonUsage()
143 {
144     string ret = "";
145     ret = "\n                         Harmony device connector daemon(HDCD) Usage: hdcd [options]...\n\n"
146           "\n"
147           "general options:\n"
148           " -h                            - Print help\n"
149           " -l 0-5                        - Print runtime log\n"
150           "\n"
151           "daemon mode options:\n"
152           " -b                            - Daemon run in background/fork mode\n"
153 #ifdef HDC_SUPPORT_UART
154           " -i                            - Enable UART mode\n"
155 #endif
156           " -u                            - Enable USB mode\n"
157           " -t                            - Enable TCP mode\n";
158     return ret;
159 }
160 
GetDaemonCommandlineOptions(int argc,const char * argv[])161 bool GetDaemonCommandlineOptions(int argc, const char *argv[])
162 {
163     int ch;
164     // hdcd -l4 ...
165     WRITE_LOG(LOG_DEBUG, "Foreground cli-mode");
166     // Both settings are running with parameters
167     while ((ch = getopt(argc, const_cast<char *const *>(argv), "utl:")) != -1) {
168         switch (ch) {
169             case 'l': {
170                 int logLevel = atoi(optarg);
171                 if (logLevel < 0 || logLevel > LOG_LAST) {
172                     WRITE_LOG(LOG_DEBUG, "Loglevel error!\n");
173                     return -1;
174                 }
175                 Base::SetLogLevel(logLevel);
176                 break;
177             }
178             case 'u': {
179                 Base::PrintMessage("Option USB enabled");
180                 g_enableUsb = true;
181                 break;
182             }
183             case 't': {
184                 Base::PrintMessage("Option TCP enabled");
185                 g_enableTcp = true;
186                 break;
187             }
188 #ifdef HDC_SUPPORT_UART
189             case 'i': { // enable uart
190                 Base::PrintMessage("Parament Enable UART");
191                 g_enableUart = true;
192                 break;
193             }
194 #endif
195             default:
196                 Base::PrintMessage("Option:%c non-supported!", ch);
197                 exit(0);
198                 break;
199         }
200     }
201     return true;
202 }
203 
DropRootPrivileges()204 bool DropRootPrivileges()
205 {
206     int ret;
207     const char *userName = "shell";
208     vector<const char *> groupsNames = { "shell", "log", "readproc", "file_manager" };
209     struct passwd *user;
210     gid_t *gids = nullptr;
211 
212     user = getpwnam(userName);
213     if (user == nullptr) {
214         WRITE_LOG(LOG_FATAL, "getpwuid %s fail, %s", userName, strerror(errno));
215         return false;
216     }
217 
218     gids = static_cast<gid_t *>(calloc(groupsNames.size(), sizeof(gid_t)));
219     if (gids == nullptr) {
220         WRITE_LOG(LOG_FATAL, "calloc fail");
221         return false;
222     }
223 
224     for (size_t i = 0; i < groupsNames.size(); i++) {
225         struct group *group = getgrnam(groupsNames[i]);
226         if (group == nullptr) {
227             WRITE_LOG(LOG_FATAL, "calloc fail");
228             continue;
229         }
230         gids[i] = group->gr_gid;
231     }
232 
233     ret = setuid(user->pw_uid);
234     if (ret) {
235         WRITE_LOG(LOG_FATAL, "setuid %s fail, %s", userName, strerror(errno));
236         free(gids);
237         return false;
238     }
239 
240     ret = setgid(user->pw_gid);
241     if (ret) {
242         WRITE_LOG(LOG_FATAL, "setgid %s fail, %s", userName, strerror(errno));
243         free(gids);
244         return false;
245     }
246 
247     ret = setgroups(groupsNames.size(), gids);
248     if (ret) {
249         WRITE_LOG(LOG_FATAL, "setgroups %s fail, %s", userName, strerror(errno));
250         free(gids);
251         return false;
252     }
253 
254     free(gids);
255 #if defined(SURPPORT_SELINUX)
256     if (setcon("u:r:hdcd:s0") != 0) {
257         WRITE_LOG(LOG_FATAL, "setcon fail, errno %s", userName, strerror(errno));
258     }
259 #endif
260     return true;
261 }
262 
NeedDropRootPrivileges()263 bool NeedDropRootPrivileges()
264 {
265     string rootMode;
266     string debugMode;
267     SystemDepend::GetDevItem("const.debuggable", debugMode);
268     SystemDepend::GetDevItem("persist.hdc.root", rootMode);
269     if (debugMode == "1") {
270         if (rootMode == "1") {
271             int rc = setuid(0);
272             if (rc != 0) {
273                 char buffer[BUF_SIZE_DEFAULT] = { 0 };
274                 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
275                 WRITE_LOG(LOG_FATAL, "setuid(0) fail %s", buffer);
276             }
277             WRITE_LOG(LOG_DEBUG, "Root run rc:%d", rc);
278         } else if (rootMode == "0") {
279             if (getuid() == 0) {
280                 return DropRootPrivileges();
281             }
282         }
283         // default keep root
284     } else {
285         return DropRootPrivileges();
286     }
287     return true;
288 }
289 } // namespace Hdc
290 
291 #ifndef UNIT_TEST
292 // daemon running with default behavior. options also can be given to custom its behavior including b/t/u/l etc.
main(int argc,const char * argv[])293 int main(int argc, const char *argv[])
294 {
295 #ifdef CONFIG_USE_JEMALLOC_DFX_INIF
296     mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
297     mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
298 #endif
299 #ifndef UPDATER_MODE
300     string developerMode;
301     SystemDepend::GetDevItem("const.security.developermode.state", developerMode);
302     if (developerMode != "true") {
303         WRITE_LOG(LOG_FATAL, "non developer mode, hdcd does not start");
304         return -1;
305     }
306 #endif
307     // check property
308     if (argc == CMD_ARG1_COUNT && !strcmp(argv[1], "-h")) {
309         string usage = DaemonUsage();
310         fprintf(stderr, "%s", usage.c_str());
311         return 0;
312     }
313     if (argc == CMD_ARG1_COUNT && !strcmp(argv[1], "-v")) {
314         string ver = Hdc::Base::GetVersion();
315         fprintf(stderr, "%s\n", ver.c_str());
316         return 0;
317     }
318     if (argc == 1 || (argc == CMD_ARG1_COUNT && (!strcmp(argv[1], "-forkchild") || !strcmp(argv[1], "-b")))) {
319         ForkChildCheck(argc, argv);
320     } else {
321         GetDaemonCommandlineOptions(argc, argv);
322     }
323     if (!g_enableTcp && !g_enableUsb) {
324 #ifdef HDC_EMULATOR
325 #ifdef HDC_SUPPORT_UART
326         if (!g_enableBridge && !g_enableUart) {
327             Base::PrintMessageAndWriteLog("TCP, USB, Bridge and Uart are disable, cannot run continue");
328             return -1;
329         }
330 #else
331         if (!g_enableBridge) {
332             Base::PrintMessageAndWriteLog("Both TCP, Bridge and USB are disable, cannot run continue");
333             return -1;
334         }
335 #endif
336 #else
337 #ifdef HDC_SUPPORT_UART
338         if (!g_enableUart) {
339             Base::PrintMessageAndWriteLog("TCP, USB and Uart are disable, cannot run continue");
340             return -1;
341         }
342 #else
343         Base::PrintMessageAndWriteLog("Both TCP and USB are disable, cannot run continue");
344         return -1;
345 #endif
346 #endif
347     }
348     if (g_backgroundRun) {
349         return BackgroundRun();
350     }
351     string debugMode;
352     SystemDepend::GetDevItem("const.debuggable", debugMode);
353     if (debugMode == "1") {
354         if (!NeedDropRootPrivileges()) {
355             Base::PrintMessageAndWriteLog("DropRootPrivileges fail, EXITING...");
356             return -1;
357         }
358         WRITE_LOG(LOG_INFO, "HdcDaemon run as root mode.");
359     } else {
360         WRITE_LOG(LOG_INFO, "HdcDaemon run as user mode.");
361     }
362 
363     Base::InitProcess();
364     WRITE_LOG(LOG_DEBUG, "HdcDaemon main run");
365     HdcDaemon daemon(false, CheckUvThreadConfig());
366 
367 #ifdef HDC_EMULATOR
368 #ifdef HDC_SUPPORT_UART
369     daemon.InitMod(g_enableTcp, g_enableUsb, g_enableBridge, g_enableUart);
370 #else
371     daemon.InitMod(g_enableTcp, g_enableUsb, g_enableBridge);
372 #endif
373 #else
374 #ifdef HDC_SUPPORT_UART
375     daemon.InitMod(g_enableTcp, g_enableUsb, g_enableUart);
376 #else
377     daemon.InitMod(g_enableTcp, g_enableUsb);
378 #endif
379 #endif
380     daemon.ClearKnownHosts();
381     daemon.WorkerPendding();
382     bool wantRestart = daemon.WantRestart();
383     WRITE_LOG(LOG_DEBUG, "Daemon finish wantRestart %d", wantRestart);
384     // There is no daemon, we can only restart myself.
385     if (wantRestart) {
386         // just root can self restart, low privilege will be exit and start by service(root)
387         WRITE_LOG(LOG_INFO, "Daemon restart");
388         RestartDaemon(false);
389     }
390 #ifdef HDC_SUPPORT_UART
391     // when no usb insert , device will hung here , we don't know why.
392     // Test the command "smode -r" in uart mode, then execute shell
393     // hdcd will not really exit until usb plug in
394     // so we use abort here
395     _exit(0);
396 #endif
397     return 0;
398 }
399 #endif
400