cfg_t cfg_st;
cfg_t *cfg = &cfg_st;
char buffer[BUFSIZE];
int pgu_ret, gpn_ret;
int retval = PAM_ABORT;
device_t *devices = NULL;
unsigned n_devices = 0;
int openasuser = 0;
int should_free_origin = 0;
int should_free_appid = 0;
int should_free_auth_file = 0;
int should_free_authpending_file = 0;
parse_cfg(flags, argc, argv, cfg);
PAM_MODUTIL_DEF_PRIVS(privs);
if (!cfg->origin) {
if (!cfg->sshformat) {
strcpy(buffer, DEFAULT_ORIGIN_PREFIX);
if (gethostname(buffer + strlen(DEFAULT_ORIGIN_PREFIX),
BUFSIZE - strlen(DEFAULT_ORIGIN_PREFIX)) == -1) {
debug_dbg(cfg, "Unable to get host name");
retval = PAM_SYSTEM_ERR;
goto done;
}
} else {
strcpy(buffer, SSH_ORIGIN);
}
debug_dbg(cfg, "Origin not specified, using \"%s\"", buffer);
cfg->origin = strdup(buffer);
if (!cfg->origin) {
debug_dbg(cfg, "Unable to allocate memory");
retval = PAM_BUF_ERR;
goto done;
} else {
should_free_origin = 1;
}
}
if (!cfg->appid) {
debug_dbg(cfg, "Appid not specified, using the value of origin (%s)",
cfg->origin);
cfg->appid = strdup(cfg->origin);
if (!cfg->appid) {
debug_dbg(cfg, "Unable to allocate memory");
retval = PAM_BUF_ERR;
goto done;
} else {
should_free_appid = 1;
}
}
if (cfg->max_devs == 0) {
debug_dbg(cfg, "Maximum number of devices not set. Using default (%d)",
MAX_DEVS);
cfg->max_devs = MAX_DEVS;
}
#if WITH_FUZZING
if (cfg->max_devs > 256)
cfg->max_devs = 256;
#endif
devices = calloc(cfg->max_devs, sizeof(device_t));
if (!devices) {
debug_dbg(cfg, "Unable to allocate memory");
retval = PAM_BUF_ERR;
goto done;
}
pgu_ret = pam_get_user(pamh, &user, NULL);
if (pgu_ret != PAM_SUCCESS || user == NULL) {
debug_dbg(cfg, "Unable to get username from PAM");
retval = PAM_CONV_ERR;
goto done;
}
debug_dbg(cfg, "Requesting authentication for user %s", user);
if (!openasuser) {
openasuser = geteuid() == 0 && cfg->openasuser;
}
if (openasuser) {
debug_dbg(cfg, "Dropping privileges");
if (pam_modutil_drop_priv(pamh, &privs, pw)) {
debug_dbg(cfg, "Unable to switch user to uid %i", pw->pw_uid);
retval = PAM_SYSTEM_ERR;
goto done;
}
debug_dbg(cfg, "Switched to uid %i", pw->pw_uid);
}
retval = get_devices_from_authfile(cfg, user, devices, &n_devices);
if (openasuser) {
if (pam_modutil_regain_priv(pamh, &privs)) {
debug_dbg(cfg, "could not restore privileges");
retval = PAM_SYSTEM_ERR;
goto done;
}
debug_dbg(cfg, "Restored privileges");
}
if (retval != PAM_SUCCESS) {
goto done;
}
// Determine the full path for authpending_file in order to emit touch request
// notifications
if (!cfg->authpending_file) {
int actual_size =
snprintf(buffer, BUFSIZE, DEFAULT_AUTHPENDING_FILE_PATH, getuid());
if (actual_size >= 0 && actual_size < BUFSIZE) {
cfg->authpending_file = strdup(buffer);
}
if (!cfg->authpending_file) {
debug_dbg(cfg, "Unable to allocate memory for the authpending_file, "
"touch request notifications will not be emitted");
} else {
should_free_authpending_file = 1;
}
} else {
if (strlen(cfg->authpending_file) == 0) {
debug_dbg(cfg, "authpending_file is set to an empty value, touch request "
"notifications will be disabled");
cfg->authpending_file = NULL;
}
}
int authpending_file_descriptor = -1;
if (cfg->authpending_file) {
debug_dbg(cfg, "Touch request notifications will be emitted via '%s'",
cfg->authpending_file);
// Open (or create) the authpending_file to indicate that we start waiting
// for a touch
authpending_file_descriptor =
open(cfg->authpending_file,
O_RDONLY | O_CREAT | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY, 0664);
if (authpending_file_descriptor < 0) {
debug_dbg(cfg, "Unable to emit 'authentication started' notification: %s",
strerror(errno));
}
}
// Close the authpending_file to indicate that we stop waiting for a touch
if (authpending_file_descriptor >= 0) {
if (close(authpending_file_descriptor) < 0) {
debug_dbg(cfg, "Unable to emit 'authentication stopped' notification: %s",
strerror(errno));
}
}
done:
free_devices(devices, n_devices);
if (should_free_origin) {
free_const(cfg->origin);
cfg->origin = NULL;
}
if (should_free_appid) {
free_const(cfg->appid);
cfg->appid = NULL;
}
if (should_free_auth_file) {
free_const(cfg->auth_file);
cfg->auth_file = NULL;
}
if (should_free_authpending_file) {
free_const(cfg->authpending_file);
cfg->authpending_file = NULL;
}