Skip to content

Commit d21c02c

Browse files
authored
Merge pull request #3497 from jimklimov/issue-3454
Try to avoid losing client outputs if exit clean-up crashes; try to avoid (Open)SSL-related crashes there
2 parents 261b18a + c9f8dc6 commit d21c02c

11 files changed

Lines changed: 74 additions & 2 deletions

File tree

NEWS.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ https://github.com/networkupstools/nut/milestone/13
162162
* The `libupsclient` (C) and `libnutclient` (C++) API were updated to
163163
report the ability to check `CERTIDENT` information. [#3331]
164164

165+
- Various clients:
166+
* Flush standard output and error buffers before handling clean exit
167+
rituals, to avoid losing the result of client's work in case that
168+
clean-up crashes (e.g. due to third-party code involved). [#3454]
169+
165170
- `upsimage.cgi` client updates:
166171
* Adjust scaling for small (single-digit) value ranges to avoid division
167172
by zero and not rendering anything. [issue #3469]

clients/upsc.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ static void list_clients(const char *devname)
381381

382382
static void clean_exit(void)
383383
{
384+
/* Flush *our* output before possibly failing in third-party code
385+
* (e.g. SSL libs), so client consumers have a chance to see it */
386+
fflush(stdout);
387+
fflush(stderr);
388+
384389
if (ups) {
385390
upscli_disconnect(ups);
386391
}

clients/upsclient.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ static struct timeval upscli_default_connect_timeout = {0, 0};
173173
static int upscli_default_connect_timeout_initialized = 0;
174174

175175
#ifdef WITH_OPENSSL
176-
static SSL_CTX *ssl_ctx;
176+
static SSL_CTX *ssl_ctx = NULL;
177177
#endif /* WITH_OPENSSL */
178178

179179
#ifdef WITH_NSS
@@ -832,6 +832,7 @@ int upscli_init2(int certverify, const char *certpath,
832832
ret = SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
833833
if (ret != 1) {
834834
upslogx(LOG_ERR, "Can not set minimum protocol to TLSv1");
835+
upscli_cleanup();
835836
return -1;
836837
}
837838
# endif
@@ -841,6 +842,7 @@ int upscli_init2(int certverify, const char *certpath,
841842
upslogx(LOG_ERR, "Can not verify certificate if any is specified: no CERTPATH was given");
842843
/* Failed: checking the server cert is mandatory, but no
843844
* collection of trusted CA/server cert files was given */
845+
upscli_cleanup();
844846
return -1;
845847
}
846848
} else {
@@ -863,6 +865,7 @@ int upscli_init2(int certverify, const char *certpath,
863865
if ((ret = SSL_CTX_load_verify_locations(ssl_ctx, certpath, NULL)) != 1) {
864866
ssl_debug();
865867
upslogx(LOG_ERR, "Failed to load CA certificate(s) from directory or file %s", certpath);
868+
upscli_cleanup();
866869
return -1;
867870
} else {
868871
upsdebugx(1, "%s: ...but succeeded to load CA certificate(s) from file %s", __func__, certpath);
@@ -918,6 +921,7 @@ int upscli_init2(int certverify, const char *certpath,
918921
# else /* Not SSL_* methods either */
919922

920923
upslogx(LOG_ERR, "Private key password support not implemented for OpenSSL < ~0.9.6..~1.1 yet");
924+
upscli_cleanup();
921925
return -1;
922926
# endif
923927
# endif /* ...SET_DEFAULT_PASSWD_CB */
@@ -930,16 +934,19 @@ int upscli_init2(int certverify, const char *certpath,
930934
if ((ssl_ret = SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile)) != 1) {
931935
upslogx(LOG_ERR, "Failed to load client certificate from %s", certfile);
932936
ssl_debug();
937+
upscli_cleanup();
933938
return -1;
934939
}
935940
if ((ssl_ret = SSL_CTX_use_PrivateKey_file(ssl_ctx, certfile, SSL_FILETYPE_PEM)) != 1) {
936941
upslogx(LOG_ERR, "Failed to load client private key from %s", certfile);
937942
ssl_debug();
943+
upscli_cleanup();
938944
return -1;
939945
}
940946
if ((ssl_ret = SSL_CTX_check_private_key(ssl_ctx)) != 1) {
941947
upslogx(LOG_ERR, "Failed to check client private key from %s", certfile);
942948
ssl_debug();
949+
upscli_cleanup();
943950
return -1;
944951
}
945952

@@ -976,6 +983,7 @@ int upscli_init2(int certverify, const char *certpath,
976983
OPENSSL_free(subject);
977984
}
978985
upslogx(LOG_ERR, "Unexpected certificate provided");
986+
upscli_cleanup();
979987
return -1;
980988
} else {
981989
upsdebugx(2, "Certificate subject verified against CERTIDENT subject name (%s)", sslcertname);
@@ -986,12 +994,14 @@ int upscli_init2(int certverify, const char *certpath,
986994
}
987995
# else /* Missing X509 methods wanted above */
988996
upslogx(LOG_ERR, "Can not verify CERTIDENT '%s': not supported in this OpenSSL build (too old)", sslcertname);
997+
upscli_cleanup();
989998
return -1;
990999
# endif /* Got ways to check CERTIDENT? */
9911000
} /* else: CERTIDENT did not pass a name, nothing to check */
9921001
} else {
9931002
if (sslcertname && *sslcertname) {
9941003
upslogx(LOG_ERR, "Can not verify CERTIDENT '%s': no CERTFILE was provided", sslcertname);
1004+
upscli_cleanup();
9951005
return -1;
9961006
}
9971007
}
@@ -1024,13 +1034,15 @@ int upscli_init2(int certverify, const char *certpath,
10241034
if (status != SECSuccess) {
10251035
upslogx(LOG_ERR, "Can not initialize SSL context");
10261036
nss_error("upscli_init / NSS_[NoDB]_Init");
1037+
upscli_cleanup();
10271038
return -1;
10281039
}
10291040

10301041
status = NSS_SetDomesticPolicy();
10311042
if (status != SECSuccess) {
10321043
upslogx(LOG_ERR, "Can not initialize SSL policy");
10331044
nss_error("upscli_init / NSS_SetDomesticPolicy");
1045+
upscli_cleanup();
10341046
return -1;
10351047
}
10361048

@@ -1040,25 +1052,29 @@ int upscli_init2(int certverify, const char *certpath,
10401052
if (status != SECSuccess) {
10411053
upslogx(LOG_ERR, "Can not enable SSLv3");
10421054
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_SSL3)");
1055+
upscli_cleanup();
10431056
return -1;
10441057
}
10451058
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
10461059
if (status != SECSuccess) {
10471060
upslogx(LOG_ERR, "Can not enable TLSv1");
10481061
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)");
1062+
upscli_cleanup();
10491063
return -1;
10501064
}
10511065
status = SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE);
10521066
if (status != SECSuccess) {
10531067
upslogx(LOG_ERR, "Can not disable SSLv2 hello compatibility");
10541068
nss_error("upscli_init / SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO)");
1069+
upscli_cleanup();
10551070
return -1;
10561071
}
10571072
verify_certificate = certverify;
10581073
#else
10591074
/* Note: historically we do not return with error here,
10601075
* and nowadays have the default timeout handling etc.,
10611076
* just fall through to below and treat as initialized.
1077+
* There's nothing to retry to change that state anyway.
10621078
*/
10631079
if (certverify || certpath || certname || certpasswd || certfile) {
10641080
upslogx(LOG_ERR, "upscli_init called but SSL wasn't compiled in");
@@ -1118,7 +1134,6 @@ int upscli_cleanup(void)
11181134
SSL_CTX_free(ssl_ctx);
11191135
ssl_ctx = NULL;
11201136
}
1121-
11221137
#endif /* WITH_OPENSSL */
11231138

11241139
#ifdef WITH_NSS

clients/upscmd.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ static void do_cmd(char **argv, const int argc)
299299

300300
static void clean_exit(void)
301301
{
302+
/* Flush *our* output before possibly failing in third-party code
303+
* (e.g. SSL libs), so client consumers have a chance to see it */
304+
fflush(stdout);
305+
fflush(stderr);
306+
302307
if (ups) {
303308
upscli_disconnect(ups);
304309
}

clients/upsimage.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,11 @@ static int get_var(const char *var, char *buf, size_t buflen)
656656

657657
static void clean_exit(void)
658658
{
659+
/* Flush *our* output before possibly failing in third-party code
660+
* (e.g. SSL libs), so client consumers have a chance to see it */
661+
fflush(stdout);
662+
fflush(stderr);
663+
659664
upscli_cleanup();
660665

661666
upsdebugx(1, "%s: finished, exiting", __func__);

clients/upslog.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,11 @@ int main(int argc, char **argv)
10651065
upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
10661066
upsnotify(NOTIFY_STATE_STOPPING, "Signal %d: exiting", exit_flag);
10671067

1068+
/* Flush *our* output before possibly failing in third-party code
1069+
* (e.g. SSL libs), so client consumers have a chance to see it */
1070+
fflush(stdout);
1071+
fflush(stderr);
1072+
10681073
for (
10691074
monhost_ups_current = monhost_ups_anchor;
10701075
monhost_ups_current != NULL;
@@ -1087,6 +1092,9 @@ int main(int argc, char **argv)
10871092
logformat = NULL;
10881093
}
10891094

1095+
fflush(stdout);
1096+
fflush(stderr);
1097+
10901098
upscli_cleanup();
10911099
exit(EXIT_SUCCESS);
10921100
}

clients/upsmon.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,11 @@ static void upsmon_cleanup(void)
27772777
int i;
27782778
utype_t *utmp, *unext;
27792779

2780+
/* Flush *our* output before possibly failing in third-party code
2781+
* (e.g. SSL libs), so client consumers have a chance to see it */
2782+
fflush(stdout);
2783+
fflush(stderr);
2784+
27802785
/* close all fds */
27812786
utmp = firstups;
27822787

@@ -2799,6 +2804,9 @@ static void upsmon_cleanup(void)
27992804
free(notifylist[i].msg);
28002805
}
28012806

2807+
fflush(stdout);
2808+
fflush(stderr);
2809+
28022810
upscli_cleanup();
28032811

28042812
#ifdef WIN32

clients/upsrw.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ static void help(const char *prog)
9191

9292
static void clean_exit(void)
9393
{
94+
/* Flush *our* output before possibly failing in third-party code
95+
* (e.g. SSL libs), so client consumers have a chance to see it */
96+
fflush(stdout);
97+
fflush(stderr);
98+
9499
if (ups) {
95100
upscli_disconnect(ups);
96101
}

clients/upssched.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,5 +2270,11 @@ int main(int argc, char **argv)
22702270
checkconf();
22712271

22722272
upsdebugx(1, "Exiting upssched (CLI process)");
2273+
2274+
/* Flush *our* output before possibly failing in third-party code
2275+
* (e.g. SSL libs), so client consumers have a chance to see it */
2276+
fflush(stdout);
2277+
fflush(stderr);
2278+
22732279
exit(EXIT_SUCCESS);
22742280
}

clients/upsset.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,11 @@ static void check_conf(void)
11171117

11181118
static void clean_exit(void)
11191119
{
1120+
/* Flush *our* output before possibly failing in third-party code
1121+
* (e.g. SSL libs), so client consumers have a chance to see it */
1122+
fflush(stdout);
1123+
fflush(stderr);
1124+
11201125
upscli_cleanup();
11211126

11221127
upsdebugx(1, "%s: finished, exiting", __func__);

0 commit comments

Comments
 (0)