github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/filesystem/permissions.go (about) 1 package filesystem 2 3 import ( 4 "strings" 5 ) 6 7 // OwnershipIdentifierKind specifies the type of an identifier provided for 8 // ownership specification. 9 type OwnershipIdentifierKind uint8 10 11 const ( 12 // OwnershipIdentifierKindInvalid specifies an invalid identifier kind. 13 OwnershipIdentifierKindInvalid OwnershipIdentifierKind = iota 14 // OwnershipIdentifierKindPOSIXID specifies a POSIX user or group ID. 15 OwnershipIdentifierKindPOSIXID 16 // OwnershipIdentifierKindWindowsSID specifies a Windows SID. 17 OwnershipIdentifierKindWindowsSID 18 // OwnershipIdentifierKindName specifies a name-based identifier. 19 OwnershipIdentifierKindName 20 ) 21 22 // isValidPOSIXID determines whether or not a string represents a valid POSIX 23 // user or group ID. 24 func isValidPOSIXID(value string) bool { 25 // Ensure that the value is non-empty. 26 if len(value) == 0 { 27 return false 28 } 29 30 // As a special case, allow 0 for root specification. We disallow numeric 31 // values that start with a 0 below, so we have to allow this specification 32 // explicitly. 33 if value == "0" { 34 return true 35 } 36 37 // Ensure that the string starts with a non-0 digit (just so we know that 38 // we're not going to parse in octal mode) and that all digits are between 39 // 0 and 9. 40 first := true 41 for _, r := range value { 42 if first { 43 if !('1' <= r && r <= '9') { 44 return false 45 } 46 first = false 47 } else { 48 if !('0' <= r && r <= '9') { 49 return false 50 } 51 } 52 } 53 54 // Success. 55 return true 56 } 57 58 // isValidWindowsSID determines whether or not a string represents a valid 59 // Windows SID. It does not validate that the string resolves to a valid SID, 60 // merely that the formatting is plausible. 61 func isValidWindowsSID(value string) bool { 62 // Ensure that the value is non-empty. 63 if len(value) == 0 { 64 return false 65 } 66 67 // Unfortunately there's not much validation we can do beyond this because 68 // Windows supports string constants (e.g. "BA" resolves to built-in 69 // administrators) that we have no way of validating (and they seem to 70 // change by syste language). So we just assume that the identifier is valid 71 // for now. It will fail later on resolution if it's invalid. 72 return true 73 } 74 75 // ParseOwnershipIdentifier parses an identifier provided for ownership 76 // specification. 77 func ParseOwnershipIdentifier(specification string) (OwnershipIdentifierKind, string) { 78 // Ensure that the specification is non-empty. 79 if len(specification) == 0 { 80 return OwnershipIdentifierKindInvalid, "" 81 } 82 83 // Check if this is a POSIX ID. 84 if strings.HasPrefix(specification, "id:") { 85 if value := specification[3:]; !isValidPOSIXID(value) { 86 return OwnershipIdentifierKindInvalid, "" 87 } else { 88 return OwnershipIdentifierKindPOSIXID, value 89 } 90 } 91 92 // Check if this is a Windows SID. 93 if strings.HasPrefix(specification, "sid:") { 94 if value := specification[4:]; !isValidWindowsSID(value) { 95 return OwnershipIdentifierKindInvalid, "" 96 } else { 97 return OwnershipIdentifierKindWindowsSID, value 98 } 99 } 100 101 // Otherwise assume this is a name-based specification. If it's not valid, 102 // it will fail during lookup. Unfortunately there isn't a good set of 103 // cross-platform validations that we can perform to ensure that the name is 104 // valid. On POSIX it's governed by NAME_REGEX, which is system-dependent 105 // and not accessible except via cgo. On Windows, I think it's more of a 106 // trial-and-error check. 107 return OwnershipIdentifierKindName, specification 108 }