@@ -501,6 +501,80 @@ static int test_GetUserConfMatchOverride(void)
501501 return ret ;
502502}
503503
504+ /* Only the User and Group Match selectors are implemented. A Match block keyed
505+ * on any other selector (Address, Host, LocalAddress, LocalPort, RDomain) would
506+ * otherwise be accepted but never apply, a fail-open misconfiguration. Verify
507+ * that User/Group are accepted while the unsupported selectors are rejected. */
508+ static int test_MatchUnsupportedSelector (void )
509+ {
510+ int ret = WS_SUCCESS ;
511+ int i ;
512+ WOLFSSHD_CONFIG * head ;
513+ WOLFSSHD_CONFIG * conf ;
514+
515+ static CONFIG_LINE_VECTOR vectors [] = {
516+ /* supported selectors */
517+ {"Match User" , "Match User testuser" , 0 },
518+ {"Match Group" , "Match Group testgroup" , 0 },
519+
520+ /* combined supported selectors must be accepted, in either order */
521+ {"Match User+Group" , "Match User alice Group dev" , 0 },
522+ {"Match Group+User" , "Match Group dev User alice" , 0 },
523+
524+ /* unsupported selectors must be rejected, not silently ignored */
525+ {"Match Address" , "Match Address 10.0.0.0/8" , 1 },
526+ {"Match Host" , "Match Host example.com" , 1 },
527+ {"Match LocalAddress" , "Match LocalAddress 192.168.1.1" , 1 },
528+ {"Match LocalPort" , "Match LocalPort 22" , 1 },
529+ {"Match RDomain" , "Match RDomain vrf-external" , 1 },
530+
531+ /* no-selector forms must also be rejected, not silently accepted */
532+ {"Match all" , "Match all" , 1 },
533+ {"Bare Match" , "Match" , 1 },
534+
535+ /* supported selector with no argument: passes the selector check but
536+ * fails while parsing the (missing) name, exercising the cleanup of
537+ * the already allocated config node */
538+ {"Match User no arg" , "Match User" , 1 },
539+
540+ /* mixed supported+unsupported selectors must be rejected; the
541+ * unsupported part must not be silently dropped */
542+ {"Mixed User+Address" , "Match User alice Address 10.0.0.0/8" , 1 },
543+ {"Mixed Group+Host" , "Match Group dev Host example.com" , 1 },
544+ };
545+ const int numVectors = (int )(sizeof (vectors ) / sizeof (* vectors ));
546+
547+ head = wolfSSHD_ConfigNew (NULL );
548+ if (head == NULL ) {
549+ ret = WS_MEMORY_E ;
550+ }
551+ conf = head ;
552+
553+ if (ret == WS_SUCCESS ) {
554+ for (i = 0 ; i < numVectors ; ++ i ) {
555+ int rc ;
556+
557+ Log (" Testing scenario: %s." , vectors [i ].desc );
558+
559+ rc = ParseConfigLine (& conf , vectors [i ].line ,
560+ (int )WSTRLEN (vectors [i ].line ), 0 );
561+
562+ if ((rc == WS_SUCCESS && !vectors [i ].shouldFail ) ||
563+ (rc != WS_SUCCESS && vectors [i ].shouldFail )) {
564+ Log (" PASSED.\n" );
565+ }
566+ else {
567+ Log (" FAILED.\n" );
568+ ret = WS_FATAL_ERROR ;
569+ break ;
570+ }
571+ }
572+ wolfSSHD_ConfigFree (head );
573+ }
574+
575+ return ret ;
576+ }
577+
504578/* Bounded recursion through Include directives: a self-including config
505579 * must fail with WS_BAD_ARGUMENT once the depth limit is hit, and the
506580 * config object must remain usable so a subsequent load of a normal
@@ -936,6 +1010,7 @@ const TEST_CASE testCases[] = {
9361010 TEST_DECL (test_ParseConfigLine ),
9371011 TEST_DECL (test_ConfigCopy ),
9381012 TEST_DECL (test_GetUserConfMatchOverride ),
1013+ TEST_DECL (test_MatchUnsupportedSelector ),
9391014 TEST_DECL (test_CAKeysFileDiffers ),
9401015 TEST_DECL (test_IncludeRecursionBound ),
9411016 TEST_DECL (test_ConfigFree ),
0 commit comments