smbdotconf: mark "ldap group suffix" with constant="1"
[Samba.git] / nsswitch / krb5_plugin / winbind_krb5_localauth.c
blob293f5297ca8c03025c7f72cdfd6e66f670d6d3cb
1 /*
2 Unix SMB/CIFS implementation.
4 A localauth plugin for MIT Kerberos
6 Copyright (C) 2018 Andreas Schneider <asn@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "replace.h"
23 #include <krb5/localauth_plugin.h>
24 #include <wbclient.h>
25 #ifdef HAVE_COM_ERR_H
26 #include <com_err.h>
27 #endif
29 struct krb5_localauth_moddata_st {
30 struct wbcContext *wbc_ctx;
34 * Initialize the module data.
36 * This creates the wbclient context.
38 static krb5_error_code winbind_init(krb5_context context,
39 krb5_localauth_moddata *data)
41 krb5_localauth_moddata d;
43 *data = NULL;
44 d = malloc(sizeof(struct krb5_localauth_moddata_st));
45 if (d == NULL) {
46 return ENOMEM;
49 d->wbc_ctx = wbcCtxCreate();
50 if (d->wbc_ctx == NULL) {
51 free(d);
52 return ENOMEM;
55 wbcSetClientProcessName("krb5_localauth_plugin");
57 *data = d;
59 return 0;
63 * Release resources used by module data.
65 static void winbind_fini(krb5_context context, krb5_localauth_moddata data)
67 wbcCtxFree(data->wbc_ctx);
68 free(data);
69 data = NULL;
73 * Determine whether aname is authorized to log in as the local account lname.
75 * Return 0 if aname is authorized, EPERM if aname is authoritatively not
76 * authorized, KRB5_PLUGIN_NO_HANDLE if the module cannot determine whether
77 * aname is authorized, and any other error code for a serious failure to
78 * process the request. aname will be considered authorized if at least one
79 * module returns 0 and all other modules return KRB5_PLUGIN_NO_HANDLE.
81 static krb5_error_code winbind_userok(krb5_context context,
82 krb5_localauth_moddata data,
83 krb5_const_principal aname,
84 const char *lname)
86 krb5_error_code code = 0;
87 char *princ_str = NULL;
88 struct passwd *pwd = NULL;
89 uid_t princ_uid = (uid_t)-1;
90 uid_t lname_uid = (uid_t)-1;
91 wbcErr wbc_status;
92 int cmp;
94 code = krb5_unparse_name(context, aname, &princ_str);
95 if (code != 0) {
96 return code;
99 cmp = strcasecmp(princ_str, lname);
100 if (cmp == 0) {
101 goto out;
104 wbc_status = wbcCtxGetpwnam(data->wbc_ctx,
105 princ_str,
106 &pwd);
107 switch (wbc_status) {
108 case WBC_ERR_SUCCESS:
109 princ_uid = pwd->pw_uid;
110 code = 0;
111 break;
112 case WBC_ERR_UNKNOWN_USER:
113 /* match other insane libwbclient return codes */
114 case WBC_ERR_WINBIND_NOT_AVAILABLE:
115 case WBC_ERR_DOMAIN_NOT_FOUND:
116 code = KRB5_PLUGIN_NO_HANDLE;
117 break;
118 default:
119 code = EIO;
120 break;
122 wbcFreeMemory(pwd);
123 if (code != 0) {
124 goto out;
127 wbc_status = wbcCtxGetpwnam(data->wbc_ctx,
128 lname,
129 &pwd);
130 switch (wbc_status) {
131 case WBC_ERR_SUCCESS:
132 lname_uid = pwd->pw_uid;
133 break;
134 case WBC_ERR_UNKNOWN_USER:
135 /* match other insane libwbclient return codes */
136 case WBC_ERR_WINBIND_NOT_AVAILABLE:
137 case WBC_ERR_DOMAIN_NOT_FOUND:
138 code = KRB5_PLUGIN_NO_HANDLE;
139 break;
140 default:
141 code = EIO;
142 break;
144 wbcFreeMemory(pwd);
145 if (code != 0) {
146 goto out;
149 if (princ_uid != lname_uid) {
150 code = EPERM;
153 com_err("winbind_localauth",
154 code,
155 "Access %s: %s (uid=%u) %sequal to %s (uid=%u)",
156 code == 0 ? "granted" : "denied",
157 princ_str,
158 (unsigned int)princ_uid,
159 code == 0 ? "" : "not ",
160 lname,
161 (unsigned int)lname_uid);
163 out:
164 krb5_free_unparsed_name(context, princ_str);
166 return code;
170 * Determine the local account name corresponding to aname.
172 * Return 0 and set *lname_out if a mapping can be determined; the contents of
173 * *lname_out will later be released with a call to the module's free_string
174 * method. Return KRB5_LNAME_NOTRANS if no mapping can be determined. Return
175 * any other error code for a serious failure to process the request; this will
176 * halt the krb5_aname_to_localname operation.
178 * If the module's an2ln_types field is set, this method will only be invoked
179 * when a profile "auth_to_local" value references one of the module's types.
180 * type and residual will be set to the type and residual of the auth_to_local
181 * value.
183 * If the module's an2ln_types field is not set but the an2ln method is
184 * implemented, this method will be invoked independently of the profile's
185 * auth_to_local settings, with type and residual set to NULL. If multiple
186 * modules are registered with an2ln methods but no an2ln_types field, the
187 * order of invocation is not defined, but all such modules will be consulted
188 * before the built-in mechanisms are tried.
190 static krb5_error_code winbind_an2ln(krb5_context context,
191 krb5_localauth_moddata data,
192 const char *type,
193 const char *residual,
194 krb5_const_principal aname,
195 char **lname_out)
197 krb5_error_code code = 0;
198 char *princ_str = NULL;
199 char *name = NULL;
200 struct passwd *pwd = NULL;
201 wbcErr wbc_status;
203 code = krb5_unparse_name(context, aname, &princ_str);
204 if (code != 0) {
205 return code;
208 wbc_status = wbcCtxGetpwnam(data->wbc_ctx,
209 princ_str,
210 &pwd);
211 krb5_free_unparsed_name(context, princ_str);
212 switch (wbc_status) {
213 case WBC_ERR_SUCCESS:
214 name = strdup(pwd->pw_name);
215 code = 0;
216 break;
217 case WBC_ERR_UNKNOWN_USER:
218 /* match other insane libwbclient return codes */
219 case WBC_ERR_WINBIND_NOT_AVAILABLE:
220 case WBC_ERR_DOMAIN_NOT_FOUND:
221 code = KRB5_LNAME_NOTRANS;
222 break;
223 default:
224 code = EIO;
225 break;
227 wbcFreeMemory(pwd);
228 if (code != 0) {
229 return code;
232 if (name == NULL) {
233 return ENOMEM;
236 *lname_out = name;
238 return code;
242 * Release the memory returned by an invocation of an2ln.
244 static void winbind_free_string(krb5_context context,
245 krb5_localauth_moddata data,
246 char *str)
248 free(str);
251 krb5_error_code
252 localauth_winbind_initvt(krb5_context context,
253 int maj_ver,
254 int min_ver,
255 krb5_plugin_vtable vtable);
257 krb5_error_code
258 localauth_winbind_initvt(krb5_context context,
259 int maj_ver,
260 int min_ver,
261 krb5_plugin_vtable vtable)
263 krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
265 if (maj_ver != 1) {
266 com_err("winbind_localauth",
267 EINVAL,
268 "Failed to load, plugin API changed.");
269 return KRB5_PLUGIN_VER_NOTSUPP;
272 vt->init = winbind_init;
273 vt->fini = winbind_fini;
274 vt->name = "winbind";
275 vt->an2ln = winbind_an2ln;
276 vt->userok = winbind_userok;
277 vt->free_string = winbind_free_string;
279 return 0;