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 39 greet_init(krb5_context kcontext, void **plugin_context) 40 { 41 *plugin_context = 0; 42 return 0; 43 } 44 45 static void 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 55 greet_fini(krb5_context kcontext, void *plugin_context) 56 { 57 return; 58 } 59 60 static krb5_error_code 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 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 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 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 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 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 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 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 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 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 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