1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/authdata/greet_client/greet.c - Sample authorization data plugin */
3 /*
4 * Copyright 2009 by the Massachusetts Institute of Technology.
5 *
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
10 *
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
24 */
25
26 #include "k5-int.h"
27 #include <krb5/authdata_plugin.h>
28 #include <assert.h>
29
30 struct greet_context {
31 krb5_data greeting;
32 krb5_boolean verified;
33 };
34
35 static krb5_data greet_attr = {
36 KV5M_DATA, sizeof("urn:greet:greeting") - 1, "urn:greet:greeting" };
37
38 static krb5_error_code
greet_init(krb5_context kcontext,void ** plugin_context)39 greet_init(krb5_context kcontext, void **plugin_context)
40 {
41 *plugin_context = 0;
42 return 0;
43 }
44
45 static void
greet_flags(krb5_context kcontext,void * plugin_context,krb5_authdatatype ad_type,krb5_flags * flags)46 greet_flags(krb5_context kcontext,
47 void *plugin_context,
48 krb5_authdatatype ad_type,
49 krb5_flags *flags)
50 {
51 *flags = AD_USAGE_AP_REQ | AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL;
52 }
53
54 static void
greet_fini(krb5_context kcontext,void * plugin_context)55 greet_fini(krb5_context kcontext, void *plugin_context)
56 {
57 return;
58 }
59
60 static krb5_error_code
greet_request_init(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void ** request_context)61 greet_request_init(krb5_context kcontext,
62 krb5_authdata_context context,
63 void *plugin_context,
64 void **request_context)
65 {
66 struct greet_context *greet;
67
68 greet = malloc(sizeof(*greet));
69 if (greet == NULL)
70 return ENOMEM;
71
72 greet->greeting.data = NULL;
73 greet->greeting.length = 0;
74 greet->verified = FALSE;
75
76 *request_context = greet;
77
78 return 0;
79 }
80
81 static krb5_error_code
greet_export_authdata(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,krb5_flags usage,krb5_authdata *** out_authdata)82 greet_export_authdata(krb5_context kcontext,
83 krb5_authdata_context context,
84 void *plugin_context,
85 void *request_context,
86 krb5_flags usage,
87 krb5_authdata ***out_authdata)
88 {
89 struct greet_context *greet = (struct greet_context *)request_context;
90 krb5_authdata *data[2];
91 krb5_authdata datum;
92 krb5_error_code code;
93
94 datum.ad_type = -42;
95 datum.length = greet->greeting.length;
96 datum.contents = (krb5_octet *)greet->greeting.data;
97
98 data[0] = &datum;
99 data[1] = NULL;
100
101 code = krb5_copy_authdata(kcontext, data, out_authdata);
102
103 return code;
104 }
105
106 static krb5_error_code
greet_import_authdata(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,krb5_authdata ** authdata,krb5_boolean kdc_issued_flag,krb5_const_principal issuer)107 greet_import_authdata(krb5_context kcontext,
108 krb5_authdata_context context,
109 void *plugin_context,
110 void *request_context,
111 krb5_authdata **authdata,
112 krb5_boolean kdc_issued_flag,
113 krb5_const_principal issuer)
114 {
115 krb5_error_code code;
116 struct greet_context *greet = (struct greet_context *)request_context;
117 krb5_data data;
118
119 krb5_free_data_contents(kcontext, &greet->greeting);
120 greet->verified = FALSE;
121
122 assert(authdata[0] != NULL);
123
124 data.length = authdata[0]->length;
125 data.data = (char *)authdata[0]->contents;
126
127 code = krb5int_copy_data_contents_add0(kcontext, &data, &greet->greeting);
128 if (code == 0)
129 greet->verified = kdc_issued_flag;
130
131 return code;
132 }
133
134 static void
greet_request_fini(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context)135 greet_request_fini(krb5_context kcontext,
136 krb5_authdata_context context,
137 void *plugin_context,
138 void *request_context)
139 {
140 struct greet_context *greet = (struct greet_context *)request_context;
141
142 if (greet != NULL) {
143 krb5_free_data_contents(kcontext, &greet->greeting);
144 free(greet);
145 }
146 }
147
148 static krb5_error_code
greet_get_attribute_types(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,krb5_data ** out_attrs)149 greet_get_attribute_types(krb5_context kcontext,
150 krb5_authdata_context context,
151 void *plugin_context,
152 void *request_context,
153 krb5_data **out_attrs)
154 {
155 krb5_error_code code;
156 struct greet_context *greet = (struct greet_context *)request_context;
157
158 if (greet->greeting.length == 0)
159 return ENOENT;
160
161 *out_attrs = calloc(2, sizeof(krb5_data));
162 if (*out_attrs == NULL)
163 return ENOMEM;
164
165 code = krb5int_copy_data_contents_add0(kcontext,
166 &greet_attr,
167 &(*out_attrs)[0]);
168 if (code != 0) {
169 free(*out_attrs);
170 *out_attrs = NULL;
171 return code;
172 }
173
174 return 0;
175 }
176
177 static krb5_error_code
greet_get_attribute(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,const krb5_data * attribute,krb5_boolean * authenticated,krb5_boolean * complete,krb5_data * value,krb5_data * display_value,int * more)178 greet_get_attribute(krb5_context kcontext,
179 krb5_authdata_context context,
180 void *plugin_context,
181 void *request_context,
182 const krb5_data *attribute,
183 krb5_boolean *authenticated,
184 krb5_boolean *complete,
185 krb5_data *value,
186 krb5_data *display_value,
187 int *more)
188 {
189 struct greet_context *greet = (struct greet_context *)request_context;
190 krb5_error_code code;
191
192 if (!data_eq(*attribute, greet_attr) || greet->greeting.length == 0)
193 return ENOENT;
194
195 *authenticated = greet->verified;
196 *complete = TRUE;
197 *more = 0;
198
199 code = krb5int_copy_data_contents_add0(kcontext, &greet->greeting, value);
200 if (code == 0) {
201 code = krb5int_copy_data_contents_add0(kcontext,
202 &greet->greeting,
203 display_value);
204 if (code != 0)
205 krb5_free_data_contents(kcontext, value);
206 }
207
208 return code;
209 }
210
211 static krb5_error_code
greet_set_attribute(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,krb5_boolean complete,const krb5_data * attribute,const krb5_data * value)212 greet_set_attribute(krb5_context kcontext,
213 krb5_authdata_context context,
214 void *plugin_context,
215 void *request_context,
216 krb5_boolean complete,
217 const krb5_data *attribute,
218 const krb5_data *value)
219 {
220 struct greet_context *greet = (struct greet_context *)request_context;
221 krb5_data data;
222 krb5_error_code code;
223
224 if (!data_eq(*attribute, greet_attr))
225 return ENOENT;
226
227 if (greet->greeting.data != NULL)
228 return EEXIST;
229
230 code = krb5int_copy_data_contents_add0(kcontext, value, &data);
231 if (code != 0)
232 return code;
233
234 krb5_free_data_contents(kcontext, &greet->greeting);
235 greet->greeting = data;
236 greet->verified = FALSE;
237
238 return 0;
239 }
240
241 static krb5_error_code
greet_delete_attribute(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,const krb5_data * attribute)242 greet_delete_attribute(krb5_context kcontext,
243 krb5_authdata_context context,
244 void *plugin_context,
245 void *request_context,
246 const krb5_data *attribute)
247 {
248 struct greet_context *greet = (struct greet_context *)request_context;
249
250 krb5_free_data_contents(kcontext, &greet->greeting);
251 greet->verified = FALSE;
252
253 return 0;
254 }
255
256 static krb5_error_code
greet_size(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,size_t * sizep)257 greet_size(krb5_context kcontext,
258 krb5_authdata_context context,
259 void *plugin_context,
260 void *request_context,
261 size_t *sizep)
262 {
263 struct greet_context *greet = (struct greet_context *)request_context;
264
265 *sizep += sizeof(krb5_int32) +
266 greet->greeting.length +
267 sizeof(krb5_int32);
268
269 return 0;
270 }
271
272 static krb5_error_code
greet_externalize(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,krb5_octet ** buffer,size_t * lenremain)273 greet_externalize(krb5_context kcontext,
274 krb5_authdata_context context,
275 void *plugin_context,
276 void *request_context,
277 krb5_octet **buffer,
278 size_t *lenremain)
279 {
280 size_t required = 0;
281 struct greet_context *greet = (struct greet_context *)request_context;
282
283 greet_size(kcontext, context, plugin_context,
284 request_context, &required);
285
286 if (*lenremain < required)
287 return ENOMEM;
288
289 /* Greeting Length | Greeting Contents | Verified */
290 krb5_ser_pack_int32(greet->greeting.length, buffer, lenremain);
291 krb5_ser_pack_bytes((krb5_octet *)greet->greeting.data,
292 (size_t)greet->greeting.length,
293 buffer, lenremain);
294 krb5_ser_pack_int32((krb5_int32)greet->verified, buffer, lenremain);
295
296 return 0;
297 }
298
299 static krb5_error_code
greet_internalize(krb5_context kcontext,krb5_authdata_context context,void * plugin_context,void * request_context,krb5_octet ** buffer,size_t * lenremain)300 greet_internalize(krb5_context kcontext,
301 krb5_authdata_context context,
302 void *plugin_context,
303 void *request_context,
304 krb5_octet **buffer,
305 size_t *lenremain)
306 {
307 struct greet_context *greet = (struct greet_context *)request_context;
308 krb5_error_code code;
309 krb5_int32 length;
310 krb5_octet *contents = NULL;
311 krb5_int32 verified;
312 krb5_octet *bp;
313 size_t remain;
314
315 bp = *buffer;
316 remain = *lenremain;
317
318 /* Greeting Length */
319 code = krb5_ser_unpack_int32(&length, &bp, &remain);
320 if (code != 0)
321 return code;
322
323 /* Greeting Contents */
324 if (length != 0) {
325 contents = malloc(length);
326 if (contents == NULL)
327 return ENOMEM;
328
329 code = krb5_ser_unpack_bytes(contents, (size_t)length, &bp, &remain);
330 if (code != 0) {
331 free(contents);
332 return code;
333 }
334 }
335
336 /* Verified */
337 code = krb5_ser_unpack_int32(&verified, &bp, &remain);
338 if (code != 0) {
339 free(contents);
340 return code;
341 }
342
343 krb5_free_data_contents(kcontext, &greet->greeting);
344 greet->greeting.length = length;
345 greet->greeting.data = (char *)contents;
346 greet->verified = (verified != 0);
347
348 *buffer = bp;
349 *lenremain = remain;
350
351 return 0;
352 }
353
354 static krb5_authdatatype greet_ad_types[] = { -42, 0 };
355
356 krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
357 "greet",
358 greet_ad_types,
359 greet_init,
360 greet_fini,
361 greet_flags,
362 greet_request_init,
363 greet_request_fini,
364 greet_get_attribute_types,
365 greet_get_attribute,
366 greet_set_attribute,
367 greet_delete_attribute,
368 greet_export_authdata,
369 greet_import_authdata,
370 NULL,
371 NULL,
372 NULL,
373 greet_size,
374 greet_externalize,
375 greet_internalize,
376 NULL
377 };
378