X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/a35ec27b40ce3ca0797cdcd8e0a79b2b8896af47..bd855b0c92549d5cdcabc7a312166e4a6b556697:/lib/pam/pam_arvados.go diff --git a/lib/pam/pam_arvados.go b/lib/pam/pam_arvados.go index ddca355b87..ee967af6cc 100644 --- a/lib/pam/pam_arvados.go +++ b/lib/pam/pam_arvados.go @@ -2,11 +2,29 @@ // // SPDX-License-Identifier: Apache-2.0 +// To enable, add an entry in /etc/pam.d/common-auth where pam_unix.so +// would normally be. Examples: +// +// auth [success=1 default=ignore] /usr/lib/pam_arvados.so zzzzz.arvadosapi.com vmhostname.example +// auth [success=1 default=ignore] /usr/lib/pam_arvados.so zzzzz.arvadosapi.com vmhostname.example insecure debug +// +// Replace zzzzz.arvadosapi.com with your controller host or +// host:port. +// +// Replace vmhostname.example with the VM's name as it appears in the +// Arvados virtual_machine object. +// +// Use "insecure" if your API server certificate does not pass name +// verification. +// +// Use "debug" to enable debug log messages. + package main import ( "io/ioutil" "log/syslog" + "os" "context" "errors" @@ -38,6 +56,11 @@ func init() { } } +//export pam_sm_setcred +func pam_sm_setcred(pamh *C.pam_handle_t, flags, cArgc C.int, cArgv **C.char) C.int { + return C.PAM_IGNORE +} + //export pam_sm_authenticate func pam_sm_authenticate(pamh *C.pam_handle_t, flags, cArgc C.int, cArgv **C.char) C.int { runtime.GOMAXPROCS(1) @@ -65,7 +88,7 @@ func pam_sm_authenticate(pamh *C.pam_handle_t, flags, cArgc C.int, cArgv **C.cha return C.PAM_SUCCESS } -func authenticate(logger logrus.FieldLogger, username, token string, argv []string) error { +func authenticate(logger *logrus.Logger, username, token string, argv []string) error { hostname := "" apiHost := "" insecure := false @@ -76,12 +99,22 @@ func authenticate(logger logrus.FieldLogger, username, token string, argv []stri hostname = arg } else if arg == "insecure" { insecure = true + } else if arg == "debug" { + logger.SetLevel(logrus.DebugLevel) } else { - logger.Warnf("unkown option: %s\n", arg) + logger.Warnf("unknown option: %s\n", arg) } } + if hostname == "" || hostname == "-" { + h, err := os.Hostname() + if err != nil { + logger.WithError(err).Warnf("cannot get hostname -- try using an explicit hostname in pam config") + return fmt.Errorf("cannot get hostname: %w", err) + } + hostname = h + } logger.Debugf("username=%q arvados_api_host=%q hostname=%q insecure=%t", username, apiHost, hostname, insecure) - if apiHost == "" || hostname == "" { + if apiHost == "" { logger.Warnf("cannot authenticate: config error: arvados_api_host and hostname must be non-empty") return errors.New("config error") } @@ -104,7 +137,11 @@ func authenticate(logger logrus.FieldLogger, username, token string, argv []stri return err } if len(vms.Items) == 0 { - return fmt.Errorf("no results for hostname %q", hostname) + // It's possible there is no VM entry for the + // configured hostname, but typically this just means + // the user does not have permission to see (let alone + // log in to) this VM. + return errors.New("permission denied") } else if len(vms.Items) > 1 { return fmt.Errorf("multiple results for hostname %q", hostname) } else if vms.Items[0].Hostname != hostname { @@ -117,7 +154,7 @@ func authenticate(logger logrus.FieldLogger, username, token string, argv []stri } var links arvados.LinkList err = arv.RequestAndDecodeContext(ctx, &links, "GET", "arvados/v1/links", nil, arvados.ListOptions{ - Limit: 10000, + Limit: 1, Filters: []arvados.Filter{ {"link_class", "=", "permission"}, {"name", "=", "can_login"},