go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/shadow/shadow.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package shadow 5 6 import ( 7 "encoding/csv" 8 "io" 9 "strconv" 10 "strings" 11 "time" 12 ) 13 14 type ShadowEntry struct { 15 User string 16 Password string 17 LastChanged *time.Time 18 MinDays string 19 MaxDays string 20 WarnDays string 21 InactiveDays string 22 ExpiryDates string 23 Reserved string 24 } 25 26 func ParseShadow(r io.Reader) ([]ShadowEntry, error) { 27 res := []ShadowEntry{} 28 29 csvReader := csv.NewReader(r) 30 csvReader.Comma = ':' 31 for { 32 record, err := csvReader.Read() 33 if err == io.EOF { 34 break 35 } 36 if err != nil { 37 return nil, err 38 } 39 // the /etc/shadow file gives the count of days since jan 1, 1970 40 start := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC) 41 var lastChangedTime *time.Time 42 if record[2] == "" { 43 // if the last_changes field is an empty string, nothing was ever changed, return nil 44 lastChangedTime = nil 45 } else { 46 i, err := strconv.Atoi(record[2]) 47 if err != nil { 48 return nil, err 49 } 50 date := start.Add(time.Hour * 24 * time.Duration(i)) 51 lastChangedTime = &date 52 } 53 res = append(res, ShadowEntry{ 54 User: strings.TrimSpace(record[0]), 55 Password: strings.TrimSpace(record[1]), 56 LastChanged: lastChangedTime, 57 MinDays: strings.TrimSpace(record[3]), 58 MaxDays: strings.TrimSpace(record[4]), 59 WarnDays: strings.TrimSpace(record[5]), 60 InactiveDays: strings.TrimSpace(record[6]), 61 ExpiryDates: strings.TrimSpace(record[7]), 62 Reserved: strings.TrimSpace(record[8]), 63 }) 64 } 65 66 return res, nil 67 }