mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
315ee3801b
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
285 lines
6.8 KiB
C
285 lines
6.8 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
A localauth plugin for MIT Kerberos
|
|
|
|
Copyright (C) 2018 Andreas Schneider <asn@samba.org>
|
|
|
|
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 "replace.h"
|
|
#include <krb5/localauth_plugin.h>
|
|
#include <wbclient.h>
|
|
#ifdef HAVE_COM_ERR_H
|
|
#include <com_err.h>
|
|
#endif
|
|
|
|
struct krb5_localauth_moddata_st {
|
|
struct wbcContext *wbc_ctx;
|
|
};
|
|
|
|
/*
|
|
* Initialize the module data.
|
|
*
|
|
* This creates the wbclient context.
|
|
*/
|
|
static krb5_error_code winbind_init(krb5_context context,
|
|
krb5_localauth_moddata *data)
|
|
{
|
|
krb5_localauth_moddata d;
|
|
|
|
*data = NULL;
|
|
d = malloc(sizeof(struct krb5_localauth_moddata_st));
|
|
if (d == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
d->wbc_ctx = wbcCtxCreate();
|
|
if (d->wbc_ctx == NULL) {
|
|
free(d);
|
|
return ENOMEM;
|
|
}
|
|
|
|
wbcSetClientProcessName("krb5_localauth_plugin");
|
|
|
|
*data = d;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Release resources used by module data.
|
|
*/
|
|
static void winbind_fini(krb5_context context, krb5_localauth_moddata data)
|
|
{
|
|
wbcCtxFree(data->wbc_ctx);
|
|
free(data);
|
|
data = NULL;
|
|
}
|
|
|
|
/*
|
|
* Determine whether aname is authorized to log in as the local account lname.
|
|
*
|
|
* Return 0 if aname is authorized, EPERM if aname is authoritatively not
|
|
* authorized, KRB5_PLUGIN_NO_HANDLE if the module cannot determine whether
|
|
* aname is authorized, and any other error code for a serious failure to
|
|
* process the request. aname will be considered authorized if at least one
|
|
* module returns 0 and all other modules return KRB5_PLUGIN_NO_HANDLE.
|
|
*/
|
|
static krb5_error_code winbind_userok(krb5_context context,
|
|
krb5_localauth_moddata data,
|
|
krb5_const_principal aname,
|
|
const char *lname)
|
|
{
|
|
krb5_error_code code = 0;
|
|
char *princ_str = NULL;
|
|
struct passwd *pwd = NULL;
|
|
uid_t princ_uid = (uid_t)-1;
|
|
uid_t lname_uid = (uid_t)-1;
|
|
wbcErr wbc_status;
|
|
int cmp;
|
|
|
|
code = krb5_unparse_name(context, aname, &princ_str);
|
|
if (code != 0) {
|
|
return code;
|
|
}
|
|
|
|
cmp = strcasecmp(princ_str, lname);
|
|
if (cmp == 0) {
|
|
goto out;
|
|
}
|
|
|
|
wbc_status = wbcCtxGetpwnam(data->wbc_ctx,
|
|
princ_str,
|
|
&pwd);
|
|
switch (wbc_status) {
|
|
case WBC_ERR_SUCCESS:
|
|
princ_uid = pwd->pw_uid;
|
|
code = 0;
|
|
break;
|
|
case WBC_ERR_UNKNOWN_USER:
|
|
/* match other insane libwbclient return codes */
|
|
case WBC_ERR_WINBIND_NOT_AVAILABLE:
|
|
case WBC_ERR_DOMAIN_NOT_FOUND:
|
|
case WBC_ERR_NOT_MAPPED:
|
|
code = KRB5_PLUGIN_NO_HANDLE;
|
|
break;
|
|
default:
|
|
code = EIO;
|
|
break;
|
|
}
|
|
wbcFreeMemory(pwd);
|
|
pwd = NULL;
|
|
if (code != 0) {
|
|
goto out;
|
|
}
|
|
|
|
wbc_status = wbcCtxGetpwnam(data->wbc_ctx,
|
|
lname,
|
|
&pwd);
|
|
switch (wbc_status) {
|
|
case WBC_ERR_SUCCESS:
|
|
lname_uid = pwd->pw_uid;
|
|
break;
|
|
case WBC_ERR_UNKNOWN_USER:
|
|
/* match other insane libwbclient return codes */
|
|
case WBC_ERR_WINBIND_NOT_AVAILABLE:
|
|
case WBC_ERR_DOMAIN_NOT_FOUND:
|
|
case WBC_ERR_NOT_MAPPED:
|
|
code = KRB5_PLUGIN_NO_HANDLE;
|
|
break;
|
|
default:
|
|
code = EIO;
|
|
break;
|
|
}
|
|
wbcFreeMemory(pwd);
|
|
if (code != 0) {
|
|
goto out;
|
|
}
|
|
|
|
if (princ_uid != lname_uid) {
|
|
code = EPERM;
|
|
}
|
|
|
|
com_err("winbind_localauth",
|
|
code,
|
|
"Access %s: %s (uid=%u) %sequal to %s (uid=%u)",
|
|
code == 0 ? "granted" : "denied",
|
|
princ_str,
|
|
(unsigned int)princ_uid,
|
|
code == 0 ? "" : "not ",
|
|
lname,
|
|
(unsigned int)lname_uid);
|
|
|
|
out:
|
|
krb5_free_unparsed_name(context, princ_str);
|
|
|
|
return code;
|
|
}
|
|
|
|
/*
|
|
* Determine the local account name corresponding to aname.
|
|
*
|
|
* Return 0 and set *lname_out if a mapping can be determined; the contents of
|
|
* *lname_out will later be released with a call to the module's free_string
|
|
* method. Return KRB5_LNAME_NOTRANS if no mapping can be determined. Return
|
|
* any other error code for a serious failure to process the request; this will
|
|
* halt the krb5_aname_to_localname operation.
|
|
*
|
|
* If the module's an2ln_types field is set, this method will only be invoked
|
|
* when a profile "auth_to_local" value references one of the module's types.
|
|
* type and residual will be set to the type and residual of the auth_to_local
|
|
* value.
|
|
*
|
|
* If the module's an2ln_types field is not set but the an2ln method is
|
|
* implemented, this method will be invoked independently of the profile's
|
|
* auth_to_local settings, with type and residual set to NULL. If multiple
|
|
* modules are registered with an2ln methods but no an2ln_types field, the
|
|
* order of invocation is not defined, but all such modules will be consulted
|
|
* before the built-in mechanisms are tried.
|
|
*/
|
|
static krb5_error_code winbind_an2ln(krb5_context context,
|
|
krb5_localauth_moddata data,
|
|
const char *type,
|
|
const char *residual,
|
|
krb5_const_principal aname,
|
|
char **lname_out)
|
|
{
|
|
krb5_error_code code = 0;
|
|
char *princ_str = NULL;
|
|
char *name = NULL;
|
|
struct passwd *pwd = NULL;
|
|
wbcErr wbc_status;
|
|
|
|
code = krb5_unparse_name(context, aname, &princ_str);
|
|
if (code != 0) {
|
|
return code;
|
|
}
|
|
|
|
wbc_status = wbcCtxGetpwnam(data->wbc_ctx,
|
|
princ_str,
|
|
&pwd);
|
|
krb5_free_unparsed_name(context, princ_str);
|
|
switch (wbc_status) {
|
|
case WBC_ERR_SUCCESS:
|
|
name = strdup(pwd->pw_name);
|
|
code = 0;
|
|
break;
|
|
case WBC_ERR_UNKNOWN_USER:
|
|
/* match other insane libwbclient return codes */
|
|
case WBC_ERR_WINBIND_NOT_AVAILABLE:
|
|
case WBC_ERR_DOMAIN_NOT_FOUND:
|
|
case WBC_ERR_NOT_MAPPED:
|
|
code = KRB5_LNAME_NOTRANS;
|
|
break;
|
|
default:
|
|
code = EIO;
|
|
break;
|
|
}
|
|
wbcFreeMemory(pwd);
|
|
if (code != 0) {
|
|
return code;
|
|
}
|
|
|
|
if (name == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
*lname_out = name;
|
|
|
|
return code;
|
|
}
|
|
|
|
/*
|
|
* Release the memory returned by an invocation of an2ln.
|
|
*/
|
|
static void winbind_free_string(krb5_context context,
|
|
krb5_localauth_moddata data,
|
|
char *str)
|
|
{
|
|
free(str);
|
|
}
|
|
|
|
_PUBLIC_ krb5_error_code
|
|
localauth_winbind_initvt(krb5_context context,
|
|
int maj_ver,
|
|
int min_ver,
|
|
krb5_plugin_vtable vtable);
|
|
|
|
_PUBLIC_ krb5_error_code
|
|
localauth_winbind_initvt(krb5_context context,
|
|
int maj_ver,
|
|
int min_ver,
|
|
krb5_plugin_vtable vtable)
|
|
{
|
|
krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
|
|
|
|
if (maj_ver != 1) {
|
|
com_err("winbind_localauth",
|
|
EINVAL,
|
|
"Failed to load, plugin API changed.");
|
|
return KRB5_PLUGIN_VER_NOTSUPP;
|
|
}
|
|
|
|
vt->init = winbind_init;
|
|
vt->fini = winbind_fini;
|
|
vt->name = "winbind";
|
|
vt->an2ln = winbind_an2ln;
|
|
vt->userok = winbind_userok;
|
|
vt->free_string = winbind_free_string;
|
|
|
|
return 0;
|
|
}
|