1/* 2 * Copyright (c) 2008 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "kadm5_locl.h" 37 38#define LARGETIME 0x1fffffff 39 40#define CHECK(x) \ 41 do { \ 42 int __r; \ 43 if ((__r = (x))) { \ 44 abort(); \ 45 } \ 46 } while(0) 47 48#define INSIST(x) CHECK(!(x)) 49 50 51krb5_error_code 52_kadm5_xdr_store_data_xdr(krb5_storage *sp, krb5_data data) 53{ 54 krb5_error_code ret; 55 ssize_t sret; 56 size_t res; 57 58 ret = krb5_store_data(sp, data); 59 if (ret) 60 return ret; 61 res = 4 - (data.length % 4); 62 if (res != 4) { 63 static const char zero[4] = { 0, 0, 0, 0 }; 64 65 sret = krb5_storage_write(sp, zero, res); 66 if(sret < 0 || (size_t)sret != res) 67 return (sret < 0)? errno : krb5_storage_get_eof_code(sp); 68 } 69 return 0; 70} 71 72krb5_error_code 73_kadm5_xdr_ret_data_xdr(krb5_storage *sp, krb5_data *data) 74{ 75 krb5_error_code ret; 76 ssize_t sret; 77 78 ret = krb5_ret_data(sp, data); 79 if (ret) 80 return ret; 81 82 if ((data->length % 4) != 0) { 83 char buf[4]; 84 size_t res; 85 86 res = 4 - (data->length % 4); 87 if (res != 4) { 88 sret = krb5_storage_read(sp, buf, res); 89 if(sret < 0 || (size_t)sret != res) 90 return (sret < 0)? errno : krb5_storage_get_eof_code(sp); 91 } 92 } 93 return 0; 94} 95 96krb5_error_code 97_kadm5_xdr_ret_auth_opaque(krb5_storage *msg, struct _kadm5_xdr_opaque_auth *ao) 98{ 99 krb5_error_code ret; 100 ret = krb5_ret_uint32(msg, &ao->flavor); 101 if (ret) return ret; 102 ret = _kadm5_xdr_ret_data_xdr(msg, &ao->data); 103 return ret; 104} 105 106krb5_error_code 107_kadm5_xdr_store_auth_opaque(krb5_storage *msg, struct _kadm5_xdr_opaque_auth *ao) 108{ 109 krb5_error_code ret; 110 ret = krb5_store_uint32(msg, ao->flavor); 111 if (ret) return ret; 112 ret = _kadm5_xdr_store_data_xdr(msg, ao->data); 113 return ret; 114} 115 116krb5_error_code 117_kadm5_xdr_ret_gcred(krb5_data *data, struct _kadm5_xdr_gcred *gcred) 118{ 119 krb5_storage *sp; 120 121 memset(gcred, 0, sizeof(*gcred)); 122 123 sp = krb5_storage_from_data(data); 124 INSIST(sp != NULL); 125 126 CHECK(krb5_ret_uint32(sp, &gcred->version)); 127 CHECK(krb5_ret_uint32(sp, &gcred->proc)); 128 CHECK(krb5_ret_uint32(sp, &gcred->seq_num)); 129 CHECK(krb5_ret_uint32(sp, &gcred->service)); 130 CHECK(_kadm5_xdr_ret_data_xdr(sp, &gcred->handle)); 131 132 krb5_storage_free(sp); 133 134 return 0; 135} 136 137krb5_error_code 138_kadm5_xdr_store_gcred(struct _kadm5_xdr_gcred *gcred, krb5_data *data) 139{ 140 krb5_error_code ret; 141 krb5_storage *sp; 142 143 krb5_data_zero(data); 144 145 sp = krb5_storage_emem(); 146 INSIST(sp != NULL); 147 148 CHECK(krb5_store_uint32(sp, gcred->version)); 149 CHECK(krb5_store_uint32(sp, gcred->proc)); 150 CHECK(krb5_store_uint32(sp, gcred->seq_num)); 151 CHECK(krb5_store_uint32(sp, gcred->service)); 152 CHECK(_kadm5_xdr_store_data_xdr(sp, gcred->handle)); 153 154 ret = krb5_storage_to_data(sp, data); 155 krb5_storage_free(sp); 156 157 return ret; 158} 159 160 161krb5_error_code 162_kadm5_xdr_store_gss_init_res(krb5_storage *sp, krb5_data handle, 163 OM_uint32 maj_stat, OM_uint32 min_stat, 164 uint32_t seq_window, gss_buffer_t gout) 165{ 166 krb5_error_code ret; 167 krb5_data out; 168 169 out.data = gout->value; 170 out.length = gout->length; 171 172 ret = _kadm5_xdr_store_data_xdr(sp, handle); 173 if (ret) return ret; 174 ret = krb5_store_uint32(sp, maj_stat); 175 if (ret) return ret; 176 ret = krb5_store_uint32(sp, min_stat); 177 if (ret) return ret; 178 ret = krb5_store_uint32(sp, seq_window); 179 if (ret) return ret; 180 ret = _kadm5_xdr_store_data_xdr(sp, out); 181 return ret; 182} 183 184krb5_error_code 185_kadm5_xdr_ret_gss_init_res(krb5_storage *sp, krb5_data *handle, 186 OM_uint32 *maj_stat, OM_uint32 *min_stat, 187 uint32_t *seq_window, krb5_data *out) 188{ 189 krb5_error_code ret; 190 191 ret = _kadm5_xdr_ret_data_xdr(sp, handle); 192 if (ret) return ret; 193 ret = krb5_ret_uint32(sp, maj_stat); 194 if (ret) return ret; 195 ret = krb5_ret_uint32(sp, min_stat); 196 if (ret) return ret; 197 ret = krb5_ret_uint32(sp, seq_window); 198 if (ret) return ret; 199 ret = _kadm5_xdr_ret_data_xdr(sp, out); 200 return ret; 201} 202 203 204krb5_error_code 205_kadm5_xdr_ret_gacred(krb5_data *data, struct _kadm5_xdr_gacred *gacred) 206{ 207 krb5_storage *sp; 208 209 memset(gacred, 0, sizeof(*gacred)); 210 211 sp = krb5_storage_from_data(data); 212 INSIST(sp != NULL); 213 214 CHECK(krb5_ret_uint32(sp, &gacred->version)); 215 CHECK(krb5_ret_uint32(sp, &gacred->auth_msg)); 216 CHECK(_kadm5_xdr_ret_data_xdr(sp, &gacred->handle)); 217 218 krb5_storage_free(sp); 219 220 return 0; 221} 222 223 224krb5_error_code 225_kadm5_xdr_store_string_xdr(krb5_storage *sp, const char *str) 226{ 227 krb5_data c; 228 if (str) { 229 c.data = rk_UNCONST(str); 230 c.length = strlen(str) + 1; 231 } else 232 krb5_data_zero(&c); 233 234 return _kadm5_xdr_store_data_xdr(sp, c); 235} 236 237krb5_error_code 238_kadm5_xdr_ret_string_xdr(krb5_storage *sp, char **str) 239{ 240 krb5_data c; 241 *str = NULL; 242 CHECK(_kadm5_xdr_ret_data_xdr(sp, &c)); 243 if (c.length) { 244 *str = malloc(c.length + 1); 245 INSIST(*str != NULL); 246 memcpy(*str, c.data, c.length); 247 (*str)[c.length] = '\0'; 248 } 249 krb5_data_free(&c); 250 return 0; 251} 252 253krb5_error_code 254_kadm5_xdr_store_principal_xdr(krb5_context context, 255 krb5_storage *sp, 256 krb5_principal p) 257{ 258 char *str; 259 CHECK(krb5_unparse_name(context, p, &str)); 260 CHECK(_kadm5_xdr_store_string_xdr(sp, str)); 261 free(str); 262 return 0; 263} 264 265krb5_error_code 266_kadm5_xdr_ret_principal_xdr(krb5_context context, 267 krb5_storage *sp, 268 krb5_principal *p) 269{ 270 char *str; 271 *p = NULL; 272 CHECK(_kadm5_xdr_ret_string_xdr(sp, &str)); 273 if (str) { 274 CHECK(krb5_parse_name(context, str, p)); 275 free(str); 276 } 277 return 0; 278} 279 280krb5_error_code 281_kadm5_xdr_store_principal_ent(krb5_context context, 282 krb5_storage *sp, 283 kadm5_principal_ent_rec *ent) 284{ 285 int32_t t; 286 size_t i; 287 288 CHECK(_kadm5_xdr_store_principal_xdr(context, sp, ent->principal)); 289 CHECK(krb5_store_uint32(sp, (uint32_t)ent->princ_expire_time)); 290 CHECK(krb5_store_uint32(sp, (uint32_t)ent->pw_expiration)); 291 CHECK(krb5_store_uint32(sp, (uint32_t)ent->last_pwd_change)); 292 t = (int32_t)ent->max_life; 293 if (t == 0) 294 t = LARGETIME; 295 CHECK(krb5_store_uint32(sp, t)); 296 CHECK(krb5_store_int32(sp, ent->mod_name == NULL)); 297 if (ent->mod_name) 298 CHECK(_kadm5_xdr_store_principal_xdr(context, sp, ent->mod_name)); 299 CHECK(krb5_store_uint32(sp, (uint32_t)ent->mod_date)); 300 CHECK(krb5_store_uint32(sp, ent->attributes)); 301 CHECK(krb5_store_uint32(sp, ent->kvno)); 302 CHECK(krb5_store_uint32(sp, ent->mkvno)); 303 CHECK(_kadm5_xdr_store_string_xdr(sp, ent->policy)); 304 CHECK(krb5_store_int32(sp, ent->aux_attributes)); 305 t = (int32_t)ent->max_renewable_life; 306 if (t == 0) 307 t = LARGETIME; 308 CHECK(krb5_store_int32(sp, t)); 309 CHECK(krb5_store_int32(sp, (int32_t)ent->last_success)); 310 CHECK(krb5_store_int32(sp, (int32_t)ent->last_failed)); 311 CHECK(krb5_store_int32(sp, ent->fail_auth_count)); 312 CHECK(krb5_store_int32(sp, ent->n_key_data)); 313 CHECK(krb5_store_int32(sp, ent->n_tl_data)); 314 CHECK(krb5_store_int32(sp, ent->n_tl_data == 0)); 315 if (ent->n_tl_data) { 316 krb5_tl_data *tp; 317 318 for (tp = ent->tl_data; tp; tp = tp->tl_data_next) { 319 krb5_data c; 320 c.length = tp->tl_data_length; 321 c.data = tp->tl_data_contents; 322 323 CHECK(krb5_store_int32(sp, 0)); /* last item */ 324 CHECK(krb5_store_int32(sp, tp->tl_data_type)); 325 CHECK(_kadm5_xdr_store_data_xdr(sp, c)); 326 } 327 CHECK(krb5_store_int32(sp, 1)); /* last item */ 328 } 329 330 CHECK(krb5_store_int32(sp, ent->n_key_data)); 331 for (i = 0; i < (size_t)ent->n_key_data; i++) { 332 CHECK(krb5_store_uint32(sp, 2)); 333 CHECK(krb5_store_uint32(sp, ent->kvno)); 334 CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[0])); 335 CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[1])); 336 } 337 338 return 0; 339} 340 341krb5_error_code 342_kadm5_xdr_ret_principal_ent(krb5_context context, 343 krb5_storage *sp, 344 kadm5_principal_ent_rec *ent) 345{ 346 uint32_t flag, num, dataver; 347 size_t i; 348 349 memset(ent, 0, sizeof(*ent)); 350 351 CHECK(_kadm5_xdr_ret_principal_xdr(context, sp, &ent->principal)); 352 CHECK(krb5_ret_uint32(sp, &flag)); 353 ent->princ_expire_time = flag; 354 CHECK(krb5_ret_uint32(sp, &flag)); 355 ent->pw_expiration = flag; 356 CHECK(krb5_ret_uint32(sp, &flag)); 357 ent->last_pwd_change = flag; 358 CHECK(krb5_ret_uint32(sp, &flag)); 359 ent->max_life = flag; 360 if (ent->max_life >= LARGETIME) 361 ent->max_life = 0; 362 CHECK(krb5_ret_uint32(sp, &flag)); 363 if (flag == 0) { 364 CHECK(_kadm5_xdr_ret_principal_xdr(context, sp, &ent->mod_name)); 365 } 366 CHECK(krb5_ret_uint32(sp, &flag)); 367 ent->mod_date = flag; 368 CHECK(krb5_ret_uint32(sp, &flag)); 369 ent->attributes = flag; 370 CHECK(krb5_ret_uint32(sp, &flag)); 371 ent->kvno = flag; 372 CHECK(krb5_ret_uint32(sp, &flag)); 373 ent->mkvno = flag; 374 CHECK(_kadm5_xdr_ret_string_xdr(sp, &ent->policy)); 375 CHECK(krb5_ret_uint32(sp, &flag)); 376 ent->aux_attributes = flag; 377 CHECK(krb5_ret_uint32(sp, &flag)); 378 ent->max_renewable_life = flag; 379 if (ent->max_renewable_life >= LARGETIME) 380 ent->max_renewable_life = 0; 381 CHECK(krb5_ret_uint32(sp, &flag)); 382 ent->last_success = flag; 383 CHECK(krb5_ret_uint32(sp, &flag)); 384 ent->last_failed = flag; 385 CHECK(krb5_ret_uint32(sp, &flag)); 386 ent->fail_auth_count = flag; 387 CHECK(krb5_ret_uint32(sp, &flag)); 388 ent->n_key_data = flag; 389 CHECK(krb5_ret_uint32(sp, &flag)); 390 ent->n_tl_data = flag; 391 CHECK(krb5_ret_uint32(sp, &flag)); 392 if (flag == 0) { 393 krb5_tl_data **tp = &ent->tl_data; 394 size_t count = 0; 395 396 while(1) { 397 krb5_data c; 398 CHECK(krb5_ret_uint32(sp, &flag)); /* last item */ 399 if (flag) 400 break; 401 *tp = calloc(1, sizeof(**tp)); 402 INSIST(*tp != NULL); 403 CHECK(krb5_ret_uint32(sp, &flag)); 404 (*tp)->tl_data_type = flag; 405 CHECK(_kadm5_xdr_ret_data_xdr(sp, &c)); 406 (*tp)->tl_data_length = c.length; 407 (*tp)->tl_data_contents = c.data; 408 tp = &(*tp)->tl_data_next; 409 410 count++; 411 412 INSIST(count < 2000); 413 } 414 INSIST((size_t)ent->n_tl_data == count); 415 } else { 416 INSIST(ent->n_tl_data == 0); 417 } 418 419 CHECK(krb5_ret_uint32(sp, &num)); 420 INSIST(num == (uint32_t)ent->n_key_data); 421 422 ent->key_data = calloc(num, sizeof(ent->key_data[0])); 423 INSIST(ent->key_data != NULL); 424 425 for (i = 0; i < num; i++) { 426 CHECK(krb5_ret_uint32(sp, &dataver)); 427 CHECK(krb5_ret_uint32(sp, &flag)); 428 ent->kvno = flag; 429 430 CHECK(krb5_ret_uint32(sp, &flag)); 431 ent->key_data[i].key_data_type[0] = flag; 432 433 if (dataver > 1) { 434 CHECK(krb5_ret_uint32(sp, &flag)); 435 ent->key_data[i].key_data_type[1] = flag; 436 } 437 } 438 439 return 0; 440} 441