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