File: main.go

package info (click to toggle)
ssh-tools 1.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,328 kB
  • sloc: sh: 1,403; perl: 785; makefile: 5
file content (345 lines) | stat: -rw-r--r-- 6,907 bytes parent folder | download
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
package main

import (
	"bufio"
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"golang.org/x/crypto/ssh"
	"log"
	"os"
	"os/exec"
	"sigs.k8s.io/yaml"
	"strings"
)

var usage = `
  Usage: %s [OPTION] [<file> ...]

  Collects info from authorized_keys files from every user it can find

  OPTIONS:

      -j  --json     output JSON
      -J  --jsonl    output JSONLINES
      -r  --rec      output RECUTILS
      -x  --xml      output XML
      -y  --yaml     output YAML

          --version  show version information

  ARGUMENTS:

      file           authorized_keys file
`

var options struct {
	version bool
	json    bool
	jsonl   bool
	xml     bool
	rec     bool
	yaml    bool
}

type User struct {
	Name      string
	Password  string
	UID       string
	GID       string
	GECOS     string
	Directory string
	Shell     string
}

type AuthorizedKey struct {
	Name              string
	Directory         string
	File              string
	Type              string
	FingerprintMD5    string
	FingerprintSHA256 string
	Comment           string
	Options           []string
	IsCA              bool
}

var Users []User
var authorizedKeys []AuthorizedKey

var Version string = "ssh-authorized-keys (ssh-tools) 1.9"

func printVersion() {
	fmt.Printf("%s\n", strings.TrimSpace(Version))
}

func getent_passwd() {

	cmd := exec.Command("getent", "passwd")

	stdout, err := cmd.StdoutPipe()

	if err != nil {
		log.Println(err)
	}

	scanner := bufio.NewScanner(stdout)

	err = cmd.Start()

	if err != nil {
		log.Println(err)
	}

	for scanner.Scan() {
		line := scanner.Text()
		// skip all line starting with #
		if equal := strings.Index(line, "#"); equal < 0 {

			lineSlice := strings.Split(line, ":")

			if len(lineSlice) > 0 {
				user := User{}
				user.Name = lineSlice[0]
				user.Password = lineSlice[1]
				user.UID = lineSlice[2]
				user.GID = lineSlice[3]
				user.GECOS = lineSlice[4]
				user.Directory = lineSlice[5]
				//user.Shell = lineSlice[6]

				Users = append(Users, user)

			}

		}
	}

	if scanner.Err() != nil {
		cmd.Process.Kill()
		cmd.Wait()
		fmt.Println(scanner.Err())
	}

	cmd.Wait()
}

func get_authorized_keys(authorized_keys_file string, name string, directory string) {

	_, err := os.Open(authorized_keys_file)

	if err == nil {

		authorizedKeysBytes, err := os.ReadFile(authorized_keys_file)

		if err != nil {
			log.Println(err)
		}

		for len(authorizedKeysBytes) > 0 {
			pubKey, comment, options, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)

			authorizedKeysBytes = rest

			if err != nil {
				log.Println(err, "in", authorized_keys_file)
				continue
			}

			isCA := false

			for _, option := range options {
				if option == "cert-authority" {
					isCA = true
				}
			}

			authorizedKey := AuthorizedKey{}

			authorizedKey.Name = name
			authorizedKey.Directory = directory
			authorizedKey.File = authorized_keys_file
			authorizedKey.Type = pubKey.Type()
			authorizedKey.FingerprintMD5 = ssh.FingerprintLegacyMD5(pubKey)
			authorizedKey.FingerprintSHA256 = ssh.FingerprintSHA256(pubKey)
			authorizedKey.Comment = comment
			authorizedKey.Options = options
			authorizedKey.IsCA = isCA

			authorizedKeys = append(authorizedKeys, authorizedKey)

		}

	}

}

func main() {

	// CLI
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), usage, os.Args[0])
	}

	flag.BoolVar(&options.version, "version", options.version, "Show version information")

	flag.BoolVar(&options.json, "j", options.json, "Output JSON")
	flag.BoolVar(&options.json, "json", options.json, "Output JSON")

	flag.BoolVar(&options.jsonl, "J", options.jsonl, "Output JSONLINES")
	flag.BoolVar(&options.jsonl, "jsonl", options.jsonl, "Output JSONLINES")

	flag.BoolVar(&options.rec, "r", options.rec, "Output RECUTILS")
	flag.BoolVar(&options.rec, "rec", options.rec, "Output RECUTILS")

	flag.BoolVar(&options.xml, "x", options.xml, "Output XML")
	flag.BoolVar(&options.xml, "xml", options.xml, "Output XML")

	flag.BoolVar(&options.yaml, "y", options.yaml, "Output YAML")
	flag.BoolVar(&options.yaml, "yaml", options.yaml, "Output YAML")

	flag.Parse()

	if options.version {
		printVersion()
		os.Exit(0)
	}

	files := flag.Args()

	find_all_files := true

	if len(files) > 0 {

		find_all_files = false

	}

	if find_all_files {

		// Get all users
		getent_passwd()

		// Now we have a list of users
		// Iterate over each of them to
		// get their info and authorized_keys file

		for _, u := range Users {

			authorized_keys_file := u.Directory + "/.ssh/authorized_keys"

			get_authorized_keys(authorized_keys_file, u.Name, u.Directory)

		}

	} else {

		for _, f := range files {

			authorized_keys_file := f

			get_authorized_keys(authorized_keys_file, "N/A", "N/A")

		}

	}

	// XML Output
	if options.xml {
		xmlBytes, err := xml.MarshalIndent(authorizedKeys, "", "    ")

		if err != nil {
			log.Println(err)
		}

		xmlOutput := string(xmlBytes)

		fmt.Println(xmlOutput)

		os.Exit(0)
	}

	// JSON Output
	if options.json {
		jsonBytes, err := json.MarshalIndent(authorizedKeys, "", "    ")

		if err != nil {
			log.Println(err)
		}

		jsonOutput := string(jsonBytes)

		fmt.Println(jsonOutput)

		os.Exit(0)
	}

	// JSON Lines Output
	if options.jsonl {

		for _, authorizedKey := range authorizedKeys {
			jsonBytes, err := json.Marshal(authorizedKey)

			if err != nil {
				log.Println(err)
			}

			jsonOutput := string(jsonBytes)

			fmt.Println(jsonOutput)
		}

		os.Exit(0)
	}

	// YAML Output
	if options.yaml {
		yamlBytes, err := yaml.Marshal(authorizedKeys)

		if err != nil {
			log.Println(err)
		}

		yamlOutput := string(yamlBytes)

		fmt.Println(yamlOutput)
		os.Exit(0)
	}

	// RECUTILS Output
	if options.rec {
		for _, authKey := range authorizedKeys {
			fmt.Println("")
			fmt.Printf("%s: %v\n", "Name", authKey.Name)
			fmt.Printf("%s: %v\n", "Directory", authKey.Directory)
			fmt.Printf("%s: %v\n", "File", authKey.File)
			fmt.Printf("%s: %v\n", "Type", authKey.Type)
			fmt.Printf("%s: %v\n", "FingerprintMD5", authKey.FingerprintMD5)
			fmt.Printf("%s: %v\n", "FingerprintSHA256", authKey.FingerprintSHA256)
			fmt.Printf("%s: %v\n", "Comment", authKey.Comment)
			fmt.Printf("%s: %v\n", "Options", authKey.Options)
			fmt.Printf("%s: %v\n", "IsCA", authKey.IsCA)
		}

		os.Exit(0)
	}

	// DEFAULT Output
	for _, authKey := range authorizedKeys {
		fmt.Println("")

		fmt.Printf("%-20s : %v\n", "Name", authKey.Name)
		fmt.Printf("%-20s : %v\n", "Directory", authKey.Directory)
		fmt.Printf("%-20s : %v\n", "File", authKey.File)
		fmt.Printf("%-20s : %v\n", "Type", authKey.Type)
		fmt.Printf("%-20s : %v\n", "FingerprintMD5", authKey.FingerprintMD5)
		fmt.Printf("%-20s : %v\n", "FingerprintSHA256", authKey.FingerprintSHA256)
		fmt.Printf("%-20s : %v\n", "Comment", authKey.Comment)
		fmt.Printf("%-20s : %v\n", "Options", authKey.Options)
		fmt.Printf("%-20s : %v\n", "IsCA", authKey.IsCA)

	}
	os.Exit(0)

}