15370: Re-enable docker tests.
[arvados.git] / lib / pam / pam_arvados.go
index ddca355b87148307a1e5e58747786e9ac25c509d..ee967af6cc6f1f773d429b69a4999c051e22989e 100644 (file)
@@ -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"},