static void source_agent_env(enum agent id) { struct agent_data_t data; int ret = envoy_get_agent(id, &data, AGENT_ENVIRON); if (ret < 0) warn("failed to fetch envoy agent"); switch (data.status) { case ENVOY_STOPPED: case ENVOY_STARTED: case ENVOY_RUNNING: break; case ENVOY_FAILED: warnx("agent failed to start, check envoyd's log"); case ENVOY_BADUSER: warnx("connection rejected, user is unauthorized to use this agent"); } if (data.type == AGENT_GPG_AGENT) { _cleanup_gpg_ struct gpg_t *agent = gpg_agent_connection(data.gpg, NULL); gpg_update_tty(agent); } if (data.gpg[0]) { putenvf("GPG_AGENT_INFO=%s", data.gpg); } else { unsetenv("GPG_AGENT_INFO"); } putenvf("SSH_AUTH_SOCK=%s", data.sock); }
static int unlock(const struct agent_data_t *data, char *password) { if (data->type != AGENT_GPG_AGENT) errx(EXIT_FAILURE, "only gpg-agent supports this operation"); _cleanup_gpg_ struct gpg_t *agent = gpg_agent_connection(data->gpg, NULL); if (!agent) err(EXIT_FAILURE, "failed to connect to GPG_AUTH_SOCK"); if (!password) read_password(&password); const struct fingerprint_t *fgpt = gpg_keyinfo(agent); for (; fgpt; fgpt = fgpt->next) { if (fgpt->flags & KEY_DISABLED) continue; if (gpg_preset_passphrase(agent, fgpt->fingerprint, -1, password) < 0) { warnx("failed to unlock key '%s'", fgpt->fingerprint); return 1; } } return 0; }
/* PAM entry point for authentication verification */ PAM_EXTERN int pam_sm_authenticate(pam_handle_t _unused_ *ph, int _unused_ flags, int _unused_ argc, const char _unused_ **argv) { struct agent_data_t data; const struct passwd *pwd; const char *user, *password; enum agent id = AGENT_DEFAULT; int ret; ret = pam_get_user(ph, &user, NULL); if (ret != PAM_SUCCESS) { syslog(PAM_LOG_ERR, "pam-envoy: couldn't get the user name: %s", pam_strerror(ph, ret)); return PAM_SERVICE_ERR; } pwd = getpwnam(user); if (!pwd) { syslog(PAM_LOG_ERR, "pam-envoy: error looking up user information: %s", strerror(errno)); return PAM_SERVICE_ERR; } /* Look up the password */ ret = pam_get_item(ph, PAM_AUTHTOK, (const void**)&password); if (ret != PAM_SUCCESS || password == NULL) { if (ret == PAM_SUCCESS) syslog(PAM_LOG_WARN, "pam-envoy: no password is available for user"); else syslog(PAM_LOG_WARN, "pam-envoy: no password is available for user: %s", pam_strerror(ph, ret)); return PAM_SUCCESS; } if (pam_get_agent(&data, id, pwd->pw_uid, pwd->pw_gid) < 0) { syslog(PAM_LOG_WARN, "pam-envoy: failed to get agent for user"); return PAM_SUCCESS; } if (data.status == ENVOY_RUNNING && data.type == AGENT_GPG_AGENT) { _cleanup_gpg_ struct gpg_t *agent = gpg_agent_connection(data.gpg); if (password) { const struct fingerprint_t *fpt = gpg_keyinfo(agent); for (; fpt; fpt = fpt->next) { if (gpg_preset_passphrase(agent, fpt->fingerprint, -1, password) < 0) syslog(PAM_LOG_ERR, "failed to unlock '%s'", fpt->fingerprint); } } gpg_close(agent); } return PAM_SUCCESS; }
static void reload_agent(struct agent_data_t *data) { if (data->type != AGENT_GPG_AGENT) errx(EXIT_FAILURE, "only gpg-agent supports this operation"); _cleanup_gpg_ struct gpg_t *agent = gpg_agent_connection(data->gpg, NULL); if (!agent) err(EXIT_FAILURE, "failed to connect to GPG_AUTH_SOCK"); gpg_reload_agent(agent); }
static void source_env(struct agent_data_t *data) { if (data->type == AGENT_GPG_AGENT) { _cleanup_gpg_ struct gpg_t *agent = gpg_agent_connection(data->gpg); if (!agent) warn("failed to connect to GPG_AUTH_SOCK"); else gpg_update_tty(agent); } putenvf("SSH_AUTH_SOCK=%s", data->sock); }
/* PAM entry point for session creation */ PAM_EXTERN int pam_sm_open_session(pam_handle_t *ph, int _unused_ flags, int argc, const char **argv) { struct agent_data_t data; const struct passwd *pwd; const char *user; enum agent id = AGENT_DEFAULT; int ret; ret = pam_get_user(ph, &user, NULL); if (ret != PAM_SUCCESS) { syslog(PAM_LOG_ERR, "pam-envoy: couldn't get the user name: %s", pam_strerror(ph, ret)); return PAM_SERVICE_ERR; } pwd = getpwnam(user); if (!pwd) { syslog(PAM_LOG_ERR, "pam-envoy: error looking up user information: %s", strerror(errno)); return PAM_SERVICE_ERR; } if (argc > 1) { syslog(PAM_LOG_WARN, "pam-envoy: too many arguments"); return PAM_SUCCESS; } else if (argc == 1) { id = lookup_agent(argv[0]); } if (pam_get_agent(&data, id, pwd->pw_uid, pwd->pw_gid) < 0) { syslog(PAM_LOG_WARN, "pam-envoy: failed to get agent for user"); return PAM_SUCCESS; } if (data.type == AGENT_GPG_AGENT) { _cleanup_gpg_ struct gpg_t *agent = gpg_agent_connection(data.gpg); gpg_update_tty(agent); pam_setenv(ph, "GPG_AGENT_INFO=%s", data.gpg); } pam_setenv(ph, "SSH_AUTH_SOCK=%s", data.sock); pam_setenv(ph, "SSH_AGENT_PID=%d", data.pid); return PAM_SUCCESS; }