1 /*
2  * Copyright 2004-2021 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #ifndef _GNU_SOURCE
13 #  define _GNU_SOURCE
14 #endif
15 
16 #include <sys/types.h>
17 #include <sys/wait.h>
18 #include <sys/stat.h>
19 #include <sys/utsname.h>
20 
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <limits.h>
26 #include <pwd.h>
27 #include <time.h>
28 #include <libgen.h>
29 #include <signal.h>
30 
31 #include <qb/qbdefs.h>
32 
33 #include <crm/crm.h>
34 #include <crm/services.h>
35 #include <crm/msg_xml.h>
36 #include <crm/cib/internal.h>
37 #include <crm/common/xml.h>
38 #include <crm/common/util.h>
39 #include <crm/common/ipc.h>
40 #include <crm/common/iso8601.h>
41 #include <crm/common/mainloop.h>
42 #include <libxml2/libxml/relaxng.h>
43 
44 #include "crmcommon_private.h"
45 
46 #ifndef PW_BUFFER_LEN
47 #  define PW_BUFFER_LEN		500
48 #endif
49 
50 CRM_TRACE_INIT_DATA(common);
51 
52 gboolean crm_config_error = FALSE;
53 gboolean crm_config_warning = FALSE;
54 char *crm_system_name = NULL;
55 
56 int pcmk__score_red = 0;
57 int pcmk__score_green = 0;
58 int pcmk__score_yellow = 0;
59 
60 int
char2score(const char * score)61 char2score(const char *score)
62 {
63     int score_f = 0;
64 
65     if (score == NULL) {
66 
67     } else if (pcmk_str_is_minus_infinity(score)) {
68         score_f = -CRM_SCORE_INFINITY;
69 
70     } else if (pcmk_str_is_infinity(score)) {
71         score_f = CRM_SCORE_INFINITY;
72 
73     } else if (pcmk__str_eq(score, "red", pcmk__str_casei)) {
74         score_f = pcmk__score_red;
75 
76     } else if (pcmk__str_eq(score, "yellow", pcmk__str_casei)) {
77         score_f = pcmk__score_yellow;
78 
79     } else if (pcmk__str_eq(score, "green", pcmk__str_casei)) {
80         score_f = pcmk__score_green;
81 
82     } else {
83         long long score_ll;
84 
85         pcmk__scan_ll(score, &score_ll, 0LL);
86         if (score_ll > CRM_SCORE_INFINITY) {
87             score_f = CRM_SCORE_INFINITY;
88 
89         } else if (score_ll < -CRM_SCORE_INFINITY) {
90             score_f = -CRM_SCORE_INFINITY;
91 
92         } else {
93             score_f = (int) score_ll;
94         }
95     }
96 
97     return score_f;
98 }
99 
100 char *
score2char_stack(int score,char * buf,size_t len)101 score2char_stack(int score, char *buf, size_t len)
102 {
103     CRM_CHECK((buf != NULL) && (len >= sizeof(CRM_MINUS_INFINITY_S)),
104               return NULL);
105 
106     if (score >= CRM_SCORE_INFINITY) {
107         strncpy(buf, CRM_INFINITY_S, 9);
108     } else if (score <= -CRM_SCORE_INFINITY) {
109         strncpy(buf, CRM_MINUS_INFINITY_S , 10);
110     } else {
111         snprintf(buf, len, "%d", score);
112     }
113     return buf;
114 }
115 
116 char *
score2char(int score)117 score2char(int score)
118 {
119     if (score >= CRM_SCORE_INFINITY) {
120         return strdup(CRM_INFINITY_S);
121 
122     } else if (score <= -CRM_SCORE_INFINITY) {
123         return strdup(CRM_MINUS_INFINITY_S);
124     }
125     return pcmk__itoa(score);
126 }
127 
128 int
crm_user_lookup(const char * name,uid_t * uid,gid_t * gid)129 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
130 {
131     int rc = pcmk_ok;
132     char *buffer = NULL;
133     struct passwd pwd;
134     struct passwd *pwentry = NULL;
135 
136     buffer = calloc(1, PW_BUFFER_LEN);
137     if (buffer == NULL) {
138         return -ENOMEM;
139     }
140 
141     rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
142     if (pwentry) {
143         if (uid) {
144             *uid = pwentry->pw_uid;
145         }
146         if (gid) {
147             *gid = pwentry->pw_gid;
148         }
149         crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
150 
151     } else {
152         rc = rc? -rc : -EINVAL;
153         crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
154     }
155 
156     free(buffer);
157     return rc;
158 }
159 
160 /*!
161  * \brief Get user and group IDs of pacemaker daemon user
162  *
163  * \param[out] uid  If non-NULL, where to store daemon user ID
164  * \param[out] gid  If non-NULL, where to store daemon group ID
165  *
166  * \return pcmk_ok on success, -errno otherwise
167  */
168 int
pcmk_daemon_user(uid_t * uid,gid_t * gid)169 pcmk_daemon_user(uid_t *uid, gid_t *gid)
170 {
171     static uid_t daemon_uid;
172     static gid_t daemon_gid;
173     static bool found = false;
174     int rc = pcmk_ok;
175 
176     if (!found) {
177         rc = crm_user_lookup(CRM_DAEMON_USER, &daemon_uid, &daemon_gid);
178         if (rc == pcmk_ok) {
179             found = true;
180         }
181     }
182     if (found) {
183         if (uid) {
184             *uid = daemon_uid;
185         }
186         if (gid) {
187             *gid = daemon_gid;
188         }
189     }
190     return rc;
191 }
192 
193 /*!
194  * \internal
195  * \brief Return the integer equivalent of a portion of a string
196  *
197  * \param[in]  text      Pointer to beginning of string portion
198  * \param[out] end_text  This will point to next character after integer
199  */
200 static int
version_helper(const char * text,const char ** end_text)201 version_helper(const char *text, const char **end_text)
202 {
203     int atoi_result = -1;
204 
205     CRM_ASSERT(end_text != NULL);
206 
207     errno = 0;
208 
209     if (text != NULL && text[0] != 0) {
210         /* seemingly sacrificing const-correctness -- because while strtol
211            doesn't modify the input, it doesn't want to artificially taint the
212            "end_text" pointer-to-pointer-to-first-char-in-string with constness
213            in case the input wasn't actually constant -- by semantic definition
214            not a single character will get modified so it shall be perfectly
215            safe to make compiler happy with dropping "const" qualifier here */
216         atoi_result = (int) strtol(text, (char **) end_text, 10);
217 
218         if (errno == EINVAL) {
219             crm_err("Conversion of '%s' %c failed", text, text[0]);
220             atoi_result = -1;
221         }
222     }
223     return atoi_result;
224 }
225 
226 /*
227  * version1 < version2 : -1
228  * version1 = version2 :  0
229  * version1 > version2 :  1
230  */
231 int
compare_version(const char * version1,const char * version2)232 compare_version(const char *version1, const char *version2)
233 {
234     int rc = 0;
235     int lpc = 0;
236     const char *ver1_iter, *ver2_iter;
237 
238     if (version1 == NULL && version2 == NULL) {
239         return 0;
240     } else if (version1 == NULL) {
241         return -1;
242     } else if (version2 == NULL) {
243         return 1;
244     }
245 
246     ver1_iter = version1;
247     ver2_iter = version2;
248 
249     while (1) {
250         int digit1 = 0;
251         int digit2 = 0;
252 
253         lpc++;
254 
255         if (ver1_iter == ver2_iter) {
256             break;
257         }
258 
259         if (ver1_iter != NULL) {
260             digit1 = version_helper(ver1_iter, &ver1_iter);
261         }
262 
263         if (ver2_iter != NULL) {
264             digit2 = version_helper(ver2_iter, &ver2_iter);
265         }
266 
267         if (digit1 < digit2) {
268             rc = -1;
269             break;
270 
271         } else if (digit1 > digit2) {
272             rc = 1;
273             break;
274         }
275 
276         if (ver1_iter != NULL && *ver1_iter == '.') {
277             ver1_iter++;
278         }
279         if (ver1_iter != NULL && *ver1_iter == '\0') {
280             ver1_iter = NULL;
281         }
282 
283         if (ver2_iter != NULL && *ver2_iter == '.') {
284             ver2_iter++;
285         }
286         if (ver2_iter != NULL && *ver2_iter == 0) {
287             ver2_iter = NULL;
288         }
289     }
290 
291     if (rc == 0) {
292         crm_trace("%s == %s (%d)", version1, version2, lpc);
293     } else if (rc < 0) {
294         crm_trace("%s < %s (%d)", version1, version2, lpc);
295     } else if (rc > 0) {
296         crm_trace("%s > %s (%d)", version1, version2, lpc);
297     }
298 
299     return rc;
300 }
301 
302 /*!
303  * \brief Parse milliseconds from a Pacemaker interval specification
304  *
305  * \param[in] input  Pacemaker time interval specification (a bare number of
306  *                   seconds, a number with a unit optionally with whitespace
307  *                   before and/or after the number, or an ISO 8601 duration)
308  *
309  * \return Milliseconds equivalent of given specification on success (limited
310  *         to the range of an unsigned integer), 0 if input is NULL,
311  *         or 0 (and set errno to EINVAL) on error
312  */
313 guint
crm_parse_interval_spec(const char * input)314 crm_parse_interval_spec(const char *input)
315 {
316     long long msec = -1;
317 
318     errno = 0;
319     if (input == NULL) {
320         return 0;
321 
322     } else if (input[0] == 'P') {
323         crm_time_t *period_s = crm_time_parse_duration(input);
324 
325         if (period_s) {
326             msec = 1000 * crm_time_get_seconds(period_s);
327             crm_time_free(period_s);
328         }
329 
330     } else {
331         msec = crm_get_msec(input);
332     }
333 
334     if (msec < 0) {
335         crm_warn("Using 0 instead of '%s'", input);
336         errno = EINVAL;
337         return 0;
338     }
339     return (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
340 }
341 
342 /*!
343  * \internal
344  * \brief Log a failed assertion
345  *
346  * \param[in] file              File making the assertion
347  * \param[in] function          Function making the assertion
348  * \param[in] line              Line of file making the assertion
349  * \param[in] assert_condition  String representation of assertion
350  */
351 static void
log_assertion_as(const char * file,const char * function,int line,const char * assert_condition)352 log_assertion_as(const char *file, const char *function, int line,
353                  const char *assert_condition)
354 {
355     if (!pcmk__is_daemon) {
356         crm_enable_stderr(TRUE); // Make sure command-line user sees message
357     }
358     crm_err("%s: Triggered fatal assertion at %s:%d : %s",
359             function, file, line, assert_condition);
360 }
361 
362 /* coverity[+kill] */
363 /*!
364  * \internal
365  * \brief Log a failed assertion and abort
366  *
367  * \param[in] file              File making the assertion
368  * \param[in] function          Function making the assertion
369  * \param[in] line              Line of file making the assertion
370  * \param[in] assert_condition  String representation of assertion
371  *
372  * \note This does not return
373  */
374 static _Noreturn void
abort_as(const char * file,const char * function,int line,const char * assert_condition)375 abort_as(const char *file, const char *function, int line,
376          const char *assert_condition)
377 {
378     log_assertion_as(file, function, line, assert_condition);
379     abort();
380 }
381 
382 /* coverity[+kill] */
383 /*!
384  * \internal
385  * \brief Handle a failed assertion
386  *
387  * When called by a daemon, fork a child that aborts (to dump core), otherwise
388  * abort the current process.
389  *
390  * \param[in] file              File making the assertion
391  * \param[in] function          Function making the assertion
392  * \param[in] line              Line of file making the assertion
393  * \param[in] assert_condition  String representation of assertion
394  */
395 static void
fail_assert_as(const char * file,const char * function,int line,const char * assert_condition)396 fail_assert_as(const char *file, const char *function, int line,
397                const char *assert_condition)
398 {
399     int status = 0;
400     pid_t pid = 0;
401 
402     if (!pcmk__is_daemon) {
403         abort_as(file, function, line, assert_condition); // does not return
404     }
405 
406     pid = fork();
407     switch (pid) {
408         case -1: // Fork failed
409             crm_warn("%s: Cannot dump core for non-fatal assertion at %s:%d "
410                      ": %s", function, file, line, assert_condition);
411             break;
412 
413         case 0: // Child process: just abort to dump core
414             abort();
415             break;
416 
417         default: // Parent process: wait for child
418             crm_err("%s: Forked child [%d] to record non-fatal assertion at "
419                     "%s:%d : %s", function, pid, file, line, assert_condition);
420             crm_write_blackbox(SIGTRAP, NULL);
421             do {
422                 if (waitpid(pid, &status, 0) == pid) {
423                     return; // Child finished dumping core
424                 }
425             } while (errno == EINTR);
426             if (errno == ECHILD) {
427                 // crm_mon ignores SIGCHLD
428                 crm_trace("Cannot wait on forked child [%d] "
429                           "(SIGCHLD is probably ignored)", pid);
430             } else {
431                 crm_err("Cannot wait on forked child [%d]: %s",
432                         pid, pcmk_rc_str(errno));
433             }
434             break;
435     }
436 }
437 
438 /* coverity[+kill] */
439 void
crm_abort(const char * file,const char * function,int line,const char * assert_condition,gboolean do_core,gboolean do_fork)440 crm_abort(const char *file, const char *function, int line,
441           const char *assert_condition, gboolean do_core, gboolean do_fork)
442 {
443     if (!do_fork) {
444         abort_as(file, function, line, assert_condition);
445     } else if (do_core) {
446         fail_assert_as(file, function, line, assert_condition);
447     } else {
448         log_assertion_as(file, function, line, assert_condition);
449     }
450 }
451 
452 /*!
453  * \internal
454  * \brief Convert the current process to a daemon process
455  *
456  * Fork a child process, exit the parent, create a PID file with the current
457  * process ID, and close the standard input/output/error file descriptors.
458  * Exit instead if a daemon is already running and using the PID file.
459  *
460  * \param[in] name     Daemon executable name
461  * \param[in] pidfile  File name to use as PID file
462  */
463 void
pcmk__daemonize(const char * name,const char * pidfile)464 pcmk__daemonize(const char *name, const char *pidfile)
465 {
466     int rc;
467     pid_t pid;
468 
469     /* Check before we even try... */
470     rc = pcmk__pidfile_matches(pidfile, 1, name, &pid);
471     if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
472         crm_err("%s: already running [pid %lld in %s]",
473                 name, (long long) pid, pidfile);
474         printf("%s: already running [pid %lld in %s]\n",
475                name, (long long) pid, pidfile);
476         crm_exit(CRM_EX_ERROR);
477     }
478 
479     pid = fork();
480     if (pid < 0) {
481         fprintf(stderr, "%s: could not start daemon\n", name);
482         crm_perror(LOG_ERR, "fork");
483         crm_exit(CRM_EX_OSERR);
484 
485     } else if (pid > 0) {
486         crm_exit(CRM_EX_OK);
487     }
488 
489     rc = pcmk__lock_pidfile(pidfile, name);
490     if (rc != pcmk_rc_ok) {
491         crm_err("Could not lock '%s' for %s: %s " CRM_XS " rc=%d",
492                 pidfile, name, pcmk_rc_str(rc), rc);
493         printf("Could not lock '%s' for %s: %s (%d)\n",
494                pidfile, name, pcmk_rc_str(rc), rc);
495         crm_exit(CRM_EX_ERROR);
496     }
497 
498     umask(S_IWGRP | S_IWOTH | S_IROTH);
499 
500     close(STDIN_FILENO);
501     pcmk__open_devnull(O_RDONLY);   // stdin (fd 0)
502 
503     close(STDOUT_FILENO);
504     pcmk__open_devnull(O_WRONLY);   // stdout (fd 1)
505 
506     close(STDERR_FILENO);
507     pcmk__open_devnull(O_WRONLY);   // stderr (fd 2)
508 }
509 
510 char *
crm_meta_name(const char * field)511 crm_meta_name(const char *field)
512 {
513     int lpc = 0;
514     int max = 0;
515     char *crm_name = NULL;
516 
517     CRM_CHECK(field != NULL, return NULL);
518     crm_name = crm_strdup_printf(CRM_META "_%s", field);
519 
520     /* Massage the names so they can be used as shell variables */
521     max = strlen(crm_name);
522     for (; lpc < max; lpc++) {
523         switch (crm_name[lpc]) {
524             case '-':
525                 crm_name[lpc] = '_';
526                 break;
527         }
528     }
529     return crm_name;
530 }
531 
532 const char *
crm_meta_value(GHashTable * hash,const char * field)533 crm_meta_value(GHashTable * hash, const char *field)
534 {
535     char *key = NULL;
536     const char *value = NULL;
537 
538     key = crm_meta_name(field);
539     if (key) {
540         value = g_hash_table_lookup(hash, key);
541         free(key);
542     }
543 
544     return value;
545 }
546 
547 #ifdef HAVE_UUID_UUID_H
548 #  include <uuid/uuid.h>
549 #endif
550 
551 char *
crm_generate_uuid(void)552 crm_generate_uuid(void)
553 {
554     unsigned char uuid[16];
555     char *buffer = malloc(37);  /* Including NUL byte */
556 
557     uuid_generate(uuid);
558     uuid_unparse(uuid, buffer);
559     return buffer;
560 }
561 
562 #ifdef HAVE_GNUTLS_GNUTLS_H
563 void
crm_gnutls_global_init(void)564 crm_gnutls_global_init(void)
565 {
566     signal(SIGPIPE, SIG_IGN);
567     gnutls_global_init();
568 }
569 #endif
570 
571 /*!
572  * \brief Get the local hostname
573  *
574  * \return Newly allocated string with name, or NULL (and set errno) on error
575  */
576 char *
pcmk_hostname()577 pcmk_hostname()
578 {
579     struct utsname hostinfo;
580 
581     return (uname(&hostinfo) < 0)? NULL : strdup(hostinfo.nodename);
582 }
583 
584 bool
pcmk_str_is_infinity(const char * s)585 pcmk_str_is_infinity(const char *s) {
586     return pcmk__str_any_of(s, CRM_INFINITY_S, CRM_PLUS_INFINITY_S, NULL);
587 }
588 
589 bool
pcmk_str_is_minus_infinity(const char * s)590 pcmk_str_is_minus_infinity(const char *s) {
591     return pcmk__str_eq(s, CRM_MINUS_INFINITY_S, pcmk__str_none);
592 }
593 
594 /*!
595  * \internal
596  * \brief Sleep for given milliseconds
597  *
598  * \param[in] ms  Time to sleep
599  *
600  * \note The full time might not be slept if a signal is received.
601  */
602 void
pcmk__sleep_ms(unsigned int ms)603 pcmk__sleep_ms(unsigned int ms)
604 {
605     // @TODO Impose a sane maximum sleep to avoid hanging a process for long
606     //CRM_CHECK(ms <= MAX_SLEEP, ms = MAX_SLEEP);
607 
608     // Use sleep() for any whole seconds
609     if (ms >= 1000) {
610         sleep(ms / 1000);
611         ms -= ms / 1000;
612     }
613 
614     if (ms == 0) {
615         return;
616     }
617 
618 #if defined(HAVE_NANOSLEEP)
619     // nanosleep() is POSIX-2008, so prefer that
620     {
621         struct timespec req = { .tv_sec = 0, .tv_nsec = (long) (ms * 1000000) };
622 
623         nanosleep(&req, NULL);
624     }
625 #elif defined(HAVE_USLEEP)
626     // usleep() is widely available, though considered obsolete
627     usleep((useconds_t) ms);
628 #else
629     // Otherwise use a trick with select() timeout
630     {
631         struct timeval tv = { .tv_sec = 0, .tv_usec = (suseconds_t) ms };
632 
633         select(0, NULL, NULL, NULL, &tv);
634     }
635 #endif
636 }
637