@@ -311,6 +311,9 @@ static void wolfSSHDLoggingCb(enum wolfSSH_LogLevel lvl, const char *const str)
311311 * level messages. Warnings carry the security relevant notices, e.g. that
312312 * a certificate was bound to an account by subject CN alone, so they must
313313 * not depend on -d. */
314+ if (logFile == NULL ) {
315+ return ;
316+ }
314317 if (lvl == WS_LOG_ERROR || lvl == WS_LOG_WARN || debugMode ) {
315318#ifdef _WIN32
316319 AcquireSRWLockExclusive (& logRepeatLock );
@@ -640,7 +643,7 @@ static int LoadUserCACertsFromStore(const WOLFSSHD_CONFIG* conf,
640643 if (providerStr != NULL &&
641644 WSTRCMP (providerStr , "CERT_STORE_PROV_SYSTEM" ) != 0 ) {
642645 wolfSSH_Log (WS_LOG_ERROR ,
643- "[SSHD] wolfSSH_WinUserStores='%s ' is not supported; only "
646+ "[SSHD] wolfSSH_WinUserStores='%.48s ' is not supported; only "
644647 "CERT_STORE_PROV_SYSTEM is supported" , providerStr );
645648 return WS_BAD_ARGUMENT ;
646649 }
@@ -704,7 +707,7 @@ static int LoadUserCACertsFromStore(const WOLFSSHD_CONFIG* conf,
704707 wStoreName );
705708 if (hStore == NULL ) {
706709 wolfSSH_Log (WS_LOG_ERROR ,
707- "[SSHD] Unable to open user CA cert store '%s ', error %lu" ,
710+ "[SSHD] Unable to open user CA cert store '%.48s ', error %lu" ,
708711 storeNameStr , (unsigned long )GetLastError ());
709712 WFREE (wStoreName , heap , DYNTYPE_SSHD );
710713 return WS_FATAL_ERROR ;
@@ -797,6 +800,32 @@ static int LoadUserCACertsFromStore(const WOLFSSHD_CONFIG* conf,
797800}
798801#endif /* WOLFSSH_CERTS && WOLFSSH_WINDOWS_CERT_STORE */
799802
803+ #if defined(WOLFSSH_CERTS ) && (defined(_WIN32 ) || defined(WOLFSSL_FPKI ))
804+ /* Returns non-zero when any config node configures a certificate trust
805+ * anchor. TrustedUserCAKeys may live inside a Match block, so the whole list
806+ * must be walked; the two store flags are global-only and live on the head
807+ * node. */
808+ static int AnyNodeHasCertTrustAnchor (const WOLFSSHD_CONFIG * conf )
809+ {
810+ const WOLFSSHD_CONFIG * cur ;
811+ int found = 0 ;
812+
813+ if (wolfSSHD_ConfigGetUserCAStore (conf ) ||
814+ wolfSSHD_ConfigGetSystemCA (conf )) {
815+ found = 1 ;
816+ }
817+ cur = conf ;
818+ while (!found && cur != NULL ) {
819+ if (wolfSSHD_ConfigGetUserCAKeysFile (cur ) != NULL ) {
820+ found = 1 ;
821+ }
822+ cur = wolfSSHD_ConfigGetNext (cur );
823+ }
824+
825+ return found ;
826+ }
827+ #endif /* WOLFSSH_CERTS && (_WIN32 || WOLFSSL_FPKI) */
828+
800829/* Initializes and sets up the WOLFSSH_CTX struct based on the configure options
801830 * return WS_SUCCESS on success
802831 */
@@ -1239,10 +1268,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
12391268 * fixed by the wolfSSL build, not by configuration, so this cannot be
12401269 * derived from the config file. */
12411270 #if defined(WOLFSSH_CERTS ) && !defined(WOLFSSL_FPKI ) && defined(_WIN32 )
1242- if (ret == WS_SUCCESS &&
1243- (wolfSSHD_ConfigGetUserCAKeysFile (conf ) != NULL ||
1244- wolfSSHD_ConfigGetUserCAStore (conf ) ||
1245- wolfSSHD_ConfigGetSystemCA (conf ))) {
1271+ if (ret == WS_SUCCESS && AnyNodeHasCertTrustAnchor (conf )) {
12461272 wolfSSH_Log (WS_LOG_WARN ,
12471273 "[SSHD] WARNING: client certificates are bound to an account by "
12481274 "subject CN only." );
@@ -1344,10 +1370,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
13441370 * callback writes WARN unconditionally, so a per-attempt WARN would let
13451371 * a peer grow the log). Only emitted when a certificate trust anchor is
13461372 * actually configured; with no CA there is no UPN check to relax. */
1347- if (ret == WS_SUCCESS &&
1348- (wolfSSHD_ConfigGetUserCAKeysFile (conf ) != NULL ||
1349- wolfSSHD_ConfigGetUserCAStore (conf ) ||
1350- wolfSSHD_ConfigGetSystemCA (conf ))) {
1373+ if (ret == WS_SUCCESS && AnyNodeHasCertTrustAnchor (conf )) {
13511374 const WOLFSSHD_CONFIG * cur ;
13521375 const char * domains ;
13531376
@@ -1376,10 +1399,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
13761399 * no CN check to skip. With FPKI the UPN identity check always runs, so
13771400 * there is nothing to note. */
13781401 #if defined(WOLFSSH_CERTS ) && !defined(WOLFSSL_FPKI ) && defined(_WIN32 )
1379- if (ret == WS_SUCCESS &&
1380- (wolfSSHD_ConfigGetUserCAKeysFile (conf ) != NULL ||
1381- wolfSSHD_ConfigGetUserCAStore (conf ) ||
1382- wolfSSHD_ConfigGetSystemCA (conf ))) {
1402+ if (ret == WS_SUCCESS && AnyNodeHasCertTrustAnchor (conf )) {
13831403 const WOLFSSHD_CONFIG * cur ;
13841404
13851405 cur = conf ;
@@ -3229,6 +3249,9 @@ static void* HandleConnection(void* arg)
32293249{
32303250 int ret = WS_SUCCESS ;
32313251 int error ;
3252+ #ifdef _WIN32
3253+ byte threaded = 0 ;
3254+ #endif
32323255
32333256 WOLFSSHD_CONNECTION * conn = NULL ;
32343257 WOLFSSH * ssh = NULL ;
@@ -3572,8 +3595,24 @@ static void* HandleConnection(void* arg)
35723595 WCLOSESOCKET (conn -> fd );
35733596 }
35743597 wolfSSH_Log (WS_LOG_INFO , "[SSHD] Return from closing connection = %d" , ret );
3598+ #ifdef _WIN32
3599+ if (conn != NULL ) {
3600+ threaded = conn -> isThreaded ;
3601+ }
3602+ #endif
35753603 WFREE (conn , NULL , DYNTYPE_SSHD );
3604+
3605+ /* The repeat state is per connection only when each connection is its own
3606+ * process (POSIX fork) or the lone in-process connection. Windows daemon
3607+ * threads share it, so flushing here would clear a streak another live
3608+ * connection thread still owns; the shutdown flush covers that path. */
3609+ #ifdef _WIN32
3610+ if (!threaded ) {
3611+ wolfSSHDLoggingFlush ();
3612+ }
3613+ #else
35763614 wolfSSHDLoggingFlush ();
3615+ #endif
35773616
35783617#ifdef _WIN32
35793618 return 0 ;
@@ -3865,6 +3904,9 @@ static int StartSSHD(int argc, char** argv)
38653904 ret = WFOPEN (NULL , & logFile , myoptarg , "ab" );
38663905 if (ret != 0 || logFile == WBADFILE ) {
38673906 fprintf (stderr , "Unable to open log file %s\n" , myoptarg );
3907+ /* option parsing continues and may log before the error is
3908+ * acted on, so never leave the stream NULL */
3909+ logFile = stderr ;
38683910 ret = WS_FATAL_ERROR ;
38693911 }
38703912 break ;
0 commit comments