...

Source file src/pkg/net/nss.go

     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	// +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	}
   161	

View as plain text