static int kerberosv4_decode_packet(void *context, const char *input, unsigned inputlen, char **output, unsigned *outputlen) { context_t *text = (context_t *) context; int result; MSG_DAT data; memset(&data,0,sizeof(MSG_DAT)); KRB_LOCK_MUTEX(text->utils); if (text->sec_type == KRB_SEC_ENCRYPTION) { result=krb_rd_priv(input, inputlen, text->init_keysched, &text->session, &text->ip_remote, &text->ip_local, &data); } else if (text->sec_type == KRB_SEC_INTEGRITY) { result = krb_rd_safe(input, inputlen, &text->session, &text->ip_remote, &text->ip_local, &data); } else { KRB_UNLOCK_MUTEX(text->utils); text->utils->seterror(text->utils->conn, 0, "KERBEROS_4 decode called with KRB_SEC_NONE"); return SASL_FAIL; } KRB_UNLOCK_MUTEX(text->utils); /* see if the krb library gave us a failure */ if (result != 0) { text->utils->seterror(text->utils->conn, 0, get_krb_err_txt(result)); return SASL_FAIL; } /* check to make sure the timestamps are ok */ if ((data.time_sec < text->time_sec) || /* if an earlier time */ (((data.time_sec == text->time_sec) && /* or the exact same time */ (data.time_5ms < text->time_5ms)))) { text->utils->seterror(text->utils->conn, 0, "timestamps not ok"); return SASL_FAIL; } text->time_sec = data.time_sec; text->time_5ms = data.time_5ms; result = _plug_buf_alloc(text->utils, &text->decode_once_buf, &text->decode_once_buf_len, data.app_length + 1); if(result != SASL_OK) return result; *output = text->decode_once_buf; *outputlen = data.app_length; memcpy(*output, data.app_data, data.app_length); (*output)[*outputlen] = '\0'; return SASL_OK; }
static int krb4_decode(void *app_data, void *buf, int len, int level, struct connectdata *conn) { MSG_DAT m; int e; struct krb4_data *d = app_data; if(level == prot_safe) e = krb_rd_safe(buf, len, &d->key, (struct sockaddr_in *)REMOTE_ADDR, (struct sockaddr_in *)LOCAL_ADDR, &m); else e = krb_rd_priv(buf, len, d->schedule, &d->key, (struct sockaddr_in *)REMOTE_ADDR, (struct sockaddr_in *)LOCAL_ADDR, &m); if(e) { struct SessionHandle *data = conn->data; infof(data, "krb4_decode: %s\n", krb_get_err_text(e)); return -1; } memmove(buf, m.app_data, m.app_length); return m.app_length; }
int krb_sendauth_udpchk(long options, LONG checksum, MSG_DAT *msg_data, CREDENTIALS* cred, Key_schedule *schedule, struct sockaddr_in *laddr, struct sockaddr_in *faddr, LPSTR packet) { int cc; long tkt_len; u_long cksum; u_char priv_buf[1024]; /* mutual authentication, if desired */ if (options & KOPT_DO_MUTUAL) { /* get the length of the reply */ bcopy(packet,(char*) &tkt_len, sizeof(tkt_len)); tkt_len = ntohl((unsigned long) tkt_len); /* if the length is negative, the server failed to recognize us */ if ((tkt_len < 0) || (tkt_len > sizeof(priv_buf))) return (KFAILURE); /* XXX */ /* read the reply... */ bcopy(packet+sizeof(tkt_len), (char *)priv_buf, (int) tkt_len); /* ...and decrypt it */ #ifndef NOENCRYPTION key_sched(cred->session, *schedule); #endif /* !NOENCRYPTION */ if (cc = krb_rd_priv(priv_buf, (unsigned long) tkt_len, *schedule, cred->session, faddr, laddr, msg_data)) return (cc); /* fetch the (modified) checksum */ (void) bcopy((char *)msg_data->app_data, (char *)&cksum, sizeof(cksum)); cksum = ntohl(cksum); /* if it doesn't match, fail */ if (cksum != checksum + 1) return (KFAILURE); /* XXX */ } return (KSUCCESS); }
static int krb4_decode(void *app_data, void *buf, int len, int level) { MSG_DAT m; int e; struct krb4_data *d = app_data; if(level == prot_safe) e = krb_rd_safe(buf, len, &d->key, (struct sockaddr_in *)REMOTE_ADDR, (struct sockaddr_in *)LOCAL_ADDR, &m); else e = krb_rd_priv(buf, len, d->schedule, &d->key, (struct sockaddr_in *)REMOTE_ADDR, (struct sockaddr_in *)LOCAL_ADDR, &m); if(e){ ftp_err("krb4_decode: %s", krb_get_err_text(e)); return -1; } memmove(buf, m.app_data, m.app_length); return m.app_length; }
static int decrypt_tkt(char *user, char *instance, char *realm, char *arg, int (*key_proc)(char *, char *, char *, char *, C_Block), KTEXT *cipp) { MSG_DAT msg_data; /* Message data containing decrypted data */ KTEXT_ST auth; /* Authenticator */ AUTH_DAT auth_dat; /* Authentication data */ KTEXT cip = *cipp; MSG_DAT scip; int status = 0; des_cblock key; des_key_schedule sched; char phost[MAXHOSTNAMELEN + 1]; struct sockaddr_in caddr; /* client internet address */ struct sockaddr_in saddr; /* server internet address */ rkinitd_intkt_info *rii = (rkinitd_intkt_info *)arg; u_char enc_data[MAX_KTXT_LEN]; SBCLEAR(auth); SBCLEAR(auth_dat); SBCLEAR(scip); BCLEAR(enc_data); scip.app_data = enc_data; /* * Exchange with the client our response from the KDC (ticket encrypted * in user's private key) for the same ticket encrypted in our * (not yet known) session key. */ rpc_exchange_tkt(cip, &scip); /* * Get the authenticator */ SBCLEAR(auth); rpc_getauth(&auth, &caddr, &saddr); /* * Decode authenticator and extract session key. The first zero * means we don't care what host this comes from. This needs to * be done with euid of root so that /etc/srvtab can be read. */ BCLEAR(phost); this_phost(phost, sizeof(phost)); /* * This function has to use longjmp to return to the caller * because the kerberos library routine that calls it doesn't * pay attention to the return value it gives. That means that * if any of these routines failed, the error returned to the client * would be "password incorrect". */ status = krb_rd_req(&auth, KEY, phost, caddr.sin_addr.s_addr, &auth_dat, ""); if (status) { sprintf(errbuf, "krb_rd_req: %s", krb_err_txt[status]); rkinit_errmsg(errbuf); longjmp(rii->env, status); } memcpy(key, auth_dat.session, sizeof(key)); if (des_key_sched(key, sched)) { sprintf(errbuf, "Error in des_key_sched"); rkinit_errmsg(errbuf); longjmp(rii->env, RKINIT_DES); } /* Decrypt the data. */ if ((status = krb_rd_priv((u_char *)scip.app_data, scip.app_length, sched, key, &caddr, &saddr, &msg_data)) == KSUCCESS) { cip->length = msg_data.app_length; memcpy(cip->dat, msg_data.app_data, msg_data.app_length); cip->dat[cip->length] = 0; } else { sprintf(errbuf, "krb_rd_priv: %s", krb_err_txt[status]); rkinit_errmsg(errbuf); longjmp(rii->env, status); } if (setuid(user_id) < 0) { sprintf(errbuf, "Failure setting uid to %lu: %s\n", (unsigned long)user_id, strerror(errno)); rkinit_errmsg(errbuf); longjmp(rii->env, RKINIT_DAEMON); } return(KSUCCESS); }
static int try_krb4_authentication(void) { KTEXT_ST auth; /* Kerberos data */ char *reply; char inst[INST_SZ]; char *realm; CREDENTIALS cred; int r, type; socklen_t slen; Key_schedule schedule; u_long checksum, cksum; MSG_DAT msg_data; struct sockaddr_in local, foreign; struct stat st; /* Don't do anything if we don't have any tickets. */ if (stat(tkt_string(), &st) < 0) return 0; strlcpy(inst, (char *)krb_get_phost(get_canonical_hostname(1)), INST_SZ); realm = (char *)krb_realmofhost(get_canonical_hostname(1)); if (!realm) { debug("Kerberos v4: no realm for %s", get_canonical_hostname(1)); return 0; } /* This can really be anything. */ checksum = (u_long)getpid(); r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); if (r != KSUCCESS) { debug("Kerberos v4 krb_mk_req failed: %s", krb_err_txt[r]); return 0; } /* Get session key to decrypt the server's reply with. */ r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred); if (r != KSUCCESS) { debug("get_cred failed: %s", krb_err_txt[r]); return 0; } des_key_sched((des_cblock *) cred.session, schedule); /* Send authentication info to server. */ packet_start(SSH_CMSG_AUTH_KERBEROS); packet_put_string((char *) auth.dat, auth.length); packet_send(); packet_write_wait(); /* Zero the buffer. */ (void) memset(auth.dat, 0, MAX_KTXT_LEN); slen = sizeof(local); memset(&local, 0, sizeof(local)); if (getsockname(packet_get_connection_in(), (struct sockaddr *)&local, &slen) < 0) debug("getsockname failed: %s", strerror(errno)); slen = sizeof(foreign); memset(&foreign, 0, sizeof(foreign)); if (getpeername(packet_get_connection_in(), (struct sockaddr *)&foreign, &slen) < 0) { debug("getpeername failed: %s", strerror(errno)); cleanup_exit(255); } /* Get server reply. */ type = packet_read(); switch (type) { case SSH_SMSG_FAILURE: /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ debug("Kerberos v4 authentication failed."); return 0; break; case SSH_SMSG_AUTH_KERBEROS_RESPONSE: /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ debug("Kerberos v4 authentication accepted."); /* Get server's response. */ reply = packet_get_string((u_int *) &auth.length); if (auth.length >= MAX_KTXT_LEN) fatal("Kerberos v4: Malformed response from server"); memcpy(auth.dat, reply, auth.length); free(reply); packet_check_eom(); /* * If his response isn't properly encrypted with the session * key, and the decrypted checksum fails to match, he's * bogus. Bail out. */ r = krb_rd_priv(auth.dat, auth.length, (void *)schedule, &cred.session, &foreign, &local, &msg_data); if (r != KSUCCESS) { debug("Kerberos v4 krb_rd_priv failed: %s", krb_err_txt[r]); packet_disconnect("Kerberos v4 challenge failed!"); } /* Fetch the (incremented) checksum that we supplied in the request. */ memcpy((char *)&cksum, (char *)msg_data.app_data, sizeof(cksum)); cksum = ntohl(cksum); /* If it matches, we're golden. */ if (cksum == checksum + 1) { debug("Kerberos v4 challenge successful."); return 1; } else packet_disconnect("Kerberos v4 challenge failed!"); break; default: packet_disconnect("Protocol error on Kerberos v4 response: %d", type); } return 0; }