void fixup_quad_cksum(void *start, size_t len, des_cblock *key, void *new_checksum, void *old_checksum, int little) { des_quad_cksum((des_cblock*)start, (des_cblock*)new_checksum, len, 2, key); if(HOST_BYTE_ORDER){ if(little){ memcpy(old_checksum, new_checksum, 16); }else{ u_int32_t *tmp = (u_int32_t*)new_checksum; memcpy(old_checksum, new_checksum, 16); swap_u_16(old_checksum); swap_u_long(tmp[0]); swap_u_long(tmp[1]); swap_u_long(tmp[2]); swap_u_long(tmp[3]); } }else{ if(little){ u_int32_t *tmp = (u_int32_t*)new_checksum; swap_u_long(tmp[0]); swap_u_long(tmp[1]); swap_u_long(tmp[2]); swap_u_long(tmp[3]); memcpy(old_checksum, new_checksum, 16); }else{ u_int32_t tmp[4]; tmp[0] = ((u_int32_t*)new_checksum)[3]; tmp[1] = ((u_int32_t*)new_checksum)[2]; tmp[2] = ((u_int32_t*)new_checksum)[1]; tmp[3] = ((u_int32_t*)new_checksum)[0]; memcpy(old_checksum, tmp, 16); } } }
void kerberos_v4(struct sockaddr_in *client, KTEXT pkt) { static KTEXT_ST rpkt_st; KTEXT rpkt = &rpkt_st; static KTEXT_ST ciph_st; KTEXT ciph = &ciph_st; static KTEXT_ST tk_st; KTEXT tk = &tk_st; static KTEXT_ST auth_st; KTEXT auth = &auth_st; AUTH_DAT ad_st; AUTH_DAT *ad = &ad_st; static struct in_addr client_host; static int msg_byte_order; static int swap_bytes; static u_char k_flags; /* char *p_name, *instance; */ int lifetime = 0; int i; C_Block key; Key_schedule key_s; char *ptr; krb5_keyblock k5key; krb5_kvno kvno; krb5_deltat sk5life, ck5life; KRB4_32 v4endtime, v4req_end; k5key.contents = NULL; /* in case we have to free it */ ciph->length = 0; client_host = client->sin_addr; /* eval macros and correct the byte order and alignment as needed */ req_version = pkt_version(pkt); /* 1 byte, version */ req_msg_type = pkt_msg_type(pkt); /* 1 byte, Kerberos msg type */ /* set these to point to something safe */ req_name_ptr = req_inst_ptr = req_realm_ptr = ""; /* check if disabled, but we tell client */ if (kdc_v4 == KDC_V4_DISABLE) { lt = klog(L_KRB_PERR, "KRB will not handle v4 request from %s", inet_ntoa(client_host)); /* send an error reply */ req_name_ptr = req_inst_ptr = req_realm_ptr = ""; kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt); return; } /* check packet version */ if (req_version != KRB_PROT_VERSION) { lt = klog(L_KRB_PERR, "KRB prot version mismatch: KRB =%d request = %d", KRB_PROT_VERSION, req_version, 0); /* send an error reply */ req_name_ptr = req_inst_ptr = req_realm_ptr = ""; kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt); return; } msg_byte_order = req_msg_type & 1; swap_bytes = 0; if (msg_byte_order != HOST_BYTE_ORDER) { swap_bytes++; } klog(L_KRB_PINFO, "Prot version: %d, Byte order: %d, Message type: %d", (int) req_version, msg_byte_order, req_msg_type); switch (req_msg_type & ~1) { case AUTH_MSG_KDC_REQUEST: { int req_life; /* Requested liftime */ unsigned int request_backdate = 0; /*How far to backdate in seconds.*/ char *service; /* Service name */ char *instance; /* Service instance */ #ifdef notdef int kerno; /* Kerberos error number */ #endif n_auth_req++; tk->length = 0; k_flags = 0; /* various kerberos flags */ /* set up and correct for byte order and alignment */ req_name_ptr = (char *) pkt_a_name(pkt); str_length_check(req_name_ptr, ANAME_SZ); req_inst_ptr = (char *) pkt_a_inst(pkt); str_length_check(req_inst_ptr, INST_SZ); req_realm_ptr = (char *) pkt_a_realm(pkt); str_length_check(req_realm_ptr, REALM_SZ); memcpy(&req_time_ws, pkt_time_ws(pkt), sizeof(req_time_ws)); /* time has to be diddled */ if (swap_bytes) { swap_u_long(req_time_ws); } ptr = (char *) pkt_time_ws(pkt) + 4; req_life = (*ptr++) & 0xff; service = ptr; str_length_check(service, SNAME_SZ); instance = ptr + strlen(service) + 1; str_length_check(instance, INST_SZ); rpkt = &rpkt_st; klog(L_INI_REQ, "Initial ticket request Host: %s User: \"%s\" \"%s\"", inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0); if ((i = check_princ(req_name_ptr, req_inst_ptr, 0, &a_name_data, &k5key, 0, &ck5life))) { kerb_err_reply(client, pkt, i, "check_princ failed"); a_name_data.key_low = a_name_data.key_high = 0; krb5_free_keyblock_contents(kdc_context, &k5key); return; } /* don't use k5key for client */ krb5_free_keyblock_contents(kdc_context, &k5key); tk->length = 0; /* init */ if (strcmp(service, "krbtgt")) klog(L_NTGT_INTK, "INITIAL request from %s.%s for %s.%s", req_name_ptr, req_inst_ptr, service, instance, 0); /* this does all the checking */ if ((i = check_princ(service, instance, lifetime, &s_name_data, &k5key, 1, &sk5life))) { kerb_err_reply(client, pkt, i, "check_princ failed"); a_name_data.key_high = a_name_data.key_low = 0; s_name_data.key_high = s_name_data.key_low = 0; krb5_free_keyblock_contents(kdc_context, &k5key); return; } /* Bound requested lifetime with service and user */ v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life); v4req_end = min(v4req_end, kerb_time.tv_sec + ck5life); v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life); lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end); v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime); /* * Adjust issue time backwards if necessary, due to * roundup in krb_time_to_life(). */ if (v4endtime > v4req_end) request_backdate = v4endtime - v4req_end; #ifdef NOENCRYPTION memset(session_key, 0, sizeof(C_Block)); #else /* random session key */ des_new_random_key(session_key); #endif /* unseal server's key from master key */ memcpy( key, &s_name_data.key_low, 4); memcpy( ((krb5_ui_4 *) key) + 1, &s_name_data.key_high, 4); s_name_data.key_low = s_name_data.key_high = 0; kdb_encrypt_key(key, key, master_key, master_key_schedule, DECRYPT); /* construct and seal the ticket */ /* We always issue des tickets; the 3des tickets are a broken hack*/ krb_create_ticket(tk, k_flags, a_name_data.name, a_name_data.instance, local_realm, client_host.s_addr, (char *) session_key, lifetime, kerb_time.tv_sec - request_backdate, s_name_data.name, s_name_data.instance, key); krb5_free_keyblock_contents(kdc_context, &k5key); memset(key, 0, sizeof(key)); memset(key_s, 0, sizeof(key_s)); /* * get the user's key, unseal it from the server's key, and * use it to seal the cipher */ /* a_name_data.key_low a_name_data.key_high */ memcpy( key, &a_name_data.key_low, 4); memcpy( ((krb5_ui_4 *) key) + 1, &a_name_data.key_high, 4); a_name_data.key_low= a_name_data.key_high = 0; /* unseal the a_name key from the master key */ kdb_encrypt_key(key, key, master_key, master_key_schedule, DECRYPT); create_ciph(ciph, session_key, s_name_data.name, s_name_data.instance, local_realm, lifetime, s_name_data.key_version, tk, kerb_time.tv_sec, key); /* clear session key */ memset(session_key, 0, sizeof(session_key)); memset(key, 0, sizeof(key)); /* always send a reply packet */ rpkt = create_auth_reply(req_name_ptr, req_inst_ptr, req_realm_ptr, req_time_ws, 0, a_name_data.exp_date, a_name_data.key_version, ciph); krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0, (struct sockaddr *) client, sizeof (struct sockaddr_in)); memset(&a_name_data, 0, sizeof(a_name_data)); memset(&s_name_data, 0, sizeof(s_name_data)); break; } case AUTH_MSG_APPL_REQUEST: { krb5_ui_4 time_ws; /* Workstation time */ int req_life; /* Requested liftime */ char *service; /* Service name */ char *instance; /* Service instance */ int kerno = 0; /* Kerberos error number */ unsigned int request_backdate = 0; /*How far to backdate in seconds.*/ char tktrlm[REALM_SZ]; n_appl_req++; tk->length = 0; k_flags = 0; /* various kerberos flags */ auth->mbz = 0; /* pkt->mbz already zeroed */ auth->length = 4 + strlen((char *)pkt->dat + 3); if (auth->length + 1 > MAX_KTXT_LEN) { lt = klog(L_KRB_PERR, "APPL request with realm length too long from %s", inet_ntoa(client_host)); kerb_err_reply(client, pkt, RD_AP_INCON, "realm length too long"); return; } auth->length += (int) *(pkt->dat + auth->length) + (int) *(pkt->dat + auth->length + 1) + 2; if (auth->length > MAX_KTXT_LEN) { lt = klog(L_KRB_PERR, "APPL request with funky tkt or req_id length from %s", inet_ntoa(client_host)); kerb_err_reply(client, pkt, RD_AP_INCON, "funky tkt or req_id length"); return; } memcpy(auth->dat, pkt->dat, auth->length); strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ); tktrlm[REALM_SZ-1] = '\0'; kvno = (krb5_kvno)auth->dat[2]; if ((!allow_v4_crossrealm)&&strcmp(tktrlm, local_realm) != 0) { lt = klog(L_ERR_UNK, "Cross realm ticket from %s denied by policy,", tktrlm); kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, lt); return; } if (set_tgtkey(tktrlm, kvno, 0)) { lt = klog(L_ERR_UNK, "FAILED set_tgtkey realm %s, kvno %d. Host: %s ", tktrlm, kvno, inet_ntoa(client_host)); /* no better error code */ kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, lt); return; } kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr, ad, 0); if (kerno) { if (set_tgtkey(tktrlm, kvno, 1)) { lt = klog(L_ERR_UNK, "FAILED 3des set_tgtkey realm %s, kvno %d. Host: %s ", tktrlm, kvno, inet_ntoa(client_host)); /* no better error code */ kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, lt); return; } kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr, ad, 0); } if (kerno) { klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s", inet_ntoa(client_host), krb_get_err_text(kerno)); req_name_ptr = req_inst_ptr = req_realm_ptr = ""; kerb_err_reply(client, pkt, kerno, "krb_rd_req failed"); return; } ptr = (char *) pkt->dat + auth->length; memcpy(&time_ws, ptr, 4); ptr += 4; req_life = (*ptr++) & 0xff; service = ptr; str_length_check(service, SNAME_SZ); instance = ptr + strlen(service) + 1; str_length_check(instance, INST_SZ); klog(L_APPL_REQ, "APPL Request %s.%s@%s on %s for %s.%s", ad->pname, ad->pinst, ad->prealm, inet_ntoa(client_host), service, instance, 0); req_name_ptr = ad->pname; req_inst_ptr = ad->pinst; req_realm_ptr = ad->prealm; if (strcmp(ad->prealm, tktrlm)) { kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, "Can't hop realms"); return; } if (!strcmp(service, "changepw")) { kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, "Can't authorize password changed based on TGT"); return; } kerno = check_princ(service, instance, req_life, &s_name_data, &k5key, 1, &sk5life); if (kerno) { kerb_err_reply(client, pkt, kerno, "check_princ failed"); s_name_data.key_high = s_name_data.key_low = 0; krb5_free_keyblock_contents(kdc_context, &k5key); return; } /* Bound requested lifetime with service and user */ v4endtime = krb_life_to_time((KRB4_32)ad->time_sec, ad->life); v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life); v4req_end = min(v4endtime, v4req_end); v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life); lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end); v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime); /* * Adjust issue time backwards if necessary, due to * roundup in krb_time_to_life(). */ if (v4endtime > v4req_end) request_backdate = v4endtime - v4req_end; /* unseal server's key from master key */ memcpy(key, &s_name_data.key_low, 4); memcpy(((krb5_ui_4 *) key) + 1, &s_name_data.key_high, 4); s_name_data.key_low = s_name_data.key_high = 0; kdb_encrypt_key(key, key, master_key, master_key_schedule, DECRYPT); /* construct and seal the ticket */ #ifdef NOENCRYPTION memset(session_key, 0, sizeof(C_Block)); #else /* random session key */ des_new_random_key(session_key); #endif /* ALways issue des tickets*/ krb_create_ticket(tk, k_flags, ad->pname, ad->pinst, ad->prealm, client_host.s_addr, (char *) session_key, lifetime, kerb_time.tv_sec - request_backdate, s_name_data.name, s_name_data.instance, key); krb5_free_keyblock_contents(kdc_context, &k5key); memset(key, 0, sizeof(key)); memset(key_s, 0, sizeof(key_s)); create_ciph(ciph, session_key, service, instance, local_realm, lifetime, s_name_data.key_version, tk, kerb_time.tv_sec, ad->session); /* clear session key */ memset(session_key, 0, sizeof(session_key)); memset(ad->session, 0, sizeof(ad->session)); rpkt = create_auth_reply(ad->pname, ad->pinst, ad->prealm, time_ws, 0, 0, 0, ciph); krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0, (struct sockaddr *) client, sizeof (struct sockaddr_in)); memset(&s_name_data, 0, sizeof(s_name_data)); break; } #ifdef notdef_DIE case AUTH_MSG_DIE: { lt = klog(L_DEATH_REQ, "Host: %s User: \"%s\" \"%s\" Kerberos killed", inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0); exit(0); } #endif /* notdef_DIE */ default: { lt = klog(L_KRB_PERR, "Unknown message type: %d from %s port %u", req_msg_type, inet_ntoa(client_host), ntohs(client->sin_port)); break; } } }