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

     1  // copyright: 2020, 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  	"regexp"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"go.mondoo.com/cnquery/llx"
    15  	"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
    16  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    17  )
    18  
    19  var findTypes = map[string]string{
    20  	"file":      "f",
    21  	"directory": "d",
    22  	"character": "c",
    23  	"block":     "b",
    24  	"socket":    "s",
    25  	"link":      "l",
    26  }
    27  
    28  func initFilesFind(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) {
    29  	if args["permissions"] == nil {
    30  		args["permissions"] = llx.IntData(int64(0o777))
    31  	}
    32  
    33  	return args, nil, nil
    34  }
    35  
    36  func octal2string(o int64) string {
    37  	return fmt.Sprintf("%o", o)
    38  }
    39  
    40  func (l *mqlFilesFind) id() (string, error) {
    41  	var id strings.Builder
    42  	id.WriteString(l.From.Data)
    43  	if !l.Xdev.Data {
    44  		id.WriteString(" -xdev")
    45  	}
    46  	if l.Type.Data != "" {
    47  		id.WriteString(" type=" + l.Type.Data)
    48  	}
    49  
    50  	if l.Regex.Data != "" {
    51  		id.WriteString(" regex=" + l.Regex.Data)
    52  	}
    53  
    54  	if l.Name.Data != "" {
    55  		id.WriteString(" name=" + l.Name.Data)
    56  	}
    57  
    58  	if l.Permissions.Data != 0o777 {
    59  		id.WriteString(" permissions=" + octal2string(l.Permissions.Data))
    60  	}
    61  
    62  	return id.String(), nil
    63  }
    64  
    65  func (l *mqlFilesFind) list() ([]interface{}, error) {
    66  	var err error
    67  	var compiledRegexp *regexp.Regexp
    68  	if len(l.Regex.Data) > 0 {
    69  		compiledRegexp, err = regexp.Compile(l.Regex.Data)
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  	}
    74  
    75  	var foundFiles []string
    76  	conn := l.MqlRuntime.Connection.(shared.Connection)
    77  	if conn.Capabilities().Has(shared.Capability_FindFile) {
    78  		fs := conn.FileSystem()
    79  		fsSearch, ok := fs.(shared.FileSearch)
    80  		if !ok {
    81  			return nil, errors.New("find is not supported for your platform")
    82  		}
    83  
    84  		foundFiles, err = fsSearch.Find(l.From.Data, compiledRegexp, l.Type.Data)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  	} else if conn.Capabilities().Has(shared.Capability_RunCommand) {
    89  		var call strings.Builder
    90  		call.WriteString("find -L ")
    91  		call.WriteString(strconv.Quote(l.From.Data))
    92  
    93  		if !l.Xdev.Data {
    94  			call.WriteString(" -xdev")
    95  		}
    96  
    97  		if l.Type.Data != "" {
    98  			t, ok := findTypes[l.Type.Data]
    99  			if ok {
   100  				call.WriteString(" -type " + t)
   101  			}
   102  		}
   103  
   104  		if l.Regex.Data != "" {
   105  			// TODO: we need to escape regex here
   106  			call.WriteString(" -regex '")
   107  			call.WriteString(l.Regex.Data)
   108  			call.WriteString("'")
   109  		}
   110  
   111  		if l.Permissions.Data != 0o777 {
   112  			call.WriteString(" -perm -")
   113  			call.WriteString(octal2string(l.Permissions.Data))
   114  		}
   115  
   116  		if l.Name.Data != "" {
   117  			call.WriteString(" -name ")
   118  			call.WriteString(l.Name.Data)
   119  		}
   120  
   121  		rawCmd, err := CreateResource(l.MqlRuntime, "command", map[string]*llx.RawData{
   122  			"command": llx.StringData(call.String()),
   123  		})
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  
   128  		cmd := rawCmd.(*mqlCommand)
   129  		out := cmd.GetStdout()
   130  		if out.Error != nil {
   131  			return nil, out.Error
   132  		}
   133  
   134  		lines := strings.TrimSpace(out.Data)
   135  		if lines == "" {
   136  			foundFiles = []string{}
   137  		} else {
   138  			foundFiles = strings.Split(lines, "\n")
   139  		}
   140  	} else {
   141  		return nil, errors.New("find is not supported for your platform")
   142  	}
   143  
   144  	files := make([]interface{}, len(foundFiles))
   145  	var filepath string
   146  	for i := range foundFiles {
   147  		filepath = foundFiles[i]
   148  		files[i], err = CreateResource(l.MqlRuntime, "file", map[string]*llx.RawData{
   149  			"path": llx.StringData(filepath),
   150  		})
   151  		if err != nil {
   152  			return nil, err
   153  		}
   154  	}
   155  
   156  	// return the packages as new entries
   157  	return files, nil
   158  }