//
// 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"
}
}
+//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)
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
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")
}
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 {
}
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"},