1 mike 1.1.2.1 /*
2 //%2006////////////////////////////////////////////////////////////////////////
3 //
4 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
5 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
6 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
7 // IBM Corp.; EMC Corporation, The Open Group.
8 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
9 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
10 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
11 // EMC Corporation; VERITAS Software Corporation; The Open Group.
12 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
13 // EMC Corporation; Symantec Corporation; The Open Group.
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining a copy
16 // of this software and associated documentation files (the "Software"), to
17 // deal in the Software without restriction, including without limitation the
18 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19 // sell copies of the Software, and to permit persons to whom the Software is
20 // furnished to do so, subject to the following conditions:
21 //
22 mike 1.1.2.1 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
23 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
24 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
25 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
26 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 //%/////////////////////////////////////////////////////////////////////////////
32 */
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include "Config.h"
39 #include "Child.h"
40 #include "Parent.h"
41 #include "User.h"
42 #include "Fatal.h"
43 mike 1.1.2.1 #include "Process.h"
44 #include "Path.h"
45 #include "Globals.h"
46 #include "Socket.h"
|
47 mike 1.1.2.6 #include "Strlcpy.h"
|
48 mike 1.1.2.1 #include "Log.h"
|
49 mike 1.1.2.7 #include "Policy.h"
|
50 mike 1.1.2.8 #include "Macro.h"
|
51 mike 1.1.2.9 #include "Assert.h"
|
52 mike 1.1.2.1
53 /*
54 **==============================================================================
55 **
56 ** GetServerUser
57 **
|
58 mike 1.1.2.9 ** Determine which user to run CIMSERVERMAIN as.
|
59 mike 1.1.2.1 **
|
60 mike 1.1.2.4 ** Note: this algorithm is no longer in use.
61 **
|
62 mike 1.1.2.1 **==============================================================================
63 */
64
|
65 mike 1.1.2.4 int GetServerUser(int* uid, int* gid)
|
66 mike 1.1.2.1 {
|
67 mike 1.1.2.4 const char* username = PEGASUS_CIMSERVERMAIN_USER;
|
68 mike 1.1.2.1
|
69 mike 1.1.2.4 if (GetUserInfo(username, uid, gid) != 0)
|
70 mike 1.1.2.1 {
|
71 mike 1.1.2.4 Fatal(FL,
|
72 mike 1.1.2.9 "The %s user does not exist: \"%s\". Please create "
|
73 mike 1.1.2.4 "a system user with that name or use an OpenPegasus build that "
|
74 mike 1.1.2.9 "disables privilege separation.", CIMSERVERMAIN, username);
|
75 mike 1.1.2.1 }
76
77 return -1;
78 }
79
80 /*
81 **==============================================================================
82 **
83 ** ReadPidFile()
84 **
85 **==============================================================================
86 */
87
88 static int ReadPidFile(const char* path, int* pid)
89 {
90 FILE* is = fopen(path, "r");
91
92 if (!is)
93 return -1;
94
95 *pid = 0;
96 mike 1.1.2.1
97 fscanf(is, "%d\n", pid);
98 fclose(is);
99
100 if (*pid == 0)
101 return -1;
102
103 return 0;
104 }
105
106 /*
107 **==============================================================================
108 **
109 ** TestCimServerProcess()
110 **
111 ** Returns 0 if cimserver process is running.
112 **
113 **==============================================================================
114 */
115
116 int TestCimServerProcess()
117 mike 1.1.2.1 {
118 int pid;
119 char name[EXECUTOR_BUFFER_SIZE];
120
121 if (ReadPidFile(PEGASUS_CIMSERVER_START_FILE, &pid) != 0)
122 return -1;
123
124 if (GetProcessName(pid, name) != 0 || strcmp(name, CIMSERVERMAIN) != 0)
125 return -1;
126
127 return 0;
128 }
129
130 /*
131 **==============================================================================
132 **
133 ** ExecShutdown()
134 **
135 **==============================================================================
136 */
137
|
138 mike 1.1.2.9 void ExecShutdown()
|
139 mike 1.1.2.1 {
140 char* tmpArgv[3];
|
141 mike 1.1.2.9 const char* cimshutdownPath;
142 const char* shutdownTimeout;
|
143 mike 1.1.2.1
|
144 mike 1.1.2.6 /* Get shutdownTimeout configuration parameter. */
|
145 mike 1.1.2.1
|
146 mike 1.1.2.9 if ((shutdownTimeout = FindMacro("shutdownTimeout")) == NULL)
147 Fatal(FL, "failed to resolve shutdownTimeout");
|
148 mike 1.1.2.6
|
149 mike 1.1.2.9 /* Get absolute CIMSHUTDOWN program name. */
|
150 mike 1.1.2.1
|
151 mike 1.1.2.9 if ((cimshutdownPath = FindMacro("cimshutdownPath")) == NULL)
152 Fatal(FL, "failed to resolve cimshutdownPath");
|
153 mike 1.1.2.1
154 /* Create argument list. */
155
156 tmpArgv[0] = CIMSHUTDOWN;
|
157 mike 1.1.2.9 tmpArgv[1] = (char*)shutdownTimeout;
|
158 mike 1.1.2.1 tmpArgv[2] = 0;
159
160 /* Exec CIMSHUTDOWN program. */
161
162 /* Flawfinder: ignore */
163 execv(cimshutdownPath, tmpArgv);
164 Fatal(FL, "failed to exec %s", cimshutdownPath);
165 }
166
167 /*
168 **==============================================================================
169 **
|
170 mike 1.1.2.8 ** DefineExecutorMacros()
171 **
172 ** Define macros used by the executor.
173 **
174 **==============================================================================
175 */
176
177 void DefineExecutorMacros()
178 {
179 /* Define ${internalBinDir} */
180 {
181 char path[EXECUTOR_BUFFER_SIZE];
182
183 if (GetPegasusInternalBinDir(path) != 0)
184 Fatal(FL, "failed to resolve internal pegasus bin directory");
185
186 DefineMacro("internalBinDir", path);
187 }
188
|
189 mike 1.1.2.9 /* Define ${cimservermain} */
190
191 DefineMacro("cimservermain", CIMSERVERMAIN);
192
193 /* Define ${cimprovagt} */
194
195 DefineMacro("cimprovagt", CIMPROVAGT);
196
197 /* Define ${cimshutdown} */
198
199 DefineMacro("cimshutdown", CIMSHUTDOWN);
200
201 /* Define ${cimservera} */
202
203 DefineMacro("cimservera", CIMSERVERA);
204
|
205 mike 1.1.2.8 /* Define ${cimservermainPath} */
206 {
207 char path[EXECUTOR_BUFFER_SIZE];
208
|
209 mike 1.1.2.9 if (ExpandMacros("${internalBinDir}/${cimservermain}", path) != 0)
210 Fatal(FL, "failed to resolve cimservermainPath");
|
211 mike 1.1.2.8
212 DefineMacro("cimservermainPath", path);
213 }
214
215 /* Define ${cimprovagtPath} */
216 {
217 char path[EXECUTOR_BUFFER_SIZE];
218
|
219 mike 1.1.2.9 if (ExpandMacros("${internalBinDir}/${cimprovagt}", path) != 0)
220 Fatal(FL, "failed to resolve cimprovagtPath");
|
221 mike 1.1.2.8
222 DefineMacro("cimprovagtPath", path);
223 }
224
|
225 mike 1.1.2.9 /* Define ${cimshutdownPath} */
226 {
227 char path[EXECUTOR_BUFFER_SIZE];
228
229 if (ExpandMacros("${internalBinDir}/${cimshutdown}", path) != 0)
230 Fatal(FL, "failed to resolve cimshutdownPath");
231
232 DefineMacro("cimshutdownPath", path);
233 }
234
|
235 mike 1.1.2.8 /* Define ${cimserveraPath} */
236 {
237 char path[EXECUTOR_BUFFER_SIZE];
238
|
239 mike 1.1.2.9 if (ExpandMacros("${internalBinDir}/${cimservera}", path) != 0)
240 Fatal(FL, "failed to resolve cimserveraPath");
|
241 mike 1.1.2.8
242 DefineMacro("cimserveraPath", path);
243 }
244
|
245 mike 1.1.2.9 /* Define ${shutdownTimeout} */
246
247 {
248 char buffer[EXECUTOR_BUFFER_SIZE];
249
250 if (GetConfigParam("shutdownTimeout", buffer) != 0)
251 Strlcpy(buffer, "5", sizeof(buffer));
252
253 DefineMacro("shutdownTimeout", buffer);
254 }
255
|
256 mike 1.1.2.8 /* Define ${currentConfigFilePath} */
257 {
258 char path[EXECUTOR_BUFFER_SIZE];
259
260 if (GetHomedPath(PEGASUS_CURRENT_CONFIG_FILE_PATH, path) != 0)
261 {
262 Fatal(FL, "GetHomedPath() failed on \"%s\"",
263 PEGASUS_CURRENT_CONFIG_FILE_PATH);
264 }
265
266 DefineMacro("currentConfigFilePath", path);
267 }
268
269 /* Define ${repositoryDir} */
270
271 if (DefineConfigPathMacro("repositoryDir", PEGASUS_REPOSITORY_DIR) != 0)
272 Fatal(FL, "missing \"repositoryDir\" configuration parameter.");
273
274 /* Define ${passwordFilePath} */
275
276 if (DefineConfigPathMacro("passwordFilePath", "cimserver.passwd") != 0)
277 mike 1.1.2.8 Fatal(FL, "missing \"passwordFilePath\" configuration parameter.");
278
279 /* Define ${traceFilePath} */
280
281 if (DefineConfigPathMacro("traceFilePath", NULL) != 0)
282 Fatal(FL, "missing \"traceFilePath\" configuration parameter.");
283
284 /* Define ${sslKeyFilePath} */
285
286 if (DefineConfigPathMacro("sslKeyFilePath", "file.pem") != 0)
287 Fatal(FL, "missing \"sslKeyFilePath\" configuration parameter.");
288
289 /* Define ${sslTrustStore} */
290
291 if (DefineConfigPathMacro("sslTrustStore", "cimserver_trust") != 0)
292 Fatal(FL, "missing \"sslTrustStore\" configuration parameter.");
293
294 /* Define ${crlStore} */
295
296 if (DefineConfigPathMacro("crlStore", "crl") != 0)
297 Fatal(FL, "missing \"crlStore\" configuration parameter.");
298 mike 1.1.2.8 }
299
300 /*
301 **==============================================================================
302 **
303 ** TestFlagOption()
304 **
305 ** Check whether argv contains the given option. Return 0 if so. Else
306 ** return -1. Remove the argument from the list if the *remove* argument
307 ** is non-zero.
308 **
309 ** if (TestFlagOption(&argc, &argv, "--help", 0) == 0)
310 ** {
311 ** }
312 **
313 **==============================================================================
314 */
315
316 int TestFlagOption(int* argc_, char*** argv_, const char* option, int remove)
317 {
318 int argc = *argc_;
319 mike 1.1.2.8 char** argv = *argv_;
320 int i;
321
322 for (i = 0; i < argc; i++)
323 {
324 if (strcmp(argv[i], option) == 0)
325 {
326 if (remove)
327 {
328 memmove(&argv[i], &argv[i + 1], (argc-i) * sizeof(char*));
329 argc--;
330 }
331
332 *argc_ = argc;
333 *argv_ = argv;
334 return 0;
335 }
336 }
337
338 /* Not found */
339 return -1;
340 mike 1.1.2.8 }
341
342 /*
343 **==============================================================================
344 **
|
345 mike 1.1.2.1 ** main()
346 **
347 **==============================================================================
348 */
349
350 void doit();
351
352 int main(int argc, char** argv)
353 {
|
354 mike 1.1.2.9 const char* cimservermainPath;
|
355 mike 1.1.2.1 int pair[2];
356 char username[EXECUTOR_BUFFER_SIZE];
357 int childPid;
358 int perror;
|
359 mike 1.1.2.8 const char* repositoryDir;
|
360 mike 1.1.2.1
361 /* Save as global so it can be used in error and log messages. */
362
|
363 mike 1.1.2.8 globals.argc = argc;
364 globals.argv = argv;
|
365 mike 1.1.2.1
|
366 mike 1.1.2.8 /* Define macros needed by the executor. */
367
368 DefineExecutorMacros();
369
|
370 mike 1.1.2.9 /* If shuting down, then run CIMSHUTDOWN client. */
371
372 if (TestFlagOption(&argc, &argv, "-s", 0) == 0)
373 ExecShutdown();
374
|
375 mike 1.1.2.8 /* Check for --dump-policy option. */
376
377 if (TestFlagOption(&argc, &argv, "--dump-policy", 0) == 0)
|
378 mike 1.1.2.1 {
|
379 mike 1.1.2.8 DumpPolicy(1);
380 putchar('\n');
381 exit(0);
382 }
383
384 /* Check for --dump-macros option. */
385
386 if (TestFlagOption(&argc, &argv, "--dump-macros", 0) == 0)
387 {
388 DumpMacros();
389 putchar('\n');
390 exit(0);
|
391 mike 1.1.2.1 }
392
|
393 mike 1.1.2.9 /* Get absolute CIMSERVERMAIN program name. */
|
394 mike 1.1.2.6
|
395 mike 1.1.2.9 if ((cimservermainPath = FindMacro("cimservermainPath")) == NULL)
396 Fatal(FL, "Failed to locate %s program", CIMSERVERMAIN);
|
397 mike 1.1.2.6
|
398 mike 1.1.2.1 /* If CIMSERVERMAIN is already running, warn and exit now. */
399
400 if (TestCimServerProcess() == 0)
401 {
402 fprintf(stderr,
403 "%s: cimserver is already running (the PID found in the file "
404 "\"%s\" corresponds to an existing process named \"%s\").\n\n",
|
405 mike 1.1.2.8 globals.argv[0], PEGASUS_CIMSERVER_START_FILE, CIMSERVERMAIN);
|
406 mike 1.1.2.1
407 exit(1);
408 }
409
|
410 mike 1.1.2.2 /* Get enableAuthentication configuration option. */
411
412 {
413 char buffer[EXECUTOR_BUFFER_SIZE];
414
|
415 mike 1.1.2.9 if (GetConfigParam("enableAuthentication", buffer) == 0 &&
|
416 mike 1.1.2.2 strcasecmp(buffer, "true") == 0)
417 {
418 globals.enableAuthentication = 1;
419 }
420 }
421
|
422 mike 1.1.2.1 /* Create a socket pair for communicating with the child process. */
423
424 if (CreateSocketPair(pair) != 0)
|
425 mike 1.1.2.5 Fatal(FL, "Failed to create socket pair");
|
426 mike 1.1.2.1
427 CloseOnExec(pair[1]);
428
429 /* Get the log-level from the configuration parameter. */
430
431 GetLogLevel(argc, argv);
432
|
433 mike 1.1.2.8 /* Extract --perror option (directs syslog output to stderr). */
|
434 mike 1.1.2.1
435 perror = 0;
436
|
437 mike 1.1.2.8 if (TestFlagOption(&argc, &argv, "--perror", 1) == 0)
438 perror = 1;
|
439 mike 1.1.2.1
440 /* Open the log. */
441
442 OpenLog("cimexecutor", perror);
443
444 Log(LL_INFORMATION, "starting");
445
446 /* Be sure this process is running as root (otherwise fail). */
447
448 if (setuid(0) != 0 || setgid(0) != 0)
449 {
450 Log(LL_FATAL, "attempted to run program as non-root user");
|
451 mike 1.1.2.8 fprintf(stderr,
452 "%s: this program must be run as root\n", globals.argv[0]);
|
453 mike 1.1.2.1 exit(0);
454 }
455
|
456 mike 1.1.2.2 /* Warn if authentication not enabled (strange use of executor if not). */
457
458 if (!globals.enableAuthentication)
459 Log(LL_WARNING, "authentication is NOT enabled");
460 else
|
461 mike 1.1.2.3 Log(LL_TRACE, "authentication is enabled");
|
462 mike 1.1.2.2
|
463 mike 1.1.2.1 /* Print user info. */
464
465 if (GetUserName(getuid(), username) != 0)
466 Fatal(FL, "cannot resolve user from uid=%d", getuid());
467
468 Log(LL_TRACE, "running as %s (uid=%d, gid=%d)",
469 username, (int)getuid(), (int)getgid());
470
|
471 mike 1.1.2.9 /* Determine user for running CIMSERVERMAIN. */
|
472 mike 1.1.2.1
|
473 mike 1.1.2.4 GetServerUser(&globals.childUid, &globals.childGid);
|
474 mike 1.1.2.1
|
475 mike 1.1.2.8 /* Get repositoryDir for child. */
476
477 if ((repositoryDir = FindMacro("repositoryDir")) == NULL)
478 Fatal(FL, "failed to find repositoryDir macro");
479
|
480 mike 1.1.2.1 /* Fork child process. */
481
482 childPid = fork();
483
484 if (childPid == 0)
485 {
486 /* Child. */
487 close(pair[1]);
|
488 mike 1.1.2.8 Child(argc, argv, cimservermainPath, globals.childUid,
489 globals.childGid, pair[0], repositoryDir);
|
490 mike 1.1.2.1 }
491 else if (childPid > 0)
492 {
493 /* Parent. */
494 close(pair[0]);
495 Parent(pair[1], childPid);
496 }
497 else
498 {
499 Fatal(FL, "fork() failed");
500 }
501
502 return 0;
503 }
|