From 5e7b10cad7e0352ff047ab7dc87305916a8a3d32 Mon Sep 17 00:00:00 2001 From: George Shaw Date: Fri, 6 Apr 2018 15:38:19 -0500 Subject: [PATCH] added package github.com/george-e-shaw-iv/nixtools to dep --- Gopkg.lock | 15 +- .../george-e-shaw-iv/nixtools/.github/LICENSE | 21 ++ .../nixtools/.github/README.md | 4 + .../george-e-shaw-iv/nixtools/.gitignore | 16 + .../george-e-shaw-iv/nixtools/nixtools.go | 10 + .../george-e-shaw-iv/nixtools/ssh.go | 215 +++++++++++++ .../george-e-shaw-iv/nixtools/users.go | 284 ++++++++++++++++++ 7 files changed, 563 insertions(+), 2 deletions(-) create mode 100644 vendor/github.com/george-e-shaw-iv/nixtools/.github/LICENSE create mode 100644 vendor/github.com/george-e-shaw-iv/nixtools/.github/README.md create mode 100644 vendor/github.com/george-e-shaw-iv/nixtools/.gitignore create mode 100644 vendor/github.com/george-e-shaw-iv/nixtools/nixtools.go create mode 100644 vendor/github.com/george-e-shaw-iv/nixtools/ssh.go create mode 100644 vendor/github.com/george-e-shaw-iv/nixtools/users.go diff --git a/Gopkg.lock b/Gopkg.lock index 2709ec5..f0edc31 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -13,10 +13,21 @@ revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29" version = "v3.1.0" +[[projects]] + branch = "master" + name = "github.com/george-e-shaw-iv/nixtools" + packages = ["."] + revision = "a3be4bd706b46bc571b4b34981b06089c6c7158d" + [[projects]] branch = "master" name = "golang.org/x/crypto" - packages = ["acme","acme/autocert","bcrypt","blowfish"] + packages = [ + "acme", + "acme/autocert", + "bcrypt", + "blowfish" + ] revision = "2509b142fb2b797aa7587dad548f113b2c0f20ce" [[projects]] @@ -28,6 +39,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "bc99bfe3269f7f4c24a0166bbfe5fd0cafdee6c803274787bff0ac01b8cb4ed6" + inputs-digest = "95bd56d22992e0d2f4bb1959e7b1b38f5c9716c6c643eff6b6da090d29fb1245" solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/github.com/george-e-shaw-iv/nixtools/.github/LICENSE b/vendor/github.com/george-e-shaw-iv/nixtools/.github/LICENSE new file mode 100644 index 0000000..6329853 --- /dev/null +++ b/vendor/github.com/george-e-shaw-iv/nixtools/.github/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 George Shaw + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/george-e-shaw-iv/nixtools/.github/README.md b/vendor/github.com/george-e-shaw-iv/nixtools/.github/README.md new file mode 100644 index 0000000..6ece8fb --- /dev/null +++ b/vendor/github.com/george-e-shaw-iv/nixtools/.github/README.md @@ -0,0 +1,4 @@ +# nixtools +A golang toolkit for linux system operations. + +The GoDoc reference for `george-e-shaw-iv/nixtools` is located [here](https://godoc.org/github.com/george-e-shaw-iv/nixtools). \ No newline at end of file diff --git a/vendor/github.com/george-e-shaw-iv/nixtools/.gitignore b/vendor/github.com/george-e-shaw-iv/nixtools/.gitignore new file mode 100644 index 0000000..da2ea25 --- /dev/null +++ b/vendor/github.com/george-e-shaw-iv/nixtools/.gitignore @@ -0,0 +1,16 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib +nixtools + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ +.idea/ diff --git a/vendor/github.com/george-e-shaw-iv/nixtools/nixtools.go b/vendor/github.com/george-e-shaw-iv/nixtools/nixtools.go new file mode 100644 index 0000000..901de06 --- /dev/null +++ b/vendor/github.com/george-e-shaw-iv/nixtools/nixtools.go @@ -0,0 +1,10 @@ +// Package nixtools is a toolkit for various linux +// system operations. +package nixtools + +// Type user is a struct that has functions attached to +// it that require a username to properly carry out. +type User struct { + ID int + Name string +} \ No newline at end of file diff --git a/vendor/github.com/george-e-shaw-iv/nixtools/ssh.go b/vendor/github.com/george-e-shaw-iv/nixtools/ssh.go new file mode 100644 index 0000000..d649a9e --- /dev/null +++ b/vendor/github.com/george-e-shaw-iv/nixtools/ssh.go @@ -0,0 +1,215 @@ +package nixtools + +import ( + "os/exec" + "bytes" + "errors" + "os" + "io/ioutil" + "strings" +) + +// Function InitSSH creates the necessary folders, +// files, and generates a default key-pair for the +// given user. If parameter rootHasAccess is set +// to true then the public key of the root (sudo) user +// will be copied into the authorized_keys file of +// the user. +func (u *User) InitSSH(rootHasAccess bool) (error) { + var stderr bytes.Buffer + + keygenArgs := []string{ + "-t", + "rsa", + "-N", + "", + "-f", + "/home/" + u.Name + "/.ssh/id_rsa", + } + + // Create the .ssh folder for said user + cmd := exec.Command("mkdir", "/home/"+u.Name+"/.ssh") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + // Create authorized_keys file + cmd = exec.Command("touch", "/home/"+u.Name+"/.ssh/authorized_keys") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + if rootHasAccess { + // Put root public key into authorized_keys file + cmd = exec.Command("cp", "/root/.ssh/id_rsa.pub", "/home/"+u.Name+"/.ssh/authorized_keys") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + } + + // Create the default key-pair for said user + cmd = exec.Command("ssh-keygen", keygenArgs...) + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + /* OWNERSHIP AND FILE PERMISSIONS START */ + cmd = exec.Command("chmod", "700", "/home/"+u.Name+"/.ssh") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chmod", "600", "/home/"+u.Name+"/.ssh/id_rsa") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chmod", "644", "/home/"+u.Name+"/.ssh/id_rsa.pub") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chmod", "644", "/home/"+u.Name+"/.ssh/authorized_keys") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chown", u.Name+":", "/home/"+u.Name+"/.ssh") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chown", u.Name+":", "/home/"+u.Name+"/.ssh/id_rsa") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chown", u.Name+":", "/home/"+u.Name+"/.ssh/id_rsa.pub") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + cmd = exec.Command("chown", u.Name+":", "/home/"+u.Name+"/.ssh/authorized_keys") + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + /* OWNERSHIP AND FILE PERMISSIONS END */ + + return nil +} + +// Function AddAuthorizedKey adds a new public key to +// a given user's authorized_keys file. +func (u *User) AddAuthorizedKey(key string) error { + f, err := os.OpenFile("/home/"+u.Name+"/.ssh/authorized_keys", os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return err + } + + if _, err = f.WriteString(key + "\n"); err != nil { + return err + } + + return nil +} + +// Function DeleteAuthorizedKey removes a public key +// that is already in the authorized_keys file of +// a given user. +func (u *User) DeleteAuthorizedKey(key string) error { + old, err := ioutil.ReadFile("/home/" + u.Name + "/.ssh/authorized_keys") + if err != nil { + return err + } + + lines := strings.Split(string(old), "\n") + + for i, line := range lines { + if strings.Contains(line, key) { + lines = append(lines[:i], lines[i+1:]...) + break + } + } + + new := strings.Join(lines, "\n") + + f, err := os.OpenFile("/home/"+u.Name+"/.ssh/authorized_keys", os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + return err + } + + if _, err = f.WriteString(new); err != nil { + return err + } + + return nil +} + +// Function GetAuthorizedKeys will return a slice +// of strings that contains all of the public keys +// within a given user's authorized_keys file. +// If the parameter removeRootKey is set to true the +// public key of the current root user of the system, +// if found within the file, will not be placed within +// the slice of strings. +func (u *User) GetAuthorizedKeys(removeRootKey bool) ([]string, error) { + f, err := ioutil.ReadFile("/home/" + u.Name + "/.ssh/authorized_keys") + if err != nil { + return nil, err + } + + // Remove empty strings + raw := strings.Split(string(f), "\n") + var clean []string + + for _, each := range raw { + if each != "" { + clean = append(clean, each) + } + } + + // Remove root key if necessary + if removeRootKey { + if len(clean) == 1 { + return nil, nil + } + + key, err := ioutil.ReadFile("/root/.ssh/id_rsa.pub") + if err != nil { + return nil, err + } + + for k, v := range clean { + if v == string(key) { + clean = append(clean[:k], clean[k+1:]...) + break + } + } + } + + return clean, nil +} \ No newline at end of file diff --git a/vendor/github.com/george-e-shaw-iv/nixtools/users.go b/vendor/github.com/george-e-shaw-iv/nixtools/users.go new file mode 100644 index 0000000..fdfeda2 --- /dev/null +++ b/vendor/github.com/george-e-shaw-iv/nixtools/users.go @@ -0,0 +1,284 @@ +package nixtools + +import ( + "os/exec" + "bytes" + "errors" + "strconv" + "io" + "os" + "strings" +) + +// Function GetUser takes either an ID or Username +// as an identifier and returns a type User associated +// with the given identifier. createIfNotExist parameter +// can only be utilized if the function is given a +// username, not an ID. +func GetUser(identifier interface{}, createIfNotExist bool) (*User, error) { + var u User + var err error + + if id, ok := identifier.(int); ok { + u.ID = id + + u.Name, err = getUsername(id) + if err == nil { + return &u, nil + } + + return nil, err + } else if name, ok := identifier.(string); ok { + u.Name = name + + u.ID, err = getUserID(name) + if err == nil { + return &u, nil + } + + if createIfNotExist { + u.ID, err = createUser(name) + if err != nil { + return nil, err + } + + return &u, nil + } + + return nil, err + } + + return nil, errors.New("identifier must be a valid user id (int) or username (string)") +} + +// Function CreateDirectory attempts to create a directory along +// with all of its parent directories (if needed) relative to the +// user's home directory. The perm parameter is in the format of linux +// file permissions (e.g. 0664). +func (u *User) CreateDirectory(dirPath string, perm os.FileMode) (error) { + return os.MkdirAll("/home/"+u.Name+"/"+dirPath, perm) +} + +// Function WriteFile writes to a file with a given mode that +// is set by flags (flag parameter) that are defined within the +// os package. The filePath is relative to the current user's +// home directory. The perm parameter is in the format of linux +// file permissions (e.g. 0664). +func (u *User) WriteFile(filePath string, flag int, perm os.FileMode, content []byte) (error) { + f, err := os.OpenFile("/home/"+u.Name+"/"+filePath, flag, perm) + if err != nil { + return err + } + defer f.Close() + + n, err := f.Write(content) + if err != nil { + return err + } + + if n != len(content) { + f.Close() + _ = os.Remove("/home/"+u.Name+"/"+filePath) + + return errors.New("full length of content was not able to be written, file was attempted to be deleted") + } + + return nil +} + +// Function DeleteFileOrDirectory attempts to delete a named +// file or directory relative to the user's home directory. +func (u *User) DeleteFileOrDirectory(path string) (error) { + return os.RemoveAll("/home/"+u.Name+"/"+path) +} + +// Function Delete will attempt to delete the given user +// attached to the struct. deleteOwnedFiles parameter +// will remove all files owned by the user and +// removeHome parameter will delete the home directory +// of the user. Warning: parameter deleteOwnedFiles will +// cause the function to take awhile to execute, consider +// using a goroutine to prevent your program from stalling. +func (u *User) Delete(removeHome, deleteOwnedFiles bool) (error) { + var stderr bytes.Buffer + var args = []string{ + "--quiet", + } + + if deleteOwnedFiles { + args = append(args, "--remove-all-files") + } + if removeHome { + args = append(args, "--remove-home") + } + + args = append(args, u.Name) + + // Delete the user and try to remove all files associated + cmd := exec.Command("deluser", args...) + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + // Forcefully remove the users home directory as sometimes + // the --remove-home or --remove-all-files flags don't work + if deleteOwnedFiles || removeHome { + cmd = exec.Command("rm", "-rf", "/home/"+u.Name) + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + } + + return nil +} + +// Function SetPassword sets the users password +// to the given parameter. +func (u *User) SetPassword(password string) (error) { + return nil +} + +// Function ForcePasswordChange forces a user to change +// their password upon next login. +func (u *User) ForcePasswordChange() (error) { + cmd := exec.Command("chage", "-d", "0", u.Name) + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + return nil +} + +// Function Lock lock's a users account, rendering them +// unable to login through any means of authentication. +func (u *User) Lock() (error) { + cmd := exec.Command("chage", "-E", "0", u.Name) + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + return nil +} + +// Function Unlock will unlock a users account, allowing +// them to authenticate through all previous mediums. +func (u *User) Unlock() (error) { + cmd := exec.Command("chage", "-E", "-1", u.Name) + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return errors.New(stderr.String()) + } + + return nil +} + +// Function getUserID returns the ID associated with +// a username if it exists or -1 and an error if the +// given username does not exist. +func getUserID(username string) (int, error) { + cmd := exec.Command("id", "-u", username) + + var stderr, stdout bytes.Buffer + cmd.Stderr = &stderr + cmd.Stdout = &stdout + + if err := cmd.Run(); err != nil { + return -1, errors.New(stderr.String()) + } + + stdoutParsed := strings.Replace(stdout.String(), "\n", "", -1) + + id, err := strconv.Atoi(stdoutParsed) + if err != nil { + return -1, err + } + + return id, nil +} + +// Function getUsername returns the username associated +// with an ID if it exists. +func getUsername(id int) (string, error) { + var stderr, stdout bytes.Buffer + reader, writer := io.Pipe() + + cmdOut := exec.Command("getent", "passwd", strconv.Itoa(id)) + cmdOut.Stdout = writer + + cmdIn := exec.Command("cut", "-d:", "-f1") + cmdIn.Stdin = reader + cmdIn.Stdout = &stdout + cmdIn.Stderr = &stderr + + cmdOut.Start() + cmdIn.Start() + + cmdOut.Wait() + writer.Close() + + cmdIn.Wait() + reader.Close() + + if len(stderr.Bytes()) > 0 { + return "", errors.New(stderr.String()) + } + + return stdout.String(), nil +} + +// Function userExists returns true if the given +// username exists within the system or false if +// the given username does not exist. +func UserExists(username string) (bool) { + cmd := exec.Command("id", "-u", username) + + if err := cmd.Run(); err != nil { + return false + } + + return true +} + +// Function createUser will attempt to create a +// new user in the system with the given username. +// Upon success will return the new ID of the +// created user. +func createUser(username string) (int, error) { + var stderr bytes.Buffer + + args := []string{ + "--disabled-password", + "--gecos", + "", + username, + } + + cmd := exec.Command("adduser", args...) + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return 0, errors.New(stderr.String()) + } + + id, err := getUserID(username) + if err != nil { + return 0, err + } + + return id, nil +} \ No newline at end of file