summaryrefslogtreecommitdiff
path: root/kdc.go
blob: 0c35a16f3bd4072b6a7f76309bd9d29cd09444c0 (plain)
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
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

type Krb5Conf struct {
	Principal string
	Keytab    string
	Realm     string
}

var suffixMap map[string]string = map[string]string{
	"SSO":     "",
	"EDUROAM": "/ppp",
	"TACACS":  "/net",
}

func CheckDuplicatePw(username, password string) error {
	for suffix, _ := range suffixMap {
		err := checkKerberosDuplicatePw(suffix, username, password)
		if err != nil {
			return err
		}
	}
	return nil
}

func checkKerberosDuplicatePw(suffix, username, password string) error {
	//   KRB5_CONFIG env for heimdal-kinit
	//   KRB5CCNAME for setting the cache name

	principal := fmt.Sprintf("%s%s@%s", username, suffixMap[suffix], pwman.Krb5Conf.Realm)

	cmd := exec.Command("kinit", "--password-file=STDIN", principal)
	cmd.Env = append(os.Environ())
	cmd.Stdin = strings.NewReader(password)

	out, err := cmd.CombinedOutput()

	if err != nil {
		// everything is fine, it should fail
		if containsEither(string(out), "kinit: Password incorrect", "krb5_get_init_creds") {
			return nil
		}
		return fmt.Errorf("Error while checking %s password for duplicate, got error: %v, Output: %s", suffix, err, out)
	}

	// Run kdestroy to log out
	kdest := exec.Command("kdestroy")
	kdest.Run()

	return fmt.Errorf("Password already used with: %s account", suffix)
}

func ChangeKerberosPw(suffix, username, new_password string) error {
	conf := pwman.Krb5Conf
	kerberos_uid := fmt.Sprintf("%s%s@%s", username, suffixMap[suffix], conf.Realm)

	err := ensureCreatedKerberosPrincipal(kerberos_uid)

	if err != nil {
		return err
	}

	cmd := exec.Command("kadmin", "-K", conf.Keytab, "-p", conf.Principal, "cpw", "-p", new_password, kerberos_uid)
	out, err := cmd.CombinedOutput()

	if err != nil {
		log.Println("ERROR", "Error runing kadmin for change password, got error:", err, "with script output:", string(out))
		return fmt.Errorf("Error could not change password, got error: %v", err)
	}

	return nil
}

func ensureCreatedKerberosPrincipal(principal string) error {
	conf := pwman.Krb5Conf
	exists, err := checkKerberosPrincipalExists(principal)

	if err != nil {
		return err
	}

	if !exists {
		cmd := exec.Command("kadmin", "-K", conf.Keytab, "-p", conf.Principal, "add", "--use-defaults", "--random-password", principal)
		out, err := cmd.CombinedOutput()

		if err != nil {
			fmt.Errorf("Could not create principal %s, got error: %v, output: %s", principal, err, out)
		}
	}
	return nil
}

func checkKerberosPrincipalExists(principal string) (bool, error) {
	conf := pwman.Krb5Conf
	cmd := exec.Command("kadmin", "-K", conf.Keytab, "-p", conf.Principal, "get", principal)
	// get markus/ppp: Principal does not exist
	out, err := cmd.CombinedOutput()

	if err != nil {
		if containsEither(string(out), "Principal does not exist") {
			return false, nil
		}
		return false, fmt.Errorf("Could not check if principal %s exists, got error: %v, output: %s", principal, err, out)
	}
	return true, nil
}