#include "k5-int.h"
#include "os-proto.h"
#include <krb5/localauth_plugin.h>
#if !defined(_WIN32)
#include <pwd.h>
#if defined(__APPLE__) && defined(__MACH__)
#include <hfs/hfs_mount.h>
#define FILE_OWNER_OK(UID) ((UID) == 0 || (UID) == UNKNOWNUID)
#else
#define FILE_OWNER_OK(UID) ((UID) == 0)
#endif
static krb5_error_code
get_k5login_filename(krb5_context context, const char *lname,
const char *homedir, char **filename_out)
{
krb5_error_code ret;
char *dir, *filename;
*filename_out = NULL;
ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
KRB5_CONF_K5LOGIN_DIRECTORY, NULL, NULL, &dir);
if (ret != 0)
return ret;
if (dir == NULL) {
if (asprintf(&filename, "%s/.k5login", homedir) < 0)
return ENOMEM;
} else {
if (asprintf(&filename, "%s/%s", dir, lname) < 0)
ret = ENOMEM;
profile_release_string(dir);
if (ret)
return ret;
}
*filename_out = filename;
return 0;
}
static krb5_error_code
userok_k5login(krb5_context context, krb5_localauth_moddata data,
krb5_const_principal aname, const char *lname)
{
krb5_error_code ret;
int authoritative = TRUE, gobble;
char *filename = NULL, *princname = NULL;
char *newline, linebuf[BUFSIZ], pwbuf[BUFSIZ];
struct stat sbuf;
struct passwd pwx, *pwd;
FILE *fp = NULL;
ret = profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS,
KRB5_CONF_K5LOGIN_AUTHORITATIVE, NULL, TRUE,
&authoritative);
if (ret)
goto cleanup;
ret = k5_getpwnam_r(lname, &pwx, pwbuf, sizeof(pwbuf), &pwd);
if (ret) {
ret = EPERM;
goto cleanup;
}
ret = get_k5login_filename(context, lname, pwd->pw_dir, &filename);
if (ret)
goto cleanup;
if (access(filename, F_OK) != 0) {
ret = KRB5_PLUGIN_NO_HANDLE;
goto cleanup;
}
ret = krb5_unparse_name(context, aname, &princname);
if (ret)
goto cleanup;
fp = fopen(filename, "r");
if (fp == NULL) {
ret = errno;
goto cleanup;
}
set_cloexec_file(fp);
if (fstat(fileno(fp), &sbuf)) {
ret = errno;
goto cleanup;
}
if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) {
ret = EPERM;
goto cleanup;
}
while (fgets(linebuf, sizeof(linebuf), fp) != NULL) {
newline = strrchr(linebuf, '\n');
if (newline != NULL)
*newline = '\0';
if (strcmp(linebuf, princname) == 0) {
ret = 0;
goto cleanup;
}
if (newline == NULL)
while ((gobble = getc(fp)) != EOF && gobble != '\n');
}
ret = EPERM;
cleanup:
free(princname);
free(filename);
if (fp != NULL)
fclose(fp);
return (!authoritative && ret) ? KRB5_PLUGIN_NO_HANDLE : ret;
}
#else
static krb5_error_code
userok_k5login(krb5_context context, krb5_localauth_moddata data,
krb5_const_principal aname, const char *lname)
{
return KRB5_PLUGIN_NO_HANDLE;
}
#endif
krb5_error_code
localauth_k5login_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable)
{
krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
vt->name = "k5login";
vt->userok = userok_k5login;
return 0;
}