package client import ( "context" "fmt" "sync" "git.tardisproject.uk/tcmal/vault-plugin-kerberos-secrets/config" krbClient "github.com/jcmturner/gokrb5/v8/client" krbConfig "github.com/jcmturner/gokrb5/v8/config" "github.com/jcmturner/gokrb5/v8/iana/nametype" // "github.com/jcmturner/gokrb5/v8/kadmin" krbMessages "github.com/jcmturner/gokrb5/v8/messages" krbTypes "github.com/jcmturner/gokrb5/v8/types" ) type client struct { *sync.Mutex kCfg *krbConfig.Config kClient *krbClient.Client } func ClientFromConfig(config *config.Config) (client, error) { kCfg := krbConfig.New() kCfg.Realms = []krbConfig.Realm{ { Realm: config.Realm, DefaultDomain: config.Realm, KDC: config.KDC, KPasswdServer: config.KPasswdServer, AdminServer: []string{}, MasterKDC: config.KDC, }, } kClient := krbClient.NewWithPassword(config.Username, config.Realm, config.Password, kCfg) return client{ &sync.Mutex{}, kCfg, kClient, }, nil } func (c client) SetPassword(ctx context.Context, username string, password string) error { c.Lock() defer c.Unlock() if err := c.kClient.AffirmLogin(); err != nil { return fmt.Errorf("error logging in as admin principal: %e", err) } // Get a ticket for using kadmin/admin cl := c.kClient ASReq, err := krbMessages.NewASReqForChgPasswd(cl.Credentials.Domain(), cl.Config, cl.Credentials.CName()) if err != nil { return fmt.Errorf("error creating ticket request for kadmin: %s", err) } ASRep, err := cl.ASExchange(cl.Credentials.Domain(), ASReq, 0) if err != nil { return fmt.Errorf("error exchanging request for kadmin ticket: %s", err) } // Construct the change passwd msg msg, key, err := ChangePasswdMsg( krbTypes.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, username), cl.Credentials.CName(), cl.Credentials.Domain(), password, ASRep.Ticket, ASRep.DecryptedEncPart.Key, ) if err != nil { return fmt.Errorf("error creating change passwd msg: %s", err) } // Send it to kpasswd r, err := sendToKAdmin(cl, msg) if err != nil { return fmt.Errorf("error communicating with kpasswd: %s", err) } // Decrypt the result if r.ResultCode != 0 { return fmt.Errorf("error response from kadmin: code: %d; result: %s; krberror: %v", r.ResultCode, r.Result, r.KRBError) } err = r.Decrypt(key) if err != nil { return fmt.Errorf("error decrypting result: %s", err) } return nil }