summaryrefslogtreecommitdiff
path: root/client/cmd.go
diff options
context:
space:
mode:
Diffstat (limited to 'client/cmd.go')
-rw-r--r--client/cmd.go131
1 files changed, 131 insertions, 0 deletions
diff --git a/client/cmd.go b/client/cmd.go
new file mode 100644
index 0000000..b69880c
--- /dev/null
+++ b/client/cmd.go
@@ -0,0 +1,131 @@
+package client
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os/exec"
+ "strings"
+)
+
+func (c client) princExists(ctx context.Context, name string) (exists bool, err error) {
+ out, err := c.execKrbAdmin(ctx, fmt.Sprintf("getprinc \"%s\"", name), func(writer io.WriteCloser) error { return nil })
+ if err != nil {
+ err = fmt.Errorf("%s (output: %s)", err, out)
+ return
+ }
+
+ if strings.Contains(out, "Principal does not exist") {
+ exists = false
+ } else if strings.Contains(out, "Expiration date: ") {
+ exists = true
+ } else {
+ err = fmt.Errorf("unrecognised output format: %s", out)
+ }
+
+ return
+}
+
+func (c client) doCreatePrinc(ctx context.Context, name string, password string) (err error) {
+ out, err := c.execKrbAdmin(ctx, fmt.Sprintf("addprinc \"%s\"", name), func(writer io.WriteCloser) error {
+ toWrite := append([]byte(password), '\n')
+ for i := 0; i < 2; i++ {
+ n, err := writer.Write(toWrite)
+ if err != nil || n != len(toWrite) {
+ return fmt.Errorf("error writing to stdin: %s", err)
+ }
+ }
+ return nil
+ })
+
+ if err != nil {
+ return
+ }
+
+ if !strings.Contains(out, "created") {
+ err = fmt.Errorf("unrecognised output format: %s", out)
+ }
+
+ return
+}
+
+func (c client) doChangePassword(ctx context.Context, name string, password string) (err error) {
+ out, err := c.execKrbAdmin(ctx, fmt.Sprintf("cpw \"%s\"", name), func(writer io.WriteCloser) error {
+ toWrite := append([]byte(password), '\n')
+ for i := 0; i < 2; i++ {
+ n, err := writer.Write(toWrite)
+ if err != nil || n != len(toWrite) {
+ return fmt.Errorf("error writing to stdin: %s", err)
+ }
+ }
+ return nil
+ })
+
+ if err != nil {
+ return
+ }
+
+ if !strings.Contains(out, "changed") {
+ err = fmt.Errorf("unrecognised output format: %s", out)
+ }
+
+ return
+}
+
+// execKrbAdmin starts krbadmin with the appropriate commands, and tries to authenticate as the admin principal
+func (c client) execKrbAdmin(ctx context.Context, query string, writeFunc func(writer io.WriteCloser) error) (string, error) {
+ kadm, err := exec.LookPath("kadmin")
+ if err != nil {
+ return "", fmt.Errorf("error finding kadmin executable: %s", err)
+ }
+ cmd := exec.CommandContext(
+ ctx,
+ kadm,
+ "-p",
+ c.config.Username,
+ "-r",
+ c.config.Realm,
+ "-s",
+ c.config.KAdminServer,
+ "-q",
+ query,
+ )
+
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ return "", fmt.Errorf("error getting stdin pipe: %s", err)
+ }
+
+ errChan := make(chan error)
+
+ go func() {
+ defer stdin.Close()
+ toWrite := append([]byte(c.config.Password), '\n')
+ n, err := stdin.Write(toWrite)
+
+ if err != nil || n != len(toWrite) {
+ errChan <- fmt.Errorf("error writing to stdin: %s", err)
+ return
+ }
+
+ err = writeFunc(stdin)
+ if err != nil || n != len(toWrite) {
+ errChan <- fmt.Errorf("error writing to stdin: %s", err)
+ return
+ }
+ }()
+
+ rawOut, err := cmd.CombinedOutput()
+ if err != nil {
+ return "", err
+ }
+ out := string(rawOut)
+
+ select {
+ case err = <-errChan:
+ return "", err
+ default:
+ }
+
+ return out, nil
+}