Line data Source code
1 : /*
2 : Authors:
3 : Sumit Bose <sbose@redhat.com>
4 :
5 : Copyright (C) 2011, 2012, 2013 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU Lesser General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : /* A short documentation about authdata plugins can be found in
22 : * http://http://k5wiki.kerberos.org/wiki/Projects/VerifyAuthData */
23 :
24 : #include <krb5/krb5.h>
25 : #include <errno.h>
26 :
27 : #include "krb5_authdata_int.h"
28 : #include "sss_cli.h"
29 :
30 :
31 : struct sssd_context {
32 : krb5_data data;
33 : };
34 :
35 : static krb5_error_code
36 0 : sssdpac_init(krb5_context kcontext, void **plugin_context)
37 : {
38 0 : *plugin_context = NULL;
39 0 : return 0;
40 : }
41 :
42 : static void
43 0 : sssdpac_flags(krb5_context kcontext,
44 : void *plugin_context,
45 : krb5_authdatatype ad_type,
46 : krb5_flags *flags)
47 : {
48 0 : *flags = AD_USAGE_KDC_ISSUED | AD_USAGE_TGS_REQ;
49 0 : }
50 :
51 : static void
52 0 : sssdpac_fini(krb5_context kcontext, void *plugin_context)
53 : {
54 0 : return;
55 : }
56 :
57 : static krb5_error_code
58 0 : sssdpac_request_init(krb5_context kcontext,
59 : krb5_authdata_context context,
60 : void *plugin_context,
61 : void **request_context)
62 : {
63 : struct sssd_context *sssdctx;
64 :
65 0 : sssdctx = (struct sssd_context *)calloc(1, sizeof(*sssdctx));
66 0 : if (sssdctx == NULL) {
67 0 : return ENOMEM;
68 : }
69 :
70 0 : *request_context = sssdctx;
71 :
72 0 : return 0;
73 : }
74 :
75 : static krb5_error_code
76 0 : sssdpac_import_authdata(krb5_context kcontext,
77 : krb5_authdata_context context,
78 : void *plugin_context,
79 : void *request_context,
80 : krb5_authdata **authdata,
81 : krb5_boolean kdc_issued,
82 : krb5_const_principal kdc_issuer)
83 : {
84 0 : char *data = NULL;
85 0 : struct sssd_context *sssdctx = (struct sssd_context *)request_context;
86 :
87 0 : if (authdata[0] == NULL) {
88 0 : return EINVAL;
89 : }
90 :
91 0 : if (authdata[0]->length > 0) {
92 0 : data = malloc(sizeof(char) * authdata[0]->length);
93 0 : if (data == NULL) {
94 0 : return ENOMEM;
95 : }
96 0 : memcpy(data, authdata[0]->contents, authdata[0]->length);
97 : }
98 :
99 0 : if (sssdctx->data.data != NULL) {
100 0 : krb5_free_data_contents(kcontext, &sssdctx->data);
101 : }
102 :
103 0 : sssdctx->data.length = authdata[0]->length;
104 0 : sssdctx->data.data = data;
105 0 : return 0;
106 : }
107 :
108 : static void
109 0 : sssdpac_request_fini(krb5_context kcontext,
110 : krb5_authdata_context context,
111 : void *plugin_context,
112 : void *request_context)
113 : {
114 0 : struct sssd_context *sssdctx = (struct sssd_context *)request_context;
115 :
116 0 : if (sssdctx != NULL) {
117 0 : if (sssdctx->data.data != NULL) {
118 0 : krb5_free_data_contents(kcontext, &sssdctx->data);
119 : }
120 :
121 0 : free(sssdctx);
122 : }
123 0 : }
124 :
125 0 : static krb5_error_code sssdpac_verify(krb5_context kcontext,
126 : krb5_authdata_context context,
127 : void *plugin_context,
128 : void *request_context,
129 : const krb5_auth_context *auth_context,
130 : const krb5_keyblock *key,
131 : const krb5_ap_req *req)
132 : {
133 : krb5_error_code kerr;
134 : int ret;
135 : krb5_pac pac;
136 0 : struct sssd_context *sssdctx = (struct sssd_context *)request_context;
137 : struct sss_cli_req_data sss_data;
138 : int errnop;
139 :
140 0 : if (sssdctx == NULL || sssdctx->data.data == NULL) {
141 0 : return EINVAL;
142 : }
143 :
144 0 : kerr = krb5_pac_parse(kcontext, sssdctx->data.data,
145 0 : sssdctx->data.length, &pac);
146 0 : if (kerr != 0) {
147 0 : return EINVAL;
148 : }
149 :
150 0 : kerr = krb5_pac_verify(kcontext, pac,
151 0 : req->ticket->enc_part2->times.authtime,
152 0 : req->ticket->enc_part2->client, key, NULL);
153 : /* deallocate pac */
154 0 : krb5_pac_free(kcontext, pac);
155 0 : pac = NULL;
156 0 : if (kerr != 0) {
157 : /* The krb5 documentation says:
158 : * A checksum mismatch can occur if the PAC was copied from a
159 : * cross-realm TGT by an ignorant KDC; also Apple Mac OS X Server
160 : * Open Directory (as of 10.6) generates PACs with no server checksum
161 : * at all. One should consider not failing the whole authentication
162 : * because of this reason, but, instead, treating the ticket as
163 : * if it did not contain a PAC or marking the PAC information as
164 : * non-verified.
165 : */
166 0 : return 0;
167 : }
168 :
169 0 : sss_data.len = sssdctx->data.length;
170 0 : sss_data.data = sssdctx->data.data;
171 :
172 0 : ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
173 : NULL, NULL, &errnop);
174 : if (ret != 0) {
175 : /* Ignore the error */
176 : }
177 :
178 0 : return 0;
179 : }
180 :
181 : static krb5_error_code
182 0 : sssdpac_size(krb5_context kcontext,
183 : krb5_authdata_context context,
184 : void *plugin_context,
185 : void *request_context,
186 : size_t *sizep)
187 : {
188 0 : struct sssd_context *sssdctx = (struct sssd_context *)request_context;
189 :
190 0 : *sizep += sizeof(krb5_int32);
191 :
192 0 : *sizep += sssdctx->data.length;
193 :
194 0 : *sizep += sizeof(krb5_int32);
195 :
196 0 : return 0;
197 : }
198 :
199 : static krb5_error_code
200 0 : sssdpac_externalize(krb5_context kcontext,
201 : krb5_authdata_context context,
202 : void *plugin_context,
203 : void *request_context,
204 : krb5_octet **buffer,
205 : size_t *lenremain)
206 : {
207 0 : krb5_error_code code = 0;
208 0 : struct sssd_context *sssdctx = (struct sssd_context *)request_context;
209 0 : size_t required = 0;
210 : krb5_octet *bp;
211 : size_t remain;
212 :
213 0 : bp = *buffer;
214 0 : remain = *lenremain;
215 :
216 0 : if (sssdctx->data.data != NULL) {
217 0 : sssdpac_size(kcontext, context, plugin_context,
218 : request_context, &required);
219 :
220 0 : if (required <= remain) {
221 0 : krb5_ser_pack_int32((krb5_int32)sssdctx->data.length,
222 : &bp, &remain);
223 0 : krb5_ser_pack_bytes((krb5_octet *)sssdctx->data.data,
224 0 : (size_t)sssdctx->data.length,
225 : &bp, &remain);
226 0 : krb5_ser_pack_int32(0,
227 : &bp, &remain);
228 : } else {
229 0 : code = ENOMEM;
230 : }
231 : } else {
232 0 : krb5_ser_pack_int32(0, &bp, &remain); /* length */
233 0 : krb5_ser_pack_int32(0, &bp, &remain); /* verified */
234 : }
235 :
236 0 : *buffer = bp;
237 0 : *lenremain = remain;
238 :
239 0 : return code;
240 : }
241 :
242 : static krb5_error_code
243 0 : sssdpac_internalize(krb5_context kcontext,
244 : krb5_authdata_context context,
245 : void *plugin_context,
246 : void *request_context,
247 : krb5_octet **buffer,
248 : size_t *lenremain)
249 : {
250 0 : struct sssd_context *sssdctx = (struct sssd_context *)request_context;
251 : krb5_error_code code;
252 : krb5_int32 ibuf;
253 : krb5_octet *bp;
254 : size_t remain;
255 : krb5_data data;
256 :
257 0 : bp = *buffer;
258 0 : remain = *lenremain;
259 :
260 : /* length */
261 0 : code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
262 0 : if (code != 0) {
263 0 : return code;
264 : }
265 :
266 0 : if (ibuf != 0) {
267 :
268 0 : data.length = ibuf;
269 0 : data.data = malloc(sizeof(char) * ibuf);
270 0 : if (data.data == NULL) {
271 0 : return ENOMEM;
272 : }
273 0 : memcpy(data.data, bp, ibuf);
274 :
275 0 : bp += ibuf;
276 0 : remain -= ibuf;
277 : } else {
278 0 : data.length = 0;
279 0 : data.data = NULL;
280 : }
281 :
282 : /* verified */
283 0 : code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
284 0 : if (code != 0) {
285 0 : free(data.data);
286 0 : return code;
287 : }
288 :
289 0 : if (sssdctx->data.data != NULL) {
290 0 : krb5_free_data_contents(kcontext, &sssdctx->data);
291 : }
292 :
293 0 : sssdctx->data.length = data.length;
294 0 : sssdctx->data.data = data.data;
295 :
296 0 : *buffer = bp;
297 0 : *lenremain = remain;
298 :
299 0 : return 0;
300 : }
301 :
302 : static krb5_authdatatype sssdpac_ad_types[] = { KRB5_AUTHDATA_WIN2K_PAC, 0 };
303 :
304 : krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
305 : ((void *)((uintptr_t)("sssd_sssdpac"))),
306 : sssdpac_ad_types,
307 : sssdpac_init,
308 : sssdpac_fini,
309 : sssdpac_flags,
310 : sssdpac_request_init,
311 : sssdpac_request_fini,
312 : NULL,
313 : NULL,
314 : NULL,
315 : NULL,
316 : NULL,
317 : sssdpac_import_authdata,
318 : NULL,
319 : NULL,
320 : sssdpac_verify,
321 : sssdpac_size,
322 : sssdpac_externalize,
323 : sssdpac_internalize,
324 : NULL
325 : };
|