github.com/m10x/go/src@v0.0.0-20220112094212-ba61592315da/net/nss.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 7 package net 8 9 import ( 10 "errors" 11 "internal/bytealg" 12 "io" 13 "os" 14 ) 15 16 // nssConf represents the state of the machine's /etc/nsswitch.conf file. 17 type nssConf struct { 18 err error // any error encountered opening or parsing the file 19 sources map[string][]nssSource // keyed by database (e.g. "hosts") 20 } 21 22 type nssSource struct { 23 source string // e.g. "compat", "files", "mdns4_minimal" 24 criteria []nssCriterion 25 } 26 27 // standardCriteria reports all specified criteria have the default 28 // status actions. 29 func (s nssSource) standardCriteria() bool { 30 for i, crit := range s.criteria { 31 if !crit.standardStatusAction(i == len(s.criteria)-1) { 32 return false 33 } 34 } 35 return true 36 } 37 38 // nssCriterion is the parsed structure of one of the criteria in brackets 39 // after an NSS source name. 40 type nssCriterion struct { 41 negate bool // if "!" was present 42 status string // e.g. "success", "unavail" (lowercase) 43 action string // e.g. "return", "continue" (lowercase) 44 } 45 46 // standardStatusAction reports whether c is equivalent to not 47 // specifying the criterion at all. last is whether this criteria is the 48 // last in the list. 49 func (c nssCriterion) standardStatusAction(last bool) bool { 50 if c.negate { 51 return false 52 } 53 var def string 54 switch c.status { 55 case "success": 56 def = "return" 57 case "notfound", "unavail", "tryagain": 58 def = "continue" 59 default: 60 // Unknown status 61 return false 62 } 63 if last && c.action == "return" { 64 return true 65 } 66 return c.action == def 67 } 68 69 func parseNSSConfFile(file string) *nssConf { 70 f, err := os.Open(file) 71 if err != nil { 72 return &nssConf{err: err} 73 } 74 defer f.Close() 75 return parseNSSConf(f) 76 } 77 78 func parseNSSConf(r io.Reader) *nssConf { 79 slurp, err := readFull(r) 80 if err != nil { 81 return &nssConf{err: err} 82 } 83 conf := new(nssConf) 84 conf.err = foreachLine(slurp, func(line []byte) error { 85 line = trimSpace(removeComment(line)) 86 if len(line) == 0 { 87 return nil 88 } 89 colon := bytealg.IndexByte(line, ':') 90 if colon == -1 { 91 return errors.New("no colon on line") 92 } 93 db := string(trimSpace(line[:colon])) 94 srcs := line[colon+1:] 95 for { 96 srcs = trimSpace(srcs) 97 if len(srcs) == 0 { 98 break 99 } 100 sp := bytealg.IndexByte(srcs, ' ') 101 var src string 102 if sp == -1 { 103 src = string(srcs) 104 srcs = nil // done 105 } else { 106 src = string(srcs[:sp]) 107 srcs = trimSpace(srcs[sp+1:]) 108 } 109 var criteria []nssCriterion 110 // See if there's a criteria block in brackets. 111 if len(srcs) > 0 && srcs[0] == '[' { 112 bclose := bytealg.IndexByte(srcs, ']') 113 if bclose == -1 { 114 return errors.New("unclosed criterion bracket") 115 } 116 var err error 117 criteria, err = parseCriteria(srcs[1:bclose]) 118 if err != nil { 119 return errors.New("invalid criteria: " + string(srcs[1:bclose])) 120 } 121 srcs = srcs[bclose+1:] 122 } 123 if conf.sources == nil { 124 conf.sources = make(map[string][]nssSource) 125 } 126 conf.sources[db] = append(conf.sources[db], nssSource{ 127 source: src, 128 criteria: criteria, 129 }) 130 } 131 return nil 132 }) 133 return conf 134 } 135 136 // parses "foo=bar !foo=bar" 137 func parseCriteria(x []byte) (c []nssCriterion, err error) { 138 err = foreachField(x, func(f []byte) error { 139 not := false 140 if len(f) > 0 && f[0] == '!' { 141 not = true 142 f = f[1:] 143 } 144 if len(f) < 3 { 145 return errors.New("criterion too short") 146 } 147 eq := bytealg.IndexByte(f, '=') 148 if eq == -1 { 149 return errors.New("criterion lacks equal sign") 150 } 151 lowerASCIIBytes(f) 152 c = append(c, nssCriterion{ 153 negate: not, 154 status: string(f[:eq]), 155 action: string(f[eq+1:]), 156 }) 157 return nil 158 }) 159 return 160 }