Skip to content

Commit 95a94f7

Browse files
authored
Merge pull request #2548 from jimklimov/issue-2463
Refactor and fix check for process name by PID; update docs for ASCII in config files
2 parents 73cfa9b + 5f9bde3 commit 95a94f7

18 files changed

Lines changed: 166 additions & 28 deletions

clients/upsclient.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags
10251025
ups->fd = -1;
10261026

10271027
if (!host) {
1028-
upslogx(LOG_WARNING, "%s: Host not found: '%s'", __func__, NUT_STRARG(host));
1028+
upslogx(LOG_WARNING, "%s: Host not specified", __func__);
10291029
ups->upserror = UPSCLI_ERR_NOSUCHHOST;
10301030
return -1;
10311031
}

common/common.c

Lines changed: 89 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -919,10 +919,26 @@ size_t parseprogbasename(char *buf, size_t buflen, const char *progname, size_t
919919
return progbasenamelen;
920920
}
921921

922-
int checkprocname(pid_t pid, const char *progname)
922+
int checkprocname_ignored(const char *caller)
923923
{
924-
/* If we can determine the binary path name of the specified "pid",
924+
char *s = NULL;
925+
926+
if ((s = getenv("NUT_IGNORE_CHECKPROCNAME"))) {
927+
/* FIXME: Make server/conf.c::parse_boolean() reusable */
928+
if ( (!strcasecmp(s, "true")) || (!strcasecmp(s, "on")) || (!strcasecmp(s, "yes")) || (!strcasecmp(s, "1"))) {
929+
upsdebugx(1, "%s for %s: skipping because caller set NUT_IGNORE_CHECKPROCNAME", __func__, NUT_STRARG(caller));
930+
return 1;
931+
}
932+
}
933+
934+
return 0;
935+
}
936+
937+
int compareprocname(pid_t pid, const char *procname, const char *progname)
938+
{
939+
/* Given the binary path name of (presumably) a running process,
925940
* check if it matches the assumed name of the current program.
941+
* The "pid" value is used in log reporting.
926942
* Returns:
927943
* -3 Skipped because NUT_IGNORE_CHECKPROCNAME is set
928944
* -2 Could not parse a program name (ok to proceed,
@@ -932,9 +948,9 @@ int checkprocname(pid_t pid, const char *progname)
932948
* 0 Process name identified, does not seem to match
933949
* 1+ Process name identified, and seems to match with
934950
* varying precision
935-
* Generally speaking, if (checkprocname(...)) then ok to proceed
951+
* Generally speaking, if (compareprocname(...)) then ok to proceed
936952
*/
937-
char *procname = NULL, *s;
953+
938954
int ret = -127;
939955
size_t procbasenamelen = 0, progbasenamelen = 0;
940956
/* Track where the last dot is in the basename; 0 means none */
@@ -945,16 +961,11 @@ int checkprocname(pid_t pid, const char *progname)
945961
char procbasename[PATH_MAX], progbasename[PATH_MAX];
946962
#endif
947963

948-
if ((s = getenv("NUT_IGNORE_CHECKPROCNAME"))) {
949-
/* FIXME: Make server/conf.c::parse_boolean() reusable */
950-
if ( (!strcasecmp(s, "true")) || (!strcasecmp(s, "on")) || (!strcasecmp(s, "yes")) || (!strcasecmp(s, "1"))) {
951-
upsdebugx(1, "%s: skipping because caller set NUT_IGNORE_CHECKPROCNAME", __func__);
952-
ret = -3;
953-
goto finish;
954-
}
964+
if (checkprocname_ignored(__func__)) {
965+
ret = -3;
966+
goto finish;
955967
}
956968

957-
procname = getprocname(pid);
958969
if (!procname || !progname) {
959970
ret = -1;
960971
goto finish;
@@ -975,7 +986,7 @@ int checkprocname(pid_t pid, const char *progname)
975986
}
976987

977988
/* First quickly try for an exact hit of base names */
978-
if (progbasenamelen == procbasenamelen && progbasenamedot == procbasenamedot && !strcmp(procname, progname)) {
989+
if (progbasenamelen == procbasenamelen && progbasenamedot == procbasenamedot && !strcmp(procbasename, progbasename)) {
979990
ret = 2;
980991
goto finish;
981992
}
@@ -1091,6 +1102,42 @@ int checkprocname(pid_t pid, const char *progname)
10911102
return ret;
10921103
}
10931104

1105+
int checkprocname(pid_t pid, const char *progname)
1106+
{
1107+
/* If we can determine the binary path name of the specified "pid",
1108+
* check if it matches the assumed name of the current program.
1109+
* Returns: same as compareprocname()
1110+
* Generally speaking, if (checkprocname(...)) then ok to proceed
1111+
*/
1112+
char *procname = NULL;
1113+
int ret = 0;
1114+
1115+
/* Quick skip before drilling into getprocname() */
1116+
if (checkprocname_ignored(__func__)) {
1117+
ret = -3;
1118+
goto finish;
1119+
}
1120+
1121+
if (!progname) {
1122+
ret = -1;
1123+
goto finish;
1124+
}
1125+
1126+
procname = getprocname(pid);
1127+
if (!procname) {
1128+
ret = -1;
1129+
goto finish;
1130+
}
1131+
1132+
ret = compareprocname(pid, procname, progname);
1133+
1134+
finish:
1135+
if (procname)
1136+
free(procname);
1137+
1138+
return ret;
1139+
}
1140+
10941141
#ifdef WIN32
10951142
/* In WIN32 all non binaries files (namely configuration and PID files)
10961143
are retrieved relative to the path of the binary itself.
@@ -1154,7 +1201,7 @@ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_pr
11541201
{
11551202
#ifndef WIN32
11561203
int ret, cpn1 = -10, cpn2 = -10;
1157-
char *current_progname = NULL;
1204+
char *current_progname = NULL, *procname = NULL;
11581205

11591206
/* TOTHINK: What about containers where a NUT daemon *is* the only process
11601207
* and is the PID=1 of the container (recycle if dead)? */
@@ -1167,9 +1214,12 @@ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_pr
11671214
}
11681215

11691216
ret = 0;
1170-
if (progname) {
1217+
if (!checkprocname_ignored(__func__))
1218+
procname = getprocname(pid);
1219+
1220+
if (procname && progname) {
11711221
/* Check against some expected (often built-in) name */
1172-
if (!(cpn1 = checkprocname(pid, progname))) {
1222+
if (!(cpn1 = compareprocname(pid, procname, progname))) {
11731223
/* Did not match expected (often built-in) name */
11741224
ret = -1;
11751225
} else {
@@ -1182,13 +1232,13 @@ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_pr
11821232
}
11831233
/* if (cpn1 == -3) => NUT_IGNORE_CHECKPROCNAME=true */
11841234
/* if (cpn1 == -1) => could not determine name of PID... retry just in case? */
1185-
if (ret <= 0 && check_current_progname && cpn1 != -3) {
1235+
if (procname && ret <= 0 && check_current_progname && cpn1 != -3) {
11861236
/* NOTE: This could be optimized a bit by pre-finding the procname
11871237
* of "pid" and re-using it, but this is not a hot enough code path
11881238
* to bother much.
11891239
*/
11901240
current_progname = getprocname(getpid());
1191-
if (current_progname && (cpn2 = checkprocname(pid, current_progname))) {
1241+
if (current_progname && (cpn2 = compareprocname(pid, procname, current_progname))) {
11921242
if (cpn2 > 0) {
11931243
/* Matched current process as asked, ok to proceed */
11941244
ret = 2;
@@ -1206,17 +1256,23 @@ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_pr
12061256
}
12071257

12081258
/* if ret == 0, ok to proceed - not asked for any sanity checks;
1209-
* if ret > 0 we had some definitive match above
1259+
* if ret > 0, ok to proceed - we had some definitive match above;
1260+
* if ret < 0, NOT OK to proceed - we had some definitive fault above
12101261
*/
12111262
if (ret < 0) {
12121263
upsdebugx(1,
12131264
"%s: ran at least one check, and all such checks "
12141265
"found a process name for PID %" PRIuMAX " and "
1215-
"failed to match: expected progname='%s' (res=%d), "
1216-
"current progname='%s' (res=%d)",
1266+
"failed to match: "
1267+
"found procname='%s', "
1268+
"expected progname='%s' (res=%d%s), "
1269+
"current progname='%s' (res=%d%s)",
12171270
__func__, (uintmax_t)pid,
1271+
NUT_STRARG(procname),
12181272
NUT_STRARG(progname), cpn1,
1219-
NUT_STRARG(current_progname), cpn2);
1273+
(cpn1 == -10 ? ": did not check" : ""),
1274+
NUT_STRARG(current_progname), cpn2,
1275+
(cpn2 == -10 ? ": did not check" : ""));
12201276

12211277
if (nut_debug_level > 0 || nut_sendsignal_debug_level > 1) {
12221278
switch (ret) {
@@ -1267,14 +1323,25 @@ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_pr
12671323
current_progname = NULL;
12681324
}
12691325

1326+
if (procname) {
1327+
free(procname);
1328+
procname = NULL;
1329+
}
1330+
12701331
/* Logged or not, sanity-check was requested and failed */
12711332
return -1;
12721333
}
1334+
12731335
if (current_progname) {
12741336
free(current_progname);
12751337
current_progname = NULL;
12761338
}
12771339

1340+
if (procname) {
1341+
free(procname);
1342+
procname = NULL;
1343+
}
1344+
12781345
/* see if this is going to work first - does the process exist,
12791346
* and do we have permissions to signal it? */
12801347
ret = kill(pid, 0);

conf/hosts.conf.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# This file is used to control the CGI programs. If you have not
44
# installed them, you may safely ignore or delete this file.
55
#
6+
# NOTE: Contents of this file should be pure ASCII (character codes
7+
# not in range would be ignored with a warning message).
8+
#
69
# -----------------------------------------------------------------------
710
#
811
# upsstats will use the list of MONITOR entries when displaying the

conf/nut.conf.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
# You MUST NOT use spaces around the equal sign!
1515
# Practical support for this file and its settings currently varies between
1616
# various OS packages and NUT sample scripts, but should converge over time.
17+
# Contents of this file should be pure ASCII (character codes not in range
18+
# would be ignored with a warning message).
1719
#
1820
# See also: `man nut.conf` (usually in Manual pages Section 5,
1921
# for Configuration files)

conf/ups.conf.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#
1010
# ---
1111
#
12+
# NOTE: Contents of this file should be pure ASCII (character codes
13+
# not in range would be ignored with a warning message).
14+
#
1215
# This is where you configure all the UPSes that this system will be
1316
# monitoring directly. These are usually attached to serial ports, but
1417
# USB devices and SNMP devices are also supported.

conf/upsd.conf.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
# Each entry below provides usage and default value.
88
#
99
# For more information, refer to upsd.conf manual page.
10+
#
11+
# NOTE: Contents of this file should be pure ASCII (character codes
12+
# not in range would be ignored with a warning message).
1013

1114
# =======================================================================
1215
# MAXAGE <seconds>

conf/upsd.users.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
# Users are defined here, are given passwords, and their privileges are
55
# controlled here too. Since this file will contain passwords, keep it
66
# secure, with only enough permissions for upsd to read it.
7+
#
8+
# NOTE: Contents of this file should be pure ASCII (character codes
9+
# not in range would be ignored with a warning message).
710

811
# --------------------------------------------------------------------------
912

conf/upsmon.conf.sample.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#
33
# This file contains passwords, so keep it secure.
44
#
5+
# NOTE: Contents of this file should be pure ASCII (character codes
6+
# not in range would be ignored with a warning message).
7+
#
58
# A minimal configuration should include at least one MONITOR instruction,
69
# MINSUPPLIES (may be 0 if this system is only monitoring other NUT servers),
710
# and a POWERDOWNFLAG if this machine is a "primary" system connected to

conf/upssched.conf.sample.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Network UPS Tools - upssched.conf sample file
22
#
3+
# NOTE: Contents of this file should be pure ASCII (character codes
4+
# not in range would be ignored with a warning message).
5+
#
36
# ============================================================================
47
#
58
# CMDSCRIPT <scriptname>

conf/upsset.conf.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
# the upsset.cgi program from running until you have assured it that you
66
# have secured your web server's CGI directory.
77
#
8+
# NOTE: Contents of this file should be pure ASCII (character codes
9+
# not in range would be ignored with a warning message).
10+
#
811
# By default, your web server will probably let anyone access upsset.cgi
912
# once it is installed. This means that anyone could attempt to crack
1013
# upsd logins since they would appear to be coming from your web server,

0 commit comments

Comments
 (0)