go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/sshd.go (about)

     1  // copyright: 2019, Dominik Richter and Christoph Hartmann
     2  // author: Dominik Richter
     3  // author: Christoph Hartmann
     4  
     5  package resources
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"strings"
    11  
    12  	"go.mondoo.com/cnquery/llx"
    13  	"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
    14  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    15  	"go.mondoo.com/cnquery/providers/os/resources/sshd"
    16  )
    17  
    18  func initSshdConfig(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) {
    19  	if x, ok := args["path"]; ok {
    20  		path, ok := x.Value.(string)
    21  		if !ok {
    22  			return nil, nil, errors.New("wrong type for 'path' in sshd.config initialization, it must be a string")
    23  		}
    24  
    25  		f, err := CreateResource(runtime, "file", map[string]*llx.RawData{
    26  			"path": llx.StringData(path),
    27  		})
    28  		if err != nil {
    29  			return nil, nil, err
    30  		}
    31  		args["file"] = llx.ResourceData(f, "file")
    32  
    33  		delete(args, "path")
    34  	}
    35  
    36  	return args, nil, nil
    37  }
    38  
    39  const defaultSshdConfig = "/etc/ssh/sshd_config"
    40  
    41  func (s *mqlSshdConfig) id() (string, error) {
    42  	file := s.GetFile()
    43  	if file.Error != nil {
    44  		return "", file.Error
    45  	}
    46  
    47  	return file.Data.Path.Data, nil
    48  }
    49  
    50  func (s *mqlSshdConfig) file() (*mqlFile, error) {
    51  	f, err := CreateResource(s.MqlRuntime, "file", map[string]*llx.RawData{
    52  		"path": llx.StringData(defaultSshdConfig),
    53  	})
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	return f.(*mqlFile), nil
    58  }
    59  
    60  func (s *mqlSshdConfig) files(file *mqlFile) ([]interface{}, error) {
    61  	if !file.GetExists().Data {
    62  		return nil, errors.New("sshd config does not exist in " + file.GetPath().Data)
    63  	}
    64  
    65  	conn := s.MqlRuntime.Connection.(shared.Connection)
    66  	allFiles, err := sshd.GetAllSshdIncludedFiles(file.Path.Data, conn)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	// Return a list of lumi files
    72  	lumiFiles := make([]interface{}, len(allFiles))
    73  	for i, path := range allFiles {
    74  		lumiFile, err := CreateResource(s.MqlRuntime, "file", map[string]*llx.RawData{
    75  			"path": llx.StringData(path),
    76  		})
    77  		if err != nil {
    78  			return nil, err
    79  		}
    80  
    81  		lumiFiles[i] = lumiFile.(*mqlFile)
    82  	}
    83  
    84  	return lumiFiles, nil
    85  }
    86  
    87  func (s *mqlSshdConfig) content(files []interface{}) (string, error) {
    88  	// TODO: this can be heavily improved once we do it right, since this is constantly
    89  	// re-registered as the file changes
    90  
    91  	// files is in the "dependency" order that files were discovered while
    92  	// parsing the base/root config file. We will essentially re-parse the
    93  	// config and insert the contents of those dependent files in-place where
    94  	// they appear in the base/root config.
    95  	if len(files) < 1 {
    96  		return "", fmt.Errorf("no base sshd config file to read")
    97  	}
    98  
    99  	lumiFiles := make([]*mqlFile, len(files))
   100  	for i, file := range files {
   101  		lumiFile, ok := file.(*mqlFile)
   102  		if !ok {
   103  			return "", fmt.Errorf("failed to type assert list of files to File interface")
   104  		}
   105  		lumiFiles[i] = lumiFile
   106  	}
   107  
   108  	// The first entry in our list is the base/root of the sshd configuration tree
   109  	baseConfigFilePath := lumiFiles[0].Path.Data
   110  
   111  	conn := s.MqlRuntime.Connection.(shared.Connection)
   112  	fullContent, err := sshd.GetSshdUnifiedContent(baseConfigFilePath, conn)
   113  	if err != nil {
   114  		return "", err
   115  	}
   116  
   117  	return fullContent, nil
   118  }
   119  
   120  func (s *mqlSshdConfig) params(content string) (map[string]interface{}, error) {
   121  	params, err := sshd.Params(content)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	// convert  map
   127  	res := map[string]interface{}{}
   128  	for k, v := range params {
   129  		res[k] = v
   130  	}
   131  
   132  	return res, nil
   133  }
   134  
   135  func (s *mqlSshdConfig) parseConfigEntrySlice(raw interface{}) ([]interface{}, error) {
   136  	strCipher, ok := raw.(string)
   137  	if !ok {
   138  		return nil, errors.New("value is not a valid string")
   139  	}
   140  
   141  	res := []interface{}{}
   142  	entries := strings.Split(strCipher, ",")
   143  	for i := range entries {
   144  		val := strings.TrimSpace(entries[i])
   145  		res = append(res, val)
   146  	}
   147  
   148  	return res, nil
   149  }
   150  
   151  func (s *mqlSshdConfig) ciphers(params map[string]interface{}) ([]interface{}, error) {
   152  	rawCiphers, ok := params["Ciphers"]
   153  	if !ok {
   154  		return nil, nil
   155  	}
   156  
   157  	return s.parseConfigEntrySlice(rawCiphers)
   158  }
   159  
   160  func (s *mqlSshdConfig) macs(params map[string]interface{}) ([]interface{}, error) {
   161  	rawMacs, ok := params["MACs"]
   162  	if !ok {
   163  		return nil, nil
   164  	}
   165  
   166  	return s.parseConfigEntrySlice(rawMacs)
   167  }
   168  
   169  func (s *mqlSshdConfig) kexs(params map[string]interface{}) ([]interface{}, error) {
   170  	rawkexs, ok := params["KexAlgorithms"]
   171  	if !ok {
   172  		return nil, nil
   173  	}
   174  
   175  	return s.parseConfigEntrySlice(rawkexs)
   176  }
   177  
   178  func (s *mqlSshdConfig) hostkeys(params map[string]interface{}) ([]interface{}, error) {
   179  	rawHostKeys, ok := params["HostKey"]
   180  	if !ok {
   181  		return nil, nil
   182  	}
   183  
   184  	return s.parseConfigEntrySlice(rawHostKeys)
   185  }