/*
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2014 Red Hat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <nss.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <krb5/localauth_plugin.h>
enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result,
char *buffer, size_t buflen, int *errnop);
#define DEFAULT_BUFSIZE 4096
static krb5_error_code sss_userok(krb5_context context,
krb5_localauth_moddata data,
krb5_const_principal aname,
const char *lname)
{
krb5_error_code kerr;
char *princ_str;
struct passwd pwd = { 0 };
char *buffer = NULL;
size_t buflen;
enum nss_status nss_status;
int nss_errno;
uid_t princ_uid;
int ret;
kerr = krb5_unparse_name(context, aname, &princ_str);
if (kerr != 0) {
ret = kerr;
goto done;
}
if (strcasecmp(princ_str, lname) == 0) {
ret = 0;
goto done;
}
buflen = DEFAULT_BUFSIZE;
buffer = malloc(buflen);
if (buffer == NULL) {
ret = ENOMEM;
goto done;
}
nss_status = _nss_sss_getpwnam_r(princ_str, &pwd, buffer, buflen,
&nss_errno);
if (nss_status != NSS_STATUS_SUCCESS) {
if (nss_status == NSS_STATUS_NOTFOUND) {
ret = KRB5_PLUGIN_NO_HANDLE;
} else {
ret = EIO;
}
goto done;
}
princ_uid = pwd.pw_uid;
nss_status = _nss_sss_getpwnam_r(lname, &pwd, buffer, buflen, &nss_errno);
if (nss_status != NSS_STATUS_SUCCESS) {
if (nss_status == NSS_STATUS_NOTFOUND) {
ret = KRB5_PLUGIN_NO_HANDLE;
} else {
ret = EIO;
}
goto done;
}
if (princ_uid != pwd.pw_uid) {
ret = EPERM;
goto done;
}
ret = 0;
done:
krb5_free_unparsed_name(context, princ_str);
free(buffer);
if (ret != 0) {
return KRB5_PLUGIN_NO_HANDLE;
}
return ret;
}
static krb5_error_code sss_an2ln(krb5_context context,
krb5_localauth_moddata data,
const char *type, const char *residual,
krb5_const_principal aname, char **lname_out)
{
krb5_error_code kerr;
char *princ_str;
struct passwd pwd = { 0 };
char *buffer = NULL;
size_t buflen;
enum nss_status nss_status;
int nss_errno;
int ret;
char *str;
kerr = krb5_unparse_name(context, aname, &princ_str);
if (kerr != 0) {
return kerr;
}
buflen = DEFAULT_BUFSIZE;
buffer = malloc(buflen);
if (buffer == NULL) {
ret = ENOMEM;
goto done;
}
nss_status = _nss_sss_getpwnam_r(princ_str, &pwd, buffer, buflen,
&nss_errno);
if (nss_status != NSS_STATUS_SUCCESS) {
if (nss_status == NSS_STATUS_NOTFOUND) {
ret = KRB5_PLUGIN_NO_HANDLE;
} else {
ret = EIO;
}
goto done;
}
if (pwd.pw_name == NULL) {
ret = EINVAL;
goto done;
}
str = strdup(pwd.pw_name);
if (str == NULL) {
ret = ENOMEM;
goto done;
}
*lname_out = str;
ret = 0;
done:
krb5_free_unparsed_name(context, princ_str);
free(buffer);
return ret;
}
static void sss_freestr(krb5_context context,
krb5_localauth_moddata data, char *str)
{
free(str);
}
krb5_error_code
localauth_sssd_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable)
{
if (maj_ver != 1 || min_ver != 1) {
return KRB5_PLUGIN_VER_NOTSUPP;
}
krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
vt->init = NULL;
vt->fini = NULL;
vt->name = "sssd";
vt->an2ln = sss_an2ln;
vt->userok = sss_userok;
vt->free_string = sss_freestr;
return 0;
}