1226031Sstas/* 2226031Sstas * Copyright (c) 2008 Kungliga Tekniska H��gskolan 3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4226031Sstas * All rights reserved. 5226031Sstas * 6226031Sstas * Redistribution and use in source and binary forms, with or without 7226031Sstas * modification, are permitted provided that the following conditions 8226031Sstas * are met: 9226031Sstas * 10226031Sstas * 1. Redistributions of source code must retain the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer. 12226031Sstas * 13226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 14226031Sstas * notice, this list of conditions and the following disclaimer in the 15226031Sstas * documentation and/or other materials provided with the distribution. 16226031Sstas * 17226031Sstas * 3. Neither the name of the Institute nor the names of its contributors 18226031Sstas * may be used to endorse or promote products derived from this software 19226031Sstas * without specific prior written permission. 20226031Sstas * 21226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31226031Sstas * SUCH DAMAGE. 32226031Sstas */ 33226031Sstas 34226031Sstas#include "kadmin_locl.h" 35226031Sstas 36233294Sstas#include <gssapi/gssapi.h> 37233294Sstas//#include <gssapi_krb5.h> 38233294Sstas//#include <gssapi_spnego.h> 39226031Sstas 40233294Sstasstatic gss_OID_desc krb5_mechanism = 41233294Sstas{9, (void *)(uintptr_t) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 42233294Sstas#define GSS_KRB5_MECHANISM (&krb5_mechanism) 43233294Sstas 44226031Sstas#define CHECK(x) \ 45226031Sstas do { \ 46226031Sstas int __r; \ 47226031Sstas if ((__r = (x))) { \ 48226031Sstas krb5_errx(dcontext, 1, "Failed (%d) on %s:%d", \ 49226031Sstas __r, __FILE__, __LINE__); \ 50226031Sstas } \ 51226031Sstas } while(0) 52226031Sstas 53226031Sstasstatic krb5_context dcontext; 54226031Sstas 55226031Sstas#define INSIST(x) CHECK(!(x)) 56226031Sstas 57226031Sstas#define VERSION2 0x12345702 58226031Sstas 59226031Sstas#define LAST_FRAGMENT 0x80000000 60226031Sstas 61226031Sstas#define RPC_VERSION 2 62226031Sstas#define KADM_SERVER 2112 63226031Sstas#define VVERSION 2 64226031Sstas#define FLAVOR_GSS 6 65226031Sstas#define FLAVOR_GSS_VERSION 1 66226031Sstas 67226031Sstasstruct opaque_auth { 68226031Sstas uint32_t flavor; 69226031Sstas krb5_data data; 70226031Sstas}; 71226031Sstas 72226031Sstasstruct call_header { 73226031Sstas uint32_t xid; 74226031Sstas uint32_t rpcvers; 75226031Sstas uint32_t prog; 76226031Sstas uint32_t vers; 77226031Sstas uint32_t proc; 78226031Sstas struct opaque_auth cred; 79226031Sstas struct opaque_auth verf; 80226031Sstas}; 81226031Sstas 82226031Sstasenum { 83226031Sstas RPG_DATA = 0, 84226031Sstas RPG_INIT = 1, 85226031Sstas RPG_CONTINUE_INIT = 2, 86226031Sstas RPG_DESTROY = 3 87226031Sstas}; 88226031Sstas 89226031Sstasenum { 90226031Sstas rpg_privacy = 3 91226031Sstas}; 92226031Sstas 93226031Sstas/* 94226031Sstasstruct chrand_ret { 95226031Sstas krb5_ui_4 api_version; 96226031Sstas kadm5_ret_t ret; 97226031Sstas int n_keys; 98226031Sstas krb5_keyblock *keys; 99226031Sstas}; 100226031Sstas*/ 101226031Sstas 102226031Sstas 103226031Sstasstruct gcred { 104226031Sstas uint32_t version; 105226031Sstas uint32_t proc; 106226031Sstas uint32_t seq_num; 107226031Sstas uint32_t service; 108226031Sstas krb5_data handle; 109226031Sstas}; 110226031Sstas 111226031Sstasstatic int 112226031Sstasparse_name(const unsigned char *p, size_t len, 113226031Sstas const gss_OID oid, char **name) 114226031Sstas{ 115226031Sstas size_t l; 116226031Sstas 117226031Sstas if (len < 4) 118226031Sstas return 1; 119226031Sstas 120226031Sstas /* TOK_ID */ 121226031Sstas if (memcmp(p, "\x04\x01", 2) != 0) 122226031Sstas return 1; 123226031Sstas len -= 2; 124226031Sstas p += 2; 125226031Sstas 126226031Sstas /* MECH_LEN */ 127226031Sstas l = (p[0] << 8) | p[1]; 128226031Sstas len -= 2; 129226031Sstas p += 2; 130226031Sstas if (l < 2 || len < l) 131226031Sstas return 1; 132226031Sstas 133226031Sstas /* oid wrapping */ 134226031Sstas if (p[0] != 6 || p[1] != l - 2) 135226031Sstas return 1; 136226031Sstas p += 2; 137226031Sstas l -= 2; 138226031Sstas len -= 2; 139226031Sstas 140226031Sstas /* MECH */ 141226031Sstas if (l != oid->length || memcmp(p, oid->elements, oid->length) != 0) 142226031Sstas return 1; 143226031Sstas len -= l; 144226031Sstas p += l; 145226031Sstas 146226031Sstas /* MECHNAME_LEN */ 147226031Sstas if (len < 4) 148226031Sstas return 1; 149226031Sstas l = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 150226031Sstas len -= 4; 151226031Sstas p += 4; 152226031Sstas 153226031Sstas /* MECH NAME */ 154226031Sstas if (len != l) 155226031Sstas return 1; 156226031Sstas 157226031Sstas *name = malloc(l + 1); 158226031Sstas INSIST(*name != NULL); 159226031Sstas memcpy(*name, p, l); 160226031Sstas (*name)[l] = '\0'; 161226031Sstas 162226031Sstas return 0; 163226031Sstas} 164226031Sstas 165226031Sstas 166226031Sstas 167226031Sstasstatic void 168226031Sstasgss_error(krb5_context contextp, 169226031Sstas gss_OID mech, OM_uint32 type, OM_uint32 error) 170226031Sstas{ 171226031Sstas OM_uint32 new_stat; 172226031Sstas OM_uint32 msg_ctx = 0; 173226031Sstas gss_buffer_desc status_string; 174226031Sstas OM_uint32 ret; 175226031Sstas 176226031Sstas do { 177226031Sstas ret = gss_display_status (&new_stat, 178226031Sstas error, 179226031Sstas type, 180226031Sstas mech, 181226031Sstas &msg_ctx, 182226031Sstas &status_string); 183226031Sstas krb5_warnx(contextp, "%.*s", 184226031Sstas (int)status_string.length, 185226031Sstas (char *)status_string.value); 186226031Sstas gss_release_buffer (&new_stat, &status_string); 187226031Sstas } while (!GSS_ERROR(ret) && msg_ctx != 0); 188226031Sstas} 189226031Sstas 190226031Sstasstatic void 191226031Sstasgss_print_errors (krb5_context contextp, 192226031Sstas OM_uint32 maj_stat, OM_uint32 min_stat) 193226031Sstas{ 194226031Sstas gss_error(contextp, GSS_C_NO_OID, GSS_C_GSS_CODE, maj_stat); 195226031Sstas gss_error(contextp, GSS_C_NO_OID, GSS_C_MECH_CODE, min_stat); 196226031Sstas} 197226031Sstas 198226031Sstasstatic int 199226031Sstasread_data(krb5_storage *sp, krb5_storage *msg, size_t len) 200226031Sstas{ 201226031Sstas char buf[1024]; 202226031Sstas 203226031Sstas while (len) { 204226031Sstas size_t tlen = len; 205226031Sstas ssize_t slen; 206226031Sstas 207226031Sstas if (tlen > sizeof(buf)) 208226031Sstas tlen = sizeof(buf); 209226031Sstas 210226031Sstas slen = krb5_storage_read(sp, buf, tlen); 211226031Sstas INSIST((size_t)slen == tlen); 212226031Sstas 213226031Sstas slen = krb5_storage_write(msg, buf, tlen); 214226031Sstas INSIST((size_t)slen == tlen); 215226031Sstas 216226031Sstas len -= tlen; 217226031Sstas } 218226031Sstas return 0; 219226031Sstas} 220226031Sstas 221226031Sstasstatic int 222226031Sstascollect_framents(krb5_storage *sp, krb5_storage *msg) 223226031Sstas{ 224226031Sstas krb5_error_code ret; 225226031Sstas uint32_t len; 226226031Sstas int last_fragment; 227226031Sstas size_t total_len = 0; 228226031Sstas 229226031Sstas do { 230226031Sstas ret = krb5_ret_uint32(sp, &len); 231226031Sstas if (ret) 232226031Sstas return ret; 233226031Sstas 234226031Sstas last_fragment = (len & LAST_FRAGMENT); 235226031Sstas len &= ~LAST_FRAGMENT; 236226031Sstas 237226031Sstas CHECK(read_data(sp, msg, len)); 238226031Sstas total_len += len; 239226031Sstas 240226031Sstas } while(!last_fragment || total_len == 0); 241226031Sstas 242226031Sstas return 0; 243226031Sstas} 244226031Sstas 245226031Sstasstatic krb5_error_code 246226031Sstasstore_data_xdr(krb5_storage *sp, krb5_data data) 247226031Sstas{ 248226031Sstas krb5_error_code ret; 249226031Sstas size_t res; 250226031Sstas 251226031Sstas ret = krb5_store_data(sp, data); 252226031Sstas if (ret) 253226031Sstas return ret; 254226031Sstas res = 4 - (data.length % 4); 255226031Sstas if (res != 4) { 256226031Sstas static const char zero[4] = { 0, 0, 0, 0 }; 257226031Sstas 258226031Sstas ret = krb5_storage_write(sp, zero, res); 259226031Sstas if((size_t)ret != res) 260226031Sstas return (ret < 0)? errno : krb5_storage_get_eof_code(sp); 261226031Sstas } 262226031Sstas return 0; 263226031Sstas} 264226031Sstas 265226031Sstasstatic krb5_error_code 266226031Sstasret_data_xdr(krb5_storage *sp, krb5_data *data) 267226031Sstas{ 268226031Sstas krb5_error_code ret; 269226031Sstas ret = krb5_ret_data(sp, data); 270226031Sstas if (ret) 271226031Sstas return ret; 272226031Sstas 273226031Sstas if ((data->length % 4) != 0) { 274226031Sstas char buf[4]; 275226031Sstas size_t res; 276226031Sstas 277226031Sstas res = 4 - (data->length % 4); 278226031Sstas if (res != 4) { 279226031Sstas ret = krb5_storage_read(sp, buf, res); 280226031Sstas if((size_t)ret != res) 281226031Sstas return (ret < 0)? errno : krb5_storage_get_eof_code(sp); 282226031Sstas } 283226031Sstas } 284226031Sstas return 0; 285226031Sstas} 286226031Sstas 287226031Sstasstatic krb5_error_code 288226031Sstasret_auth_opaque(krb5_storage *msg, struct opaque_auth *ao) 289226031Sstas{ 290226031Sstas krb5_error_code ret; 291226031Sstas ret = krb5_ret_uint32(msg, &ao->flavor); 292226031Sstas if (ret) return ret; 293226031Sstas ret = ret_data_xdr(msg, &ao->data); 294226031Sstas return ret; 295226031Sstas} 296226031Sstas 297226031Sstasstatic int 298226031Sstasret_gcred(krb5_data *data, struct gcred *gcred) 299226031Sstas{ 300226031Sstas krb5_storage *sp; 301226031Sstas 302226031Sstas memset(gcred, 0, sizeof(*gcred)); 303226031Sstas 304226031Sstas sp = krb5_storage_from_data(data); 305226031Sstas INSIST(sp != NULL); 306226031Sstas 307226031Sstas CHECK(krb5_ret_uint32(sp, &gcred->version)); 308226031Sstas CHECK(krb5_ret_uint32(sp, &gcred->proc)); 309226031Sstas CHECK(krb5_ret_uint32(sp, &gcred->seq_num)); 310226031Sstas CHECK(krb5_ret_uint32(sp, &gcred->service)); 311226031Sstas CHECK(ret_data_xdr(sp, &gcred->handle)); 312226031Sstas 313226031Sstas krb5_storage_free(sp); 314226031Sstas 315226031Sstas return 0; 316226031Sstas} 317226031Sstas 318226031Sstasstatic krb5_error_code 319226031Sstasstore_gss_init_res(krb5_storage *sp, krb5_data handle, 320226031Sstas OM_uint32 maj_stat, OM_uint32 min_stat, 321226031Sstas uint32_t seq_window, gss_buffer_t gout) 322226031Sstas{ 323226031Sstas krb5_error_code ret; 324226031Sstas krb5_data out; 325226031Sstas 326226031Sstas out.data = gout->value; 327226031Sstas out.length = gout->length; 328226031Sstas 329226031Sstas ret = store_data_xdr(sp, handle); 330226031Sstas if (ret) return ret; 331226031Sstas ret = krb5_store_uint32(sp, maj_stat); 332226031Sstas if (ret) return ret; 333226031Sstas ret = krb5_store_uint32(sp, min_stat); 334226031Sstas if (ret) return ret; 335226031Sstas ret = store_data_xdr(sp, out); 336226031Sstas return ret; 337226031Sstas} 338226031Sstas 339226031Sstasstatic int 340226031Sstasstore_string_xdr(krb5_storage *sp, const char *str) 341226031Sstas{ 342226031Sstas krb5_data c; 343226031Sstas if (str) { 344226031Sstas c.data = rk_UNCONST(str); 345226031Sstas c.length = strlen(str) + 1; 346226031Sstas } else 347226031Sstas krb5_data_zero(&c); 348226031Sstas 349226031Sstas return store_data_xdr(sp, c); 350226031Sstas} 351226031Sstas 352226031Sstasstatic int 353226031Sstasret_string_xdr(krb5_storage *sp, char **str) 354226031Sstas{ 355226031Sstas krb5_data c; 356226031Sstas *str = NULL; 357226031Sstas CHECK(ret_data_xdr(sp, &c)); 358226031Sstas if (c.length) { 359226031Sstas *str = malloc(c.length + 1); 360226031Sstas INSIST(*str != NULL); 361226031Sstas memcpy(*str, c.data, c.length); 362226031Sstas (*str)[c.length] = '\0'; 363226031Sstas } 364226031Sstas krb5_data_free(&c); 365226031Sstas return 0; 366226031Sstas} 367226031Sstas 368226031Sstasstatic int 369226031Sstasstore_principal_xdr(krb5_context contextp, 370226031Sstas krb5_storage *sp, 371226031Sstas krb5_principal p) 372226031Sstas{ 373226031Sstas char *str; 374226031Sstas CHECK(krb5_unparse_name(contextp, p, &str)); 375226031Sstas CHECK(store_string_xdr(sp, str)); 376226031Sstas free(str); 377226031Sstas return 0; 378226031Sstas} 379226031Sstas 380226031Sstasstatic int 381226031Sstasret_principal_xdr(krb5_context contextp, 382226031Sstas krb5_storage *sp, 383226031Sstas krb5_principal *p) 384226031Sstas{ 385226031Sstas char *str; 386226031Sstas *p = NULL; 387226031Sstas CHECK(ret_string_xdr(sp, &str)); 388226031Sstas if (str) { 389226031Sstas CHECK(krb5_parse_name(contextp, str, p)); 390226031Sstas free(str); 391226031Sstas } 392226031Sstas return 0; 393226031Sstas} 394226031Sstas 395226031Sstasstatic int 396226031Sstasstore_principal_ent(krb5_context contextp, 397226031Sstas krb5_storage *sp, 398226031Sstas kadm5_principal_ent_rec *ent) 399226031Sstas{ 400226031Sstas int i; 401226031Sstas 402226031Sstas CHECK(store_principal_xdr(contextp, sp, ent->principal)); 403226031Sstas CHECK(krb5_store_uint32(sp, ent->princ_expire_time)); 404226031Sstas CHECK(krb5_store_uint32(sp, ent->pw_expiration)); 405226031Sstas CHECK(krb5_store_uint32(sp, ent->last_pwd_change)); 406226031Sstas CHECK(krb5_store_uint32(sp, ent->max_life)); 407226031Sstas CHECK(krb5_store_int32(sp, ent->mod_name == NULL)); 408226031Sstas if (ent->mod_name) 409226031Sstas CHECK(store_principal_xdr(contextp, sp, ent->mod_name)); 410226031Sstas CHECK(krb5_store_uint32(sp, ent->mod_date)); 411226031Sstas CHECK(krb5_store_uint32(sp, ent->attributes)); 412226031Sstas CHECK(krb5_store_uint32(sp, ent->kvno)); 413226031Sstas CHECK(krb5_store_uint32(sp, ent->mkvno)); 414226031Sstas CHECK(store_string_xdr(sp, ent->policy)); 415226031Sstas CHECK(krb5_store_int32(sp, ent->aux_attributes)); 416226031Sstas CHECK(krb5_store_int32(sp, ent->max_renewable_life)); 417226031Sstas CHECK(krb5_store_int32(sp, ent->last_success)); 418226031Sstas CHECK(krb5_store_int32(sp, ent->last_failed)); 419226031Sstas CHECK(krb5_store_int32(sp, ent->fail_auth_count)); 420226031Sstas CHECK(krb5_store_int32(sp, ent->n_key_data)); 421226031Sstas CHECK(krb5_store_int32(sp, ent->n_tl_data)); 422226031Sstas CHECK(krb5_store_int32(sp, ent->n_tl_data == 0)); 423226031Sstas if (ent->n_tl_data) { 424226031Sstas krb5_tl_data *tp; 425226031Sstas 426226031Sstas for (tp = ent->tl_data; tp; tp = tp->tl_data_next) { 427226031Sstas krb5_data c; 428226031Sstas c.length = tp->tl_data_length; 429226031Sstas c.data = tp->tl_data_contents; 430226031Sstas 431226031Sstas CHECK(krb5_store_int32(sp, 0)); /* last item */ 432226031Sstas CHECK(krb5_store_int32(sp, tp->tl_data_type)); 433226031Sstas CHECK(store_data_xdr(sp, c)); 434226031Sstas } 435226031Sstas CHECK(krb5_store_int32(sp, 1)); /* last item */ 436226031Sstas } 437226031Sstas 438226031Sstas CHECK(krb5_store_int32(sp, ent->n_key_data)); 439226031Sstas for (i = 0; i < ent->n_key_data; i++) { 440226031Sstas CHECK(krb5_store_uint32(sp, 2)); 441226031Sstas CHECK(krb5_store_uint32(sp, ent->kvno)); 442226031Sstas CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[0])); 443226031Sstas CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[1])); 444226031Sstas } 445226031Sstas 446226031Sstas return 0; 447226031Sstas} 448226031Sstas 449226031Sstasstatic int 450226031Sstasret_principal_ent(krb5_context contextp, 451226031Sstas krb5_storage *sp, 452226031Sstas kadm5_principal_ent_rec *ent) 453226031Sstas{ 454226031Sstas uint32_t flag, num; 455226031Sstas size_t i; 456226031Sstas 457226031Sstas memset(ent, 0, sizeof(*ent)); 458226031Sstas 459226031Sstas CHECK(ret_principal_xdr(contextp, sp, &ent->principal)); 460226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 461226031Sstas ent->princ_expire_time = flag; 462226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 463226031Sstas ent->pw_expiration = flag; 464226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 465226031Sstas ent->last_pwd_change = flag; 466226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 467226031Sstas ent->max_life = flag; 468226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 469226031Sstas if (flag == 0) 470226031Sstas ret_principal_xdr(contextp, sp, &ent->mod_name); 471226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 472226031Sstas ent->mod_date = flag; 473226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 474226031Sstas ent->attributes = flag; 475226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 476226031Sstas ent->kvno = flag; 477226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 478226031Sstas ent->mkvno = flag; 479226031Sstas CHECK(ret_string_xdr(sp, &ent->policy)); 480226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 481226031Sstas ent->aux_attributes = flag; 482226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 483226031Sstas ent->max_renewable_life = flag; 484226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 485226031Sstas ent->last_success = flag; 486226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 487226031Sstas ent->last_failed = flag; 488226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 489226031Sstas ent->fail_auth_count = flag; 490226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 491226031Sstas ent->n_key_data = flag; 492226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 493226031Sstas ent->n_tl_data = flag; 494226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 495226031Sstas if (flag == 0) { 496226031Sstas krb5_tl_data **tp = &ent->tl_data; 497226031Sstas size_t count = 0; 498226031Sstas 499226031Sstas while(1) { 500226031Sstas krb5_data c; 501226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); /* last item */ 502226031Sstas if (flag) 503226031Sstas break; 504226031Sstas *tp = calloc(1, sizeof(**tp)); 505226031Sstas INSIST(*tp != NULL); 506226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 507226031Sstas (*tp)->tl_data_type = flag; 508226031Sstas CHECK(ret_data_xdr(sp, &c)); 509226031Sstas (*tp)->tl_data_length = c.length; 510226031Sstas (*tp)->tl_data_contents = c.data; 511226031Sstas tp = &(*tp)->tl_data_next; 512226031Sstas 513226031Sstas count++; 514226031Sstas } 515226031Sstas INSIST((size_t)ent->n_tl_data == count); 516226031Sstas } else { 517226031Sstas INSIST(ent->n_tl_data == 0); 518226031Sstas } 519226031Sstas 520226031Sstas CHECK(krb5_ret_uint32(sp, &num)); 521226031Sstas INSIST(num == (uint32_t)ent->n_key_data); 522226031Sstas 523226031Sstas ent->key_data = calloc(num, sizeof(ent->key_data[0])); 524226031Sstas INSIST(ent->key_data != NULL); 525226031Sstas 526226031Sstas for (i = 0; i < num; i++) { 527226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); /* data version */ 528226031Sstas INSIST(flag > 1); 529226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 530226031Sstas ent->kvno = flag; 531226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 532226031Sstas ent->key_data[i].key_data_type[0] = flag; 533226031Sstas CHECK(krb5_ret_uint32(sp, &flag)); 534226031Sstas ent->key_data[i].key_data_type[1] = flag; 535226031Sstas } 536226031Sstas 537226031Sstas return 0; 538226031Sstas} 539226031Sstas 540226031Sstas/* 541226031Sstas * 542226031Sstas */ 543226031Sstas 544226031Sstasstatic void 545226031Sstasproc_create_principal(kadm5_server_context *contextp, 546226031Sstas krb5_storage *in, 547226031Sstas krb5_storage *out) 548226031Sstas{ 549226031Sstas uint32_t version, mask; 550226031Sstas kadm5_principal_ent_rec ent; 551226031Sstas krb5_error_code ret; 552226031Sstas char *password; 553226031Sstas 554226031Sstas memset(&ent, 0, sizeof(ent)); 555226031Sstas 556226031Sstas CHECK(krb5_ret_uint32(in, &version)); 557226031Sstas INSIST(version == VERSION2); 558226031Sstas CHECK(ret_principal_ent(contextp->context, in, &ent)); 559226031Sstas CHECK(krb5_ret_uint32(in, &mask)); 560226031Sstas CHECK(ret_string_xdr(in, &password)); 561226031Sstas 562226031Sstas INSIST(ent.principal); 563226031Sstas 564226031Sstas 565226031Sstas ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ent.principal); 566226031Sstas if (ret) 567226031Sstas goto fail; 568226031Sstas 569226031Sstas ret = kadm5_create_principal(contextp, &ent, mask, password); 570226031Sstas 571226031Sstas fail: 572226031Sstas krb5_warn(contextp->context, ret, "create principal"); 573226031Sstas CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ 574226031Sstas CHECK(krb5_store_uint32(out, ret)); /* code */ 575226031Sstas 576226031Sstas free(password); 577226031Sstas kadm5_free_principal_ent(contextp, &ent); 578226031Sstas} 579226031Sstas 580226031Sstasstatic void 581226031Sstasproc_delete_principal(kadm5_server_context *contextp, 582226031Sstas krb5_storage *in, 583226031Sstas krb5_storage *out) 584226031Sstas{ 585226031Sstas uint32_t version; 586226031Sstas krb5_principal princ; 587226031Sstas krb5_error_code ret; 588226031Sstas 589226031Sstas CHECK(krb5_ret_uint32(in, &version)); 590226031Sstas INSIST(version == VERSION2); 591226031Sstas CHECK(ret_principal_xdr(contextp->context, in, &princ)); 592226031Sstas 593226031Sstas ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); 594226031Sstas if (ret) 595226031Sstas goto fail; 596226031Sstas 597226031Sstas ret = kadm5_delete_principal(contextp, princ); 598226031Sstas 599226031Sstas fail: 600226031Sstas krb5_warn(contextp->context, ret, "delete principal"); 601226031Sstas CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ 602226031Sstas CHECK(krb5_store_uint32(out, ret)); /* code */ 603226031Sstas 604226031Sstas krb5_free_principal(contextp->context, princ); 605226031Sstas} 606226031Sstas 607226031Sstasstatic void 608226031Sstasproc_get_principal(kadm5_server_context *contextp, 609226031Sstas krb5_storage *in, 610226031Sstas krb5_storage *out) 611226031Sstas{ 612226031Sstas uint32_t version, mask; 613226031Sstas krb5_principal princ; 614226031Sstas kadm5_principal_ent_rec ent; 615226031Sstas krb5_error_code ret; 616226031Sstas 617226031Sstas memset(&ent, 0, sizeof(ent)); 618226031Sstas 619226031Sstas CHECK(krb5_ret_uint32(in, &version)); 620226031Sstas INSIST(version == VERSION2); 621226031Sstas CHECK(ret_principal_xdr(contextp->context, in, &princ)); 622226031Sstas CHECK(krb5_ret_uint32(in, &mask)); 623226031Sstas 624226031Sstas ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ); 625226031Sstas if(ret) 626226031Sstas goto fail; 627226031Sstas 628226031Sstas ret = kadm5_get_principal(contextp, princ, &ent, mask); 629226031Sstas 630226031Sstas fail: 631226031Sstas krb5_warn(contextp->context, ret, "get principal principal"); 632226031Sstas 633226031Sstas CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ 634226031Sstas CHECK(krb5_store_uint32(out, ret)); /* code */ 635226031Sstas if (ret == 0) { 636226031Sstas CHECK(store_principal_ent(contextp->context, out, &ent)); 637226031Sstas } 638226031Sstas krb5_free_principal(contextp->context, princ); 639226031Sstas kadm5_free_principal_ent(contextp, &ent); 640226031Sstas} 641226031Sstas 642226031Sstasstatic void 643226031Sstasproc_chrand_principal_v2(kadm5_server_context *contextp, 644226031Sstas krb5_storage *in, 645226031Sstas krb5_storage *out) 646226031Sstas{ 647226031Sstas krb5_error_code ret; 648226031Sstas krb5_principal princ; 649226031Sstas uint32_t version; 650226031Sstas krb5_keyblock *new_keys; 651226031Sstas int n_keys; 652226031Sstas 653226031Sstas CHECK(krb5_ret_uint32(in, &version)); 654226031Sstas INSIST(version == VERSION2); 655226031Sstas CHECK(ret_principal_xdr(contextp->context, in, &princ)); 656226031Sstas 657226031Sstas ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); 658226031Sstas if(ret) 659226031Sstas goto fail; 660226031Sstas 661226031Sstas ret = kadm5_randkey_principal(contextp, princ, 662226031Sstas &new_keys, &n_keys); 663226031Sstas 664226031Sstas fail: 665226031Sstas krb5_warn(contextp->context, ret, "rand key principal"); 666226031Sstas 667226031Sstas CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ 668226031Sstas CHECK(krb5_store_uint32(out, ret)); 669226031Sstas if (ret == 0) { 670226031Sstas int i; 671226031Sstas CHECK(krb5_store_int32(out, n_keys)); 672226031Sstas 673226031Sstas for(i = 0; i < n_keys; i++){ 674226031Sstas CHECK(krb5_store_uint32(out, new_keys[i].keytype)); 675226031Sstas CHECK(store_data_xdr(out, new_keys[i].keyvalue)); 676226031Sstas krb5_free_keyblock_contents(contextp->context, &new_keys[i]); 677226031Sstas } 678226031Sstas free(new_keys); 679226031Sstas } 680226031Sstas krb5_free_principal(contextp->context, princ); 681226031Sstas} 682226031Sstas 683226031Sstasstatic void 684226031Sstasproc_init(kadm5_server_context *contextp, 685226031Sstas krb5_storage *in, 686226031Sstas krb5_storage *out) 687226031Sstas{ 688226031Sstas CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ 689226031Sstas CHECK(krb5_store_uint32(out, 0)); /* code */ 690226031Sstas CHECK(krb5_store_uint32(out, 0)); /* code */ 691226031Sstas} 692226031Sstas 693226031Sstasstruct krb5_proc { 694226031Sstas const char *name; 695226031Sstas void (*func)(kadm5_server_context *, krb5_storage *, krb5_storage *); 696226031Sstas} procs[] = { 697226031Sstas { "NULL", NULL }, 698226031Sstas { "create principal", proc_create_principal }, 699226031Sstas { "delete principal", proc_delete_principal }, 700226031Sstas { "modify principal", NULL }, 701226031Sstas { "rename principal", NULL }, 702226031Sstas { "get principal", proc_get_principal }, 703226031Sstas { "chpass principal", NULL }, 704226031Sstas { "chrand principal", proc_chrand_principal_v2 }, 705226031Sstas { "create policy", NULL }, 706226031Sstas { "delete policy", NULL }, 707226031Sstas { "modify policy", NULL }, 708226031Sstas { "get policy", NULL }, 709226031Sstas { "get privs", NULL }, 710226031Sstas { "init", proc_init }, 711226031Sstas { "get principals", NULL }, 712226031Sstas { "get polices", NULL }, 713226031Sstas { "setkey principal", NULL }, 714226031Sstas { "setkey principal v4", NULL }, 715226031Sstas { "create principal v3", NULL }, 716226031Sstas { "chpass principal v3", NULL }, 717226031Sstas { "chrand principal v3", NULL }, 718226031Sstas { "setkey principal v3", NULL } 719226031Sstas}; 720226031Sstas 721226031Sstasstatic krb5_error_code 722226031Sstascopyheader(krb5_storage *sp, krb5_data *data) 723226031Sstas{ 724226031Sstas off_t off; 725226031Sstas ssize_t sret; 726226031Sstas 727226031Sstas off = krb5_storage_seek(sp, 0, SEEK_CUR); 728226031Sstas 729226031Sstas CHECK(krb5_data_alloc(data, off)); 730226031Sstas INSIST((size_t)off == data->length); 731226031Sstas krb5_storage_seek(sp, 0, SEEK_SET); 732226031Sstas sret = krb5_storage_read(sp, data->data, data->length); 733226031Sstas INSIST(sret == off); 734226031Sstas INSIST(off == krb5_storage_seek(sp, 0, SEEK_CUR)); 735226031Sstas 736226031Sstas return 0; 737226031Sstas} 738226031Sstas 739226031Sstasstruct gctx { 740226031Sstas krb5_data handle; 741226031Sstas gss_ctx_id_t ctx; 742226031Sstas uint32_t seq_num; 743226031Sstas int done; 744226031Sstas int inprogress; 745226031Sstas}; 746226031Sstas 747226031Sstasstatic int 748226031Sstasprocess_stream(krb5_context contextp, 749226031Sstas unsigned char *buf, size_t ilen, 750226031Sstas krb5_storage *sp) 751226031Sstas{ 752226031Sstas krb5_error_code ret; 753226031Sstas krb5_storage *msg, *reply, *dreply; 754226031Sstas OM_uint32 maj_stat, min_stat; 755226031Sstas gss_buffer_desc gin, gout; 756226031Sstas struct gctx gctx; 757226031Sstas void *server_handle = NULL; 758226031Sstas 759226031Sstas memset(&gctx, 0, sizeof(gctx)); 760226031Sstas 761226031Sstas msg = krb5_storage_emem(); 762226031Sstas reply = krb5_storage_emem(); 763226031Sstas dreply = krb5_storage_emem(); 764226031Sstas 765226031Sstas /* 766226031Sstas * First packet comes partly from the caller 767226031Sstas */ 768226031Sstas 769226031Sstas INSIST(ilen >= 4); 770226031Sstas 771226031Sstas while (1) { 772226031Sstas struct call_header chdr; 773226031Sstas struct gcred gcred; 774226031Sstas uint32_t mtype; 775226031Sstas krb5_data headercopy; 776226031Sstas 777226031Sstas krb5_storage_truncate(dreply, 0); 778226031Sstas krb5_storage_truncate(reply, 0); 779226031Sstas krb5_storage_truncate(msg, 0); 780226031Sstas 781226031Sstas krb5_data_zero(&headercopy); 782226031Sstas memset(&chdr, 0, sizeof(chdr)); 783226031Sstas memset(&gcred, 0, sizeof(gcred)); 784226031Sstas 785226031Sstas /* 786226031Sstas * This is very icky to handle the the auto-detection between 787226031Sstas * the Heimdal protocol and the MIT ONC-RPC based protocol. 788226031Sstas */ 789226031Sstas 790226031Sstas if (ilen) { 791226031Sstas int last_fragment; 792226031Sstas unsigned long len; 793226031Sstas ssize_t slen; 794226031Sstas unsigned char tmp[4]; 795226031Sstas 796226031Sstas if (ilen < 4) { 797226031Sstas memcpy(tmp, buf, ilen); 798226031Sstas slen = krb5_storage_read(sp, tmp + ilen, sizeof(tmp) - ilen); 799226031Sstas INSIST((size_t)slen == sizeof(tmp) - ilen); 800226031Sstas 801226031Sstas ilen = sizeof(tmp); 802226031Sstas buf = tmp; 803226031Sstas } 804226031Sstas INSIST(ilen >= 4); 805226031Sstas 806226031Sstas _krb5_get_int(buf, &len, 4); 807226031Sstas last_fragment = (len & LAST_FRAGMENT) != 0; 808226031Sstas len &= ~LAST_FRAGMENT; 809226031Sstas 810226031Sstas ilen -= 4; 811226031Sstas buf += 4; 812226031Sstas 813226031Sstas if (ilen) { 814226031Sstas if (len < ilen) { 815226031Sstas slen = krb5_storage_write(msg, buf, len); 816226031Sstas INSIST((size_t)slen == len); 817226031Sstas ilen -= len; 818226031Sstas len = 0; 819226031Sstas } else { 820226031Sstas slen = krb5_storage_write(msg, buf, ilen); 821226031Sstas INSIST((size_t)slen == ilen); 822226031Sstas len -= ilen; 823226031Sstas } 824226031Sstas } 825226031Sstas 826226031Sstas CHECK(read_data(sp, msg, len)); 827226031Sstas 828226031Sstas if (!last_fragment) { 829226031Sstas ret = collect_framents(sp, msg); 830226031Sstas if (ret == HEIM_ERR_EOF) 831226031Sstas krb5_errx(contextp, 0, "client disconnected"); 832226031Sstas INSIST(ret == 0); 833226031Sstas } 834226031Sstas } else { 835226031Sstas 836226031Sstas ret = collect_framents(sp, msg); 837226031Sstas if (ret == HEIM_ERR_EOF) 838226031Sstas krb5_errx(contextp, 0, "client disconnected"); 839226031Sstas INSIST(ret == 0); 840226031Sstas } 841226031Sstas krb5_storage_seek(msg, 0, SEEK_SET); 842226031Sstas 843226031Sstas CHECK(krb5_ret_uint32(msg, &chdr.xid)); 844226031Sstas CHECK(krb5_ret_uint32(msg, &mtype)); 845226031Sstas CHECK(krb5_ret_uint32(msg, &chdr.rpcvers)); 846226031Sstas CHECK(krb5_ret_uint32(msg, &chdr.prog)); 847226031Sstas CHECK(krb5_ret_uint32(msg, &chdr.vers)); 848226031Sstas CHECK(krb5_ret_uint32(msg, &chdr.proc)); 849226031Sstas CHECK(ret_auth_opaque(msg, &chdr.cred)); 850226031Sstas CHECK(copyheader(msg, &headercopy)); 851226031Sstas CHECK(ret_auth_opaque(msg, &chdr.verf)); 852226031Sstas 853226031Sstas INSIST(chdr.rpcvers == RPC_VERSION); 854226031Sstas INSIST(chdr.prog == KADM_SERVER); 855226031Sstas INSIST(chdr.vers == VVERSION); 856226031Sstas INSIST(chdr.cred.flavor == FLAVOR_GSS); 857226031Sstas 858226031Sstas CHECK(ret_gcred(&chdr.cred.data, &gcred)); 859226031Sstas 860226031Sstas INSIST(gcred.version == FLAVOR_GSS_VERSION); 861226031Sstas 862226031Sstas if (gctx.done) { 863226031Sstas INSIST(chdr.verf.flavor == FLAVOR_GSS); 864226031Sstas 865226031Sstas /* from first byte to last of credential */ 866226031Sstas gin.value = headercopy.data; 867226031Sstas gin.length = headercopy.length; 868226031Sstas gout.value = chdr.verf.data.data; 869226031Sstas gout.length = chdr.verf.data.length; 870226031Sstas 871226031Sstas maj_stat = gss_verify_mic(&min_stat, gctx.ctx, &gin, &gout, NULL); 872226031Sstas INSIST(maj_stat == GSS_S_COMPLETE); 873226031Sstas } 874226031Sstas 875226031Sstas switch(gcred.proc) { 876226031Sstas case RPG_DATA: { 877226031Sstas krb5_data data; 878226031Sstas int conf_state; 879226031Sstas uint32_t seq; 880226031Sstas krb5_storage *sp1; 881226031Sstas 882226031Sstas INSIST(gcred.service == rpg_privacy); 883226031Sstas 884226031Sstas INSIST(gctx.done); 885226031Sstas 886226031Sstas INSIST(krb5_data_cmp(&gcred.handle, &gctx.handle) == 0); 887226031Sstas 888226031Sstas CHECK(ret_data_xdr(msg, &data)); 889226031Sstas 890226031Sstas gin.value = data.data; 891226031Sstas gin.length = data.length; 892226031Sstas 893226031Sstas maj_stat = gss_unwrap(&min_stat, gctx.ctx, &gin, &gout, 894226031Sstas &conf_state, NULL); 895226031Sstas krb5_data_free(&data); 896226031Sstas INSIST(maj_stat == GSS_S_COMPLETE); 897226031Sstas INSIST(conf_state != 0); 898226031Sstas 899226031Sstas sp1 = krb5_storage_from_mem(gout.value, gout.length); 900226031Sstas INSIST(sp1 != NULL); 901226031Sstas 902226031Sstas CHECK(krb5_ret_uint32(sp1, &seq)); 903226031Sstas INSIST (seq == gcred.seq_num); 904226031Sstas 905226031Sstas /* 906226031Sstas * Check sequence number 907226031Sstas */ 908226031Sstas INSIST(seq > gctx.seq_num); 909226031Sstas gctx.seq_num = seq; 910226031Sstas 911226031Sstas /* 912226031Sstas * If contextp is setup, priv data have the seq_num stored 913226031Sstas * first in the block, so add it here before users data is 914226031Sstas * added. 915226031Sstas */ 916226031Sstas CHECK(krb5_store_uint32(dreply, gctx.seq_num)); 917226031Sstas 918226031Sstas if (chdr.proc >= sizeof(procs)/sizeof(procs[0])) { 919226031Sstas krb5_warnx(contextp, "proc number out of array"); 920226031Sstas } else if (procs[chdr.proc].func == NULL) { 921226031Sstas krb5_warnx(contextp, "proc '%s' never implemented", 922226031Sstas procs[chdr.proc].name); 923226031Sstas } else { 924226031Sstas krb5_warnx(contextp, "proc %s", procs[chdr.proc].name); 925226031Sstas INSIST(server_handle != NULL); 926226031Sstas (*procs[chdr.proc].func)(server_handle, sp, dreply); 927226031Sstas } 928226031Sstas krb5_storage_free(sp); 929226031Sstas gss_release_buffer(&min_stat, &gout); 930226031Sstas 931226031Sstas break; 932226031Sstas } 933226031Sstas case RPG_INIT: 934226031Sstas INSIST(gctx.inprogress == 0); 935226031Sstas INSIST(gctx.ctx == NULL); 936226031Sstas 937226031Sstas gctx.inprogress = 1; 938226031Sstas /* FALL THOUGH */ 939226031Sstas case RPG_CONTINUE_INIT: { 940226031Sstas gss_name_t src_name = GSS_C_NO_NAME; 941226031Sstas krb5_data in; 942226031Sstas 943226031Sstas INSIST(gctx.inprogress); 944226031Sstas 945226031Sstas CHECK(ret_data_xdr(msg, &in)); 946226031Sstas 947226031Sstas gin.value = in.data; 948226031Sstas gin.length = in.length; 949226031Sstas gout.value = NULL; 950226031Sstas gout.length = 0; 951226031Sstas 952226031Sstas maj_stat = gss_accept_sec_context(&min_stat, 953226031Sstas &gctx.ctx, 954226031Sstas GSS_C_NO_CREDENTIAL, 955226031Sstas &gin, 956226031Sstas GSS_C_NO_CHANNEL_BINDINGS, 957226031Sstas &src_name, 958226031Sstas NULL, 959226031Sstas &gout, 960226031Sstas NULL, 961226031Sstas NULL, 962226031Sstas NULL); 963226031Sstas if (GSS_ERROR(maj_stat)) { 964226031Sstas gss_print_errors(contextp, maj_stat, min_stat); 965226031Sstas krb5_errx(contextp, 1, "gss error, exit"); 966226031Sstas } 967226031Sstas if ((maj_stat & GSS_S_CONTINUE_NEEDED) == 0) { 968226031Sstas kadm5_config_params realm_params; 969226031Sstas gss_buffer_desc bufp; 970226031Sstas char *client; 971226031Sstas 972226031Sstas gctx.done = 1; 973226031Sstas 974226031Sstas memset(&realm_params, 0, sizeof(realm_params)); 975226031Sstas 976226031Sstas maj_stat = gss_export_name(&min_stat, src_name, &bufp); 977226031Sstas INSIST(maj_stat == GSS_S_COMPLETE); 978226031Sstas 979226031Sstas CHECK(parse_name(bufp.value, bufp.length, 980226031Sstas GSS_KRB5_MECHANISM, &client)); 981226031Sstas 982226031Sstas gss_release_buffer(&min_stat, &bufp); 983226031Sstas 984226031Sstas krb5_warnx(contextp, "%s connected", client); 985226031Sstas 986226031Sstas ret = kadm5_s_init_with_password_ctx(contextp, 987226031Sstas client, 988226031Sstas NULL, 989226031Sstas KADM5_ADMIN_SERVICE, 990226031Sstas &realm_params, 991226031Sstas 0, 0, 992226031Sstas &server_handle); 993226031Sstas INSIST(ret == 0); 994226031Sstas } 995226031Sstas 996226031Sstas INSIST(gctx.ctx != GSS_C_NO_CONTEXT); 997226031Sstas 998226031Sstas CHECK(krb5_store_uint32(dreply, 0)); 999226031Sstas CHECK(store_gss_init_res(dreply, gctx.handle, 1000226031Sstas maj_stat, min_stat, 1, &gout)); 1001226031Sstas if (gout.value) 1002226031Sstas gss_release_buffer(&min_stat, &gout); 1003226031Sstas if (src_name) 1004226031Sstas gss_release_name(&min_stat, &src_name); 1005226031Sstas 1006226031Sstas break; 1007226031Sstas } 1008226031Sstas case RPG_DESTROY: 1009226031Sstas krb5_errx(contextp, 1, "client destroyed gss contextp"); 1010226031Sstas default: 1011226031Sstas krb5_errx(contextp, 1, "client sent unknown gsscode %d", 1012226031Sstas (int)gcred.proc); 1013226031Sstas } 1014226031Sstas 1015226031Sstas krb5_data_free(&gcred.handle); 1016226031Sstas krb5_data_free(&chdr.cred.data); 1017226031Sstas krb5_data_free(&chdr.verf.data); 1018226031Sstas krb5_data_free(&headercopy); 1019226031Sstas 1020226031Sstas CHECK(krb5_store_uint32(reply, chdr.xid)); 1021226031Sstas CHECK(krb5_store_uint32(reply, 1)); /* REPLY */ 1022226031Sstas CHECK(krb5_store_uint32(reply, 0)); /* MSG_ACCEPTED */ 1023226031Sstas 1024226031Sstas if (!gctx.done) { 1025226031Sstas krb5_data data; 1026226031Sstas 1027226031Sstas CHECK(krb5_store_uint32(reply, 0)); /* flavor_none */ 1028226031Sstas CHECK(krb5_store_uint32(reply, 0)); /* length */ 1029226031Sstas 1030226031Sstas CHECK(krb5_store_uint32(reply, 0)); /* SUCCESS */ 1031226031Sstas 1032226031Sstas CHECK(krb5_storage_to_data(dreply, &data)); 1033226031Sstas INSIST((size_t)krb5_storage_write(reply, data.data, data.length) == data.length); 1034226031Sstas krb5_data_free(&data); 1035226031Sstas 1036226031Sstas } else { 1037226031Sstas uint32_t seqnum = htonl(gctx.seq_num); 1038226031Sstas krb5_data data; 1039226031Sstas 1040226031Sstas gin.value = &seqnum; 1041226031Sstas gin.length = sizeof(seqnum); 1042226031Sstas 1043226031Sstas maj_stat = gss_get_mic(&min_stat, gctx.ctx, 0, &gin, &gout); 1044226031Sstas INSIST(maj_stat == GSS_S_COMPLETE); 1045226031Sstas 1046226031Sstas data.data = gout.value; 1047226031Sstas data.length = gout.length; 1048226031Sstas 1049226031Sstas CHECK(krb5_store_uint32(reply, FLAVOR_GSS)); 1050226031Sstas CHECK(store_data_xdr(reply, data)); 1051226031Sstas gss_release_buffer(&min_stat, &gout); 1052226031Sstas 1053226031Sstas CHECK(krb5_store_uint32(reply, 0)); /* SUCCESS */ 1054226031Sstas 1055226031Sstas CHECK(krb5_storage_to_data(dreply, &data)); 1056226031Sstas 1057226031Sstas if (gctx.inprogress) { 1058226031Sstas ssize_t sret; 1059226031Sstas gctx.inprogress = 0; 1060226031Sstas sret = krb5_storage_write(reply, data.data, data.length); 1061226031Sstas INSIST((size_t)sret == data.length); 1062226031Sstas krb5_data_free(&data); 1063226031Sstas } else { 1064226031Sstas int conf_state; 1065226031Sstas 1066226031Sstas gin.value = data.data; 1067226031Sstas gin.length = data.length; 1068226031Sstas 1069226031Sstas maj_stat = gss_wrap(&min_stat, gctx.ctx, 1, 0, 1070226031Sstas &gin, &conf_state, &gout); 1071226031Sstas INSIST(maj_stat == GSS_S_COMPLETE); 1072226031Sstas INSIST(conf_state != 0); 1073226031Sstas krb5_data_free(&data); 1074226031Sstas 1075226031Sstas data.data = gout.value; 1076226031Sstas data.length = gout.length; 1077226031Sstas 1078226031Sstas store_data_xdr(reply, data); 1079226031Sstas gss_release_buffer(&min_stat, &gout); 1080226031Sstas } 1081226031Sstas } 1082226031Sstas 1083226031Sstas { 1084226031Sstas krb5_data data; 1085226031Sstas ssize_t sret; 1086226031Sstas CHECK(krb5_storage_to_data(reply, &data)); 1087226031Sstas CHECK(krb5_store_uint32(sp, data.length | LAST_FRAGMENT)); 1088226031Sstas sret = krb5_storage_write(sp, data.data, data.length); 1089226031Sstas INSIST((size_t)sret == data.length); 1090226031Sstas krb5_data_free(&data); 1091226031Sstas } 1092226031Sstas 1093226031Sstas } 1094226031Sstas} 1095226031Sstas 1096226031Sstas 1097226031Sstasint 1098226031Sstashandle_mit(krb5_context contextp, void *buf, size_t len, krb5_socket_t sock) 1099226031Sstas{ 1100226031Sstas krb5_storage *sp; 1101226031Sstas 1102226031Sstas dcontext = contextp; 1103226031Sstas 1104226031Sstas sp = krb5_storage_from_fd(sock); 1105226031Sstas INSIST(sp != NULL); 1106226031Sstas 1107226031Sstas process_stream(contextp, buf, len, sp); 1108226031Sstas 1109226031Sstas return 0; 1110226031Sstas} 1111