File: pwd.go

package info (click to toggle)
golang-github-astromechza-etcpwdparse 0.0~git20170319.f0e5f07-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 76 kB
  • sloc: makefile: 2
file content (197 lines) | stat: -rw-r--r-- 5,767 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Package etcpwdparse provides straightforward functionality for loading an /etc/passwd file
// and doing lookups on its content.
//
// Remember this only looks at an /etc/passwd type file, so will work best on Linux operating systems
// and wont pick up users from LDAP and other sources.
package etcpwdparse

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
)

// EtcPasswdEntry is a parsed line from the etc passwd file. It contains all 7 parts of the structure.
// Remember that the password field is encrypted or refers to an item in an alternative authentication scheme.
type EtcPasswdEntry struct {
	username string
	password string
	uid      int
	gid      int
	info     string
	homedir  string
	shell    string
}

// Username function returns the username string for the entry
func (e *EtcPasswdEntry) Username() string {
	return e.username
}

// Password function returns the encrypted password string for the entry
func (e *EtcPasswdEntry) Password() string {
	return e.password
}

// Uid function returns the user id for the entry
func (e *EtcPasswdEntry) Uid() int {
	return e.uid
}

// Gid function returns the group id for the entry
func (e *EtcPasswdEntry) Gid() int {
	return e.gid
}

// Info function returns the info string for the entry
func (e *EtcPasswdEntry) Info() string {
	return e.info
}

// Homedir function returns the home directory for the entry
func (e *EtcPasswdEntry) Homedir() string {
	return e.homedir
}

// Shell function returns the users shell
func (e *EtcPasswdEntry) Shell() string {
	return e.shell
}

// EtcPasswdCache is an object that stores a set of entries from the passwd file and
// has quick lookup functions.
type EtcPasswdCache struct {
	entries        []EtcPasswdEntry
	namemap        map[string]*EtcPasswdEntry
	idmap          map[int]*EtcPasswdEntry
	ignoreBadLines bool
}

// ParsePasswdLine is a function used to parse a 7 entry /etc/passwd line formatted line
// into a EtcPasswdEntry object.
func ParsePasswdLine(line string) (EtcPasswdEntry, error) {
	result := EtcPasswdEntry{}
	parts := strings.Split(strings.TrimSpace(line), ":")
	if len(parts) != 7 {
		return result, fmt.Errorf("Passwd line had wrong number of parts %d != 7", len(parts))
	}
	result.username = strings.TrimSpace(parts[0])
	result.password = strings.TrimSpace(parts[1])

	uid, err := strconv.Atoi(parts[2])
	if err != nil {
		return result, fmt.Errorf("Passwd line had badly formatted uid %s", parts[2])
	}
	result.uid = uid

	gid, err := strconv.Atoi(parts[3])
	if err != nil {
		return result, fmt.Errorf("Passwd line had badly formatted gid %s", parts[2])
	}
	result.gid = gid

	result.info = strings.TrimSpace(parts[4])
	result.homedir = strings.TrimSpace(parts[5])
	result.shell = strings.TrimSpace(parts[6])
	return result, nil
}

// AddEntry adds an entry object to the cache object and links it into the lookup maps.
// Overrides any existing item in the lookup maps.
func (e *EtcPasswdCache) AddEntry(entry EtcPasswdEntry) {
	e.entries = append(e.entries, entry)
	e.namemap[entry.username] = &entry
	e.idmap[entry.uid] = &entry
}

// LoadFromPath loads the struct from a file on disk and replaces the cached content.
func (e *EtcPasswdCache) LoadFromPath(path string) error {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	lines := strings.Split(strings.TrimSpace(string(content)), "\n")
	e.entries = make([]EtcPasswdEntry, 0)
	e.namemap = make(map[string]*EtcPasswdEntry)
	e.idmap = make(map[int]*EtcPasswdEntry)
	for _, line := range lines {
		line = strings.TrimSpace(line)
		// skip commented or empty lines
		if len(line) == 0 || strings.HasPrefix(line, "#") {
			continue
		}
		// parse the current line
		entry, err := ParsePasswdLine(line)
		if err != nil {
			if e.ignoreBadLines {
				continue
			}
			return err
		}
		e.AddEntry(entry)
	}
	return nil
}

// NewEtcPasswdCache returns an empty passwd cache.
func NewEtcPasswdCache(ignoreBadLines bool) *EtcPasswdCache {
	return &EtcPasswdCache{
		ignoreBadLines: ignoreBadLines,
	}
}

// NewLoadedEtcPasswdCache returns a loaded passwd cache in a single call.
func NewLoadedEtcPasswdCache() (*EtcPasswdCache, error) {
	result := NewEtcPasswdCache(false)
	if err := result.LoadDefault(); err != nil {
		return nil, err
	}
	return result, nil
}

// LoadDefault loads the struct from the /etc/passwd file
func (e *EtcPasswdCache) LoadDefault() error {
	return e.LoadFromPath("/etc/passwd")
}

// LookupUserByName returns the entry for the given username
func (e *EtcPasswdCache) LookupUserByName(name string) (*EtcPasswdEntry, bool) {
	entry, ok := e.namemap[name]
	return entry, ok
}

// LookupUserByUid returns the entry for the given userid
func (e *EtcPasswdCache) LookupUserByUid(id int) (*EtcPasswdEntry, bool) {
	entry, ok := e.idmap[id]
	return entry, ok
}

// UidForUsername is a shortcut function to get the user id for the given username.
// Useful when needing to chown a file.
func (e *EtcPasswdCache) UidForUsername(name string) (int, error) {
	entry, ok := e.LookupUserByName(name)
	if !ok {
		return 0, fmt.Errorf("No such user with username '%s'", name)
	}
	return entry.Uid(), nil
}

// HomeDirForUsername is a shortcut function to get the home directory for the given username.
// Useful when needing to store things in the home directory.
func (e *EtcPasswdCache) HomeDirForUsername(name string) (string, error) {
	entry, ok := e.LookupUserByName(name)
	if !ok {
		return "", fmt.Errorf("No such user with username '%s'", name)
	}
	return entry.Homedir(), nil
}

// ListEntries returns a slice containing references to all the entry objects
func (e *EtcPasswdCache) ListEntries() []*EtcPasswdEntry {
	results := make([]*EtcPasswdEntry, len(e.entries))
	for i, e := range e.entries {
		results[i] = &e
	}
	return results
}