Skip to content

Commit e837af2

Browse files
authored
Merge pull request #3527 from jimklimov/issue-3525
`upssched` and other NUT daemons: fix Windows state pipe permissions
2 parents dffba91 + 3b3145c commit e837af2

5 files changed

Lines changed: 87 additions & 51 deletions

File tree

NEWS.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ https://github.com/networkupstools/nut/milestone/13
133133
`connect()` to ensure a timeout if something does not respond. [PR #3456]
134134
* Windows driver state named pipes now use explicit security attributes
135135
instead of relying on default settings from the launch context. [PR #3479]
136+
* Likewise for named pipes in other NUT daemons and `upssched`. [PR #3527]
136137
* Drivers with libusb-1.0 code path, and `nutdrv_qx` in particular: revise
137138
to fix per-close `libusb_exit()` deadlock, and escalate a persistent
138139
`LIBUSB_ERROR_OVERFLOW` state to USB reset handling. [PR #3448]
@@ -207,6 +208,10 @@ https://github.com/networkupstools/nut/milestone/13
207208
and wake-up, or NTP/RTC clock changes during boot, or severe delays
208209
on a stressed system (to name a few practical cases). [issue #3405]
209210

211+
- `upssched` client/tool updates:
212+
* Fixed handling of `NOTIFYMSG` from command line if other arguments are
213+
present (e.g. debugging with `-DDDDDD`). [issues #3105, #3525, PR #3527]
214+
210215
- `NUT-Monitor` Python GUI client:
211216
* Fixed Qt tray tooltips to render in plain text, not rich text which
212217
ended up as literal HTML on KDE Plasma 6; now that rich text formatting

clients/upssched.c

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -763,19 +763,24 @@ static TYPE_FD open_sock(void)
763763
set_close_on_exec(fd);
764764

765765
#else /* WIN32 */
766+
SECURITY_ATTRIBUTES pipe_sa;
767+
SECURITY_DESCRIPTOR pipe_sd;
768+
769+
init_pipe_security(&pipe_sa, &pipe_sd);
766770

767771
fd = CreateNamedPipe(
768-
pipefn, /* pipe name */
769-
PIPE_ACCESS_DUPLEX | /* read/write access */
770-
FILE_FLAG_OVERLAPPED, /* async IO */
771-
PIPE_TYPE_BYTE |
772-
PIPE_READMODE_BYTE |
773-
PIPE_WAIT,
774-
PIPE_UNLIMITED_INSTANCES, /* max. instances */
775-
BUF_LEN, /* output buffer size */
776-
BUF_LEN, /* input buffer size */
777-
0, /* client time-out */
778-
NULL); /* FIXME: default security attributes */
772+
pipefn, /* pipe name */
773+
PIPE_ACCESS_DUPLEX /* read/write access */
774+
| FILE_FLAG_OVERLAPPED, /* async IO */
775+
PIPE_TYPE_BYTE
776+
| PIPE_READMODE_BYTE
777+
| PIPE_REJECT_REMOTE_CLIENTS /* local host only */
778+
| PIPE_WAIT,
779+
PIPE_UNLIMITED_INSTANCES, /* max. instances */
780+
BUF_LEN, /* output buffer size */
781+
BUF_LEN, /* input buffer size */
782+
0, /* client time-out */
783+
&pipe_sa); /* default security attributes */
779784

780785
if (INVALID_FD(fd)) {
781786
fatal_with_errno(EXIT_FAILURE,
@@ -998,25 +1003,30 @@ static TYPE_FD conn_add(TYPE_FD sockfd)
9981003
#else /* WIN32 */
9991004

10001005
conn_t *conn, *tmp, *last;
1006+
SECURITY_ATTRIBUTES pipe_sa;
1007+
SECURITY_DESCRIPTOR pipe_sd;
10011008

10021009
/* We have detected a connection on the opened pipe. So we start
10031010
* by saving its handle and creating a new pipe for future connection */
10041011
conn = xcalloc(1, sizeof(*conn));
10051012
conn->fd = sockfd;
10061013

1014+
init_pipe_security(&pipe_sa, &pipe_sd);
1015+
10071016
/* sock is the handle of the connection pending pipe */
10081017
acc = CreateNamedPipe(
1009-
pipefn, /* pipe name */
1010-
PIPE_ACCESS_DUPLEX | /* read/write access */
1011-
FILE_FLAG_OVERLAPPED, /* async IO */
1012-
PIPE_TYPE_BYTE |
1013-
PIPE_READMODE_BYTE |
1014-
PIPE_WAIT,
1015-
PIPE_UNLIMITED_INSTANCES, /* max. instances */
1016-
BUF_LEN, /* output buffer size */
1017-
BUF_LEN, /* input buffer size */
1018-
0, /* client time-out */
1019-
NULL); /* FIXME: default security attribute */
1018+
pipefn, /* pipe name */
1019+
PIPE_ACCESS_DUPLEX /* read/write access */
1020+
| FILE_FLAG_OVERLAPPED, /* async IO */
1021+
PIPE_TYPE_BYTE
1022+
| PIPE_READMODE_BYTE
1023+
| PIPE_REJECT_REMOTE_CLIENTS /* local host only */
1024+
| PIPE_WAIT,
1025+
PIPE_UNLIMITED_INSTANCES, /* max. instances */
1026+
BUF_LEN, /* output buffer size */
1027+
BUF_LEN, /* input buffer size */
1028+
0, /* client time-out */
1029+
&pipe_sa); /* default security attribute */
10201030

10211031
if (INVALID_FD(acc)) {
10221032
fatal_with_errno(EXIT_FAILURE,
@@ -2352,20 +2362,19 @@ static void help(const char *arg_progname)
23522362

23532363
nut_report_config_flags();
23542364

2355-
printf("\n%s", suggest_doc_links(arg_progname, "upsmon.conf"));
2365+
printf("\n%s", suggest_doc_links(arg_progname, "upssched.conf"));
23562366

23572367
exit(EXIT_SUCCESS);
23582368
}
23592369

23602370
int main(int argc, char **argv)
23612371
{
2362-
int opt_ret, argn = 0;
2372+
int opt_ret;
23632373

23642374
/* Here this is a global variable, used also in start_daemon() */
23652375
prog = getprogname_argv0_default(argc > 0 ? argv[0] : NULL, "upssched");
23662376

23672377
while ((opt_ret = getopt(argc, argv, optstring)) != -1) {
2368-
argn++;
23692378
switch (opt_ret) {
23702379
case 'D':
23712380
nut_debug_level_args++;
@@ -2411,9 +2420,9 @@ int main(int argc, char **argv)
24112420

24122421
ups_name = getenv("UPSNAME");
24132422
notify_type = getenv("NOTIFYTYPE");
2414-
upsdebugx(2, "Remaining argn=%d of argc=%d", argn, argc);
2415-
if (argc > argn + 1 && *argv[argn + 1])
2416-
notify_msg = argv[argn + 1];
2423+
upsdebugx(2, "Handled optind=%d CLI tokens of argc=%d", optind - 1, argc);
2424+
if (argc > optind && *argv[optind])
2425+
notify_msg = argv[optind];
24172426

24182427
if ((!list_timers) && ((!ups_name) || (!notify_type))) {
24192428
printf("Error: environment variables UPSNAME and NOTIFYTYPE must be set.\n");

common/wincompat.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ void syslog(int priority, const char *fmt, ...)
454454
/* At least while this is not configurable, can be static to speed up;
455455
* see https://github.com/networkupstools/nut/issues/3375
456456
*/
457-
static char pipe_full_name[] = "\\\\.\\pipe\\"EVENTLOG_PIPE_NAME;
457+
static char pipe_full_name[] = "\\\\.\\pipe\\"EVENTLOG_PIPE_NAME, reported_no_pipe = 0, reentered = 0;
458458
char buf1[LARGEBUF + sizeof(DWORD)];
459459
char buf2[LARGEBUF];
460460
va_list ap;
@@ -465,6 +465,13 @@ void syslog(int priority, const char *fmt, ...)
465465
return;
466466
}
467467

468+
/* Could an upsdebugx() below cause re-syslog?.. */
469+
if (reentered) {
470+
return;
471+
}
472+
473+
reentered = 1;
474+
468475
/* Format message */
469476
va_start(ap, fmt);
470477
vsnprintf(buf1, sizeof(buf1), fmt, ap);
@@ -490,20 +497,29 @@ void syslog(int priority, const char *fmt, ...)
490497
NULL); /* no template file */
491498

492499
if (pipe == INVALID_HANDLE_VALUE) {
493-
upsdebug_with_errno(1,
500+
upsdebug_with_errno(reported_no_pipe ? 7 : 1,
494501
"%s: SKIP: can't open existing event log NAMED_PIPE: '%s'",
495502
__func__, pipe_full_name);
496503

504+
reported_no_pipe = 1;
505+
reentered = 0;
497506
return;
498507
}
499508

509+
if (reported_no_pipe)
510+
upsdebugx(1, "%s: opened existing event log NAMED_PIPE which we failed to use earlier: '%s'",
511+
__func__, pipe_full_name);
512+
reported_no_pipe = 0;
513+
500514
WriteFile(pipe, buf1, strlen(buf2) + sizeof(DWORD), &bytesWritten, NULL);
501515

502516
/* testing result is useless. If we have an error and try to report it,
503517
* this will probably lead to a call to this function and an infinite
504518
* loop */
505519
upsdebugx(6, "%s: closing event log NAMED_PIPE", __func__);
506520
CloseHandle(pipe);
521+
522+
reentered = 0;
507523
}
508524

509525
/* Signal emulation via NamedPipe */
@@ -515,10 +531,27 @@ static const char *named_pipe_name=NULL;
515531
OVERLAPPED pipe_connection_overlapped;
516532
pipe_conn_t *pipe_connhead = NULL;
517533

534+
void init_pipe_security(SECURITY_ATTRIBUTES *sa, SECURITY_DESCRIPTOR *sd)
535+
{
536+
if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
537+
fatal_with_errno(EXIT_FAILURE, "InitializeSecurityDescriptor failed");
538+
}
539+
540+
if (!SetSecurityDescriptorDacl(sd, TRUE, NULL, FALSE)) {
541+
fatal_with_errno(EXIT_FAILURE, "SetSecurityDescriptorDacl failed");
542+
}
543+
544+
sa->nLength = sizeof(*sa);
545+
sa->lpSecurityDescriptor = sd;
546+
sa->bInheritHandle = FALSE;
547+
}
548+
518549
void pipe_create(const char * pipe_name)
519550
{
520551
BOOL ret;
521552
char pipe_full_name[NUT_PATH_MAX + 1];
553+
SECURITY_ATTRIBUTES pipe_sa;
554+
SECURITY_DESCRIPTOR pipe_sd;
522555

523556
/* save pipe name for further use in pipe_connect */
524557
if (pipe_name == NULL) {
@@ -537,19 +570,22 @@ void pipe_create(const char * pipe_name)
537570
CloseHandle(pipe_connection_overlapped.hEvent);
538571
}
539572
memset(&pipe_connection_overlapped, 0, sizeof(pipe_connection_overlapped));
573+
init_pipe_security(&pipe_sa, &pipe_sd);
574+
540575
upsdebugx(2, "%s: creating NAMED_PIPE (listener): '%s'", __func__, pipe_full_name);
541576
pipe_connection_handle = CreateNamedPipe(
542577
pipe_full_name,
543578
PIPE_ACCESS_INBOUND /* to server only */
544579
| FILE_FLAG_OVERLAPPED, /* async IO */
545580
PIPE_TYPE_MESSAGE
546581
| PIPE_READMODE_MESSAGE
582+
| PIPE_REJECT_REMOTE_CLIENTS /* local host only */
547583
| PIPE_WAIT,
548584
PIPE_UNLIMITED_INSTANCES, /* max. instances */
549585
LARGEBUF, /* output buffer size */
550586
LARGEBUF, /* input buffer size */
551587
0, /* client time-out */
552-
NULL); /* FIXME: default security attribute */
588+
&pipe_sa); /* default security attribute */
553589

554590
if (pipe_connection_handle == INVALID_HANDLE_VALUE) {
555591
upslogx(LOG_ERR, "Error creating named pipe");

drivers/dstate.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,6 @@
6666
double previous_battery_charge_value = -1.0;
6767
st_tree_timespec_t previous_battery_charge_timestamp;
6868

69-
#ifdef WIN32
70-
static void init_pipe_security(SECURITY_ATTRIBUTES *sa, SECURITY_DESCRIPTOR *sd)
71-
{
72-
if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
73-
fatal_with_errno(EXIT_FAILURE, "InitializeSecurityDescriptor failed");
74-
}
75-
76-
if (!SetSecurityDescriptorDacl(sd, TRUE, NULL, FALSE)) {
77-
fatal_with_errno(EXIT_FAILURE, "SetSecurityDescriptorDacl failed");
78-
}
79-
80-
sa->nLength = sizeof(*sa);
81-
sa->lpSecurityDescriptor = sd;
82-
sa->bInheritHandle = FALSE;
83-
}
84-
#endif /* WIN32 */
85-
8669
#ifndef WIN32
8770
/* this may be a frequent stumbling point for new users, so be verbose here */
8871
static void sock_fail(const char *fn)
@@ -223,6 +206,7 @@ static TYPE_FD sock_open(const char *fn)
223206
| FILE_FLAG_OVERLAPPED, /* async IO */
224207
PIPE_TYPE_BYTE
225208
| PIPE_READMODE_BYTE
209+
| PIPE_REJECT_REMOTE_CLIENTS /* local host only */
226210
| PIPE_WAIT,
227211
PIPE_UNLIMITED_INSTANCES, /* max. instances */
228212
ST_SOCK_BUF_LEN, /* output buffer size */
@@ -681,6 +665,7 @@ static void sock_connect(TYPE_FD sock)
681665
| FILE_FLAG_OVERLAPPED, /* async IO */
682666
PIPE_TYPE_BYTE
683667
| PIPE_READMODE_BYTE
668+
| PIPE_REJECT_REMOTE_CLIENTS /* local host only */
684669
| PIPE_WAIT,
685670
PIPE_UNLIMITED_INSTANCES, /* max. instances */
686671
ST_SOCK_BUF_LEN, /* output buffer size */

include/wincompat.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#ifndef NUT_WINCOMPAT_H
2-
#define NUT_WINCOMPAT_H 1
3-
41
/*
52
Copyright (C)
63
2001 Andrew Delpha (delpha@computer.org)
@@ -29,6 +26,9 @@
2926
with the NUT code.
3027
*/
3128

29+
#ifndef NUT_WINCOMPAT_H
30+
#define NUT_WINCOMPAT_H 1
31+
3232
#include "common.h"
3333
#include <limits.h>
3434
#include "nut_stdint.h"
@@ -157,6 +157,7 @@ typedef struct pipe_conn_s {
157157
extern pipe_conn_t *pipe_connhead;
158158
extern OVERLAPPED pipe_connection_overlapped;
159159
void pipe_create(const char * pipe_name);
160+
void init_pipe_security(SECURITY_ATTRIBUTES *sa, SECURITY_DESCRIPTOR *sd);
160161
void pipe_connect();
161162
void pipe_disconnect(pipe_conn_t *conn);
162163
int pipe_ready(pipe_conn_t *conn);

0 commit comments

Comments
 (0)