cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

unix.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
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, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <unix.h>
26 #include <exec_tools.h>
27 #include <file_lib.h>
28 
29 #ifdef HAVE_SYS_UIO_H
30 # include <sys/uio.h>
31 #endif
32 
33 #ifndef __MINGW32__
34 
35 /* Max size of the 'passwd' string in the getpwuid_r() function,
36  * man:getpwuid_r(3) says that this value "Should be more than enough". */
37 #define GETPW_R_SIZE_MAX 16384
38 
39 static bool IsProcessRunning(pid_t pid);
40 
41 void ProcessSignalTerminate(pid_t pid)
42 {
43  if(!IsProcessRunning(pid))
44  {
45  return;
46  }
47 
48 
49  if(kill(pid, SIGINT) == -1)
50  {
51  Log(LOG_LEVEL_ERR, "Could not send SIGINT to pid '%jd'. (kill: %s)",
52  (intmax_t)pid, GetErrorStr());
53  }
54 
55  sleep(1);
56  if (kill(pid, 0) != 0)
57  {
58  /* can no longer send signals to the process => it's dead now */
59  return;
60  }
61 
62  if(kill(pid, SIGTERM) == -1)
63  {
64  Log(LOG_LEVEL_ERR, "Could not send SIGTERM to pid '%jd'. (kill: %s)",
65  (intmax_t)pid, GetErrorStr());
66  }
67 
68  sleep(5);
69  if (kill(pid, 0) != 0)
70  {
71  /* can no longer send signals to the process => it's dead now */
72  return;
73  }
74 
75  if(kill(pid, SIGKILL) == -1)
76  {
77  Log(LOG_LEVEL_ERR, "Could not send SIGKILL to pid '%jd'. (kill: %s)",
78  (intmax_t)pid, GetErrorStr());
79  }
80 
81  sleep(1);
82 }
83 
84 /*************************************************************/
85 
86 static bool IsProcessRunning(pid_t pid)
87 {
88  int res = kill(pid, 0);
89 
90  if(res == 0)
91  {
92  return true;
93  }
94 
95  if(res == -1 && errno == ESRCH)
96  {
97  return false;
98  }
99 
100  Log(LOG_LEVEL_ERR, "Failed checking for process existence. (kill: %s)", GetErrorStr());
101 
102  return false;
103 }
104 
105 /*************************************************************/
106 
107 bool GetCurrentUserName(char *userName, int userNameLen)
108 {
109  char buf[GETPW_R_SIZE_MAX] = {0};
110  struct passwd pwd;
111  struct passwd *result;
112 
113  memset(userName, 0, userNameLen);
114  int ret = getpwuid_r(getuid(), &pwd, buf, GETPW_R_SIZE_MAX, &result);
115 
116  if (result == NULL)
117  {
118  Log(LOG_LEVEL_ERR, "Could not get user name of current process, using 'UNKNOWN'. (getpwuid: %s)",
119  ret == 0 ? "not found" : GetErrorStrFromCode(ret));
120  strlcpy(userName, "UNKNOWN", userNameLen);
121  return false;
122  }
123 
124  strlcpy(userName, result->pw_name, userNameLen);
125  return true;
126 }
127 
128 /*************************************************************/
129 
130 bool IsExecutable(const char *file)
131 {
132  struct stat sb;
133  gid_t grps[NGROUPS];
134  int n;
135 
136  if (stat(file, &sb) == -1)
137  {
138  Log(LOG_LEVEL_ERR, "Proposed executable file '%s' doesn't exist", file);
139  return false;
140  }
141 
142  if (sb.st_mode & 02)
143  {
144  Log(LOG_LEVEL_ERR, "SECURITY ALERT: promised executable '%s' is world writable! ", file);
145  Log(LOG_LEVEL_ERR, "SECURITY ALERT: CFEngine will not execute this - requires human inspection");
146  return false;
147  }
148 
149  if ((getuid() == sb.st_uid) || (getuid() == 0))
150  {
151  if (sb.st_mode & 0100)
152  {
153  return true;
154  }
155  }
156  else if (getgid() == sb.st_gid)
157  {
158  if (sb.st_mode & 0010)
159  {
160  return true;
161  }
162  }
163  else
164  {
165  if (sb.st_mode & 0001)
166  {
167  return true;
168  }
169 
170  if ((n = getgroups(NGROUPS, grps)) > 0)
171  {
172  int i;
173 
174  for (i = 0; i < n; i++)
175  {
176  if (grps[i] == sb.st_gid)
177  {
178  if (sb.st_mode & 0010)
179  {
180  return true;
181  }
182  }
183  }
184  }
185  }
186 
187  return false;
188 }
189 
190 bool ShellCommandReturnsZero(const char *command, ShellType shell)
191 {
192  int status;
193  pid_t pid;
194 
195  if (shell == SHELL_TYPE_POWERSHELL)
196  {
197  Log(LOG_LEVEL_ERR, "Powershell is only supported on Windows");
198  return false;
199  }
200 
201  if ((pid = fork()) < 0)
202  {
203  Log(LOG_LEVEL_ERR, "Failed to fork new process: %s", command);
204  return false;
205  }
206  else if (pid == 0) /* child */
207  {
208  ALARM_PID = -1;
209 
210  if (shell == SHELL_TYPE_USE)
211  {
212  if (execl(SHELL_PATH, "sh", "-c", command, NULL) == -1)
213  {
214  Log(LOG_LEVEL_ERR, "Command '%s' failed. (execl: %s)", command, GetErrorStr());
215  exit(EXIT_FAILURE); /* OK since this is a forked proc and no registered cleanup functions */
216  }
217  }
218  else
219  {
220  char **argv = ArgSplitCommand(command);
221  int devnull;
222 
224  {
225  if ((devnull = open("/dev/null", O_WRONLY)) == -1)
226  {
227  Log(LOG_LEVEL_ERR, "Command '%s' failed. (open: %s)", command, GetErrorStr());
228  exit(EXIT_FAILURE); /* OK since this is a forked proc and no registered cleanup functions */
229  }
230 
231  if (dup2(devnull, STDOUT_FILENO) == -1 || dup2(devnull, STDERR_FILENO) == -1)
232  {
233  Log(LOG_LEVEL_ERR, "Command '%s' failed. (dup2: %s)", command, GetErrorStr());
234  exit(EXIT_FAILURE); /* OK since this is a forked proc and no registered cleanup functions */
235  }
236 
237  close(devnull);
238  }
239 
240  if (execv(argv[0], argv) == -1)
241  {
242  Log(LOG_LEVEL_ERR, "Command '%s' failed. (execv: %s)", argv[0], GetErrorStr());
243  exit(EXIT_FAILURE); /* OK since this is a forked proc and no registered cleanup functions */
244  }
245  }
246  }
247  else /* parent */
248  {
249  ALARM_PID = pid;
250 
251  while (waitpid(pid, &status, 0) < 0)
252  {
253  if (errno != EINTR)
254  {
255  return false;
256  }
257  }
258 
259  return (WEXITSTATUS(status) == 0);
260  }
261 
262  return false;
263 }
264 
265 #endif /* !__MINGW32__ */
ShellType
Definition: cf3.defs.h:1105
@ SHELL_TYPE_USE
Definition: cf3.defs.h:1107
@ SHELL_TYPE_POWERSHELL
Definition: cf3.defs.h:1108
pid_t ALARM_PID
Definition: cf3globals.c:112
char ** ArgSplitCommand(const char *comm)
Definition: exec_tools.c:256
int errno
#define NULL
Definition: getopt1.c:56
const char * GetErrorStrFromCode(int error_code)
Definition: logging.c:270
LogLevel LogGetGlobalLevel(void)
Definition: logging.c:581
const char * GetErrorStr(void)
Definition: logging.c:275
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_INFO
Definition: logging.h:45
uid_t getuid(void)
gid_t getgid(void)
unsigned int sleep(unsigned int seconds)
#define NGROUPS
Definition: platform.h:720
#define WEXITSTATUS(s)
Definition: platform.h:141
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:34
bool GetCurrentUserName(char *userName, int userNameLen)
Definition: unix.c:107
#define GETPW_R_SIZE_MAX
Definition: unix.c:37
static bool IsProcessRunning(pid_t pid)
Definition: unix.c:86
bool ShellCommandReturnsZero(const char *command, ShellType shell)
Definition: unix.c:190
void ProcessSignalTerminate(pid_t pid)
Definition: unix.c:41
bool IsExecutable(const char *file)
Definition: unix.c:130