static int mk_auth(struct krb4_data *d, KTEXT adat, char *service, char *host, int checksum) { int ret; CREDENTIALS cred; char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ]; strlcpy(sname, service, sizeof(sname)); strlcpy(inst, krb_get_phost(host), sizeof(inst)); strlcpy(realm, krb_realmofhost(host), sizeof(realm)); ret = krb_mk_req(adat, sname, inst, realm, checksum); if(ret) return ret; strlcpy(sname, service, sizeof(sname)); strlcpy(inst, krb_get_phost(host), sizeof(inst)); strlcpy(realm, krb_realmofhost(host), sizeof(realm)); ret = krb_get_cred(sname, inst, realm, &cred); memmove(&d->key, &cred.session, sizeof(des_cblock)); des_key_sched(&d->key, d->schedule); memset(&cred, 0, sizeof(cred)); return ret; }
static void this_phost(char *host, int hostlen) { char this_host[MAXHOSTNAMELEN + 1]; BCLEAR(this_host); if (gethostname(this_host, sizeof(this_host)) < 0) { sprintf(errbuf, "gethostname: %s", strerror(errno)); rkinit_errmsg(errbuf); error(); exit(1); } strncpy(host, krb_get_phost(this_host), hostlen - 1); }
/* * * K4_auth_send - gets authentication bits we need to send to KDC. * * Result is left in auth * * Returns: 0 on failure, 1 on success */ static int k4_auth_send(kstream ks) { int r; /* Return value */ char instance[INST_SZ]; char *realm; char buf[256]; memset(instance, 0, sizeof(instance)); if (realm = krb_get_phost(szHostName)) lstrcpy(instance, realm); realm = krb_realmofhost(szHostName); if (!realm) { strcpy(buf, "Can't find realm for host \""); strncat(buf, szHostName, sizeof(buf) - 1 - strlen(buf)); strncat(buf, "\"", sizeof(buf) - 1 - strlen(buf)); auth_abort(ks, buf, 0); return KFAILURE; } r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0); if (r == 0) r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred); if (r) { strcpy(buf, "Can't get \""); strncat(buf, KRB_SERVICE_NAME, sizeof(buf) - 1 - strlen(buf)); if (instance[0] != 0) { strncat(buf, ".", sizeof(buf) - 1 - strlen(buf)); lstrcat(buf, instance); } strncat(buf, "@", sizeof(buf) - 1 - strlen(buf)); lstrcat(buf, realm); strncat(buf, "\" ticket", sizeof(buf) - 1 - strlen(buf)); auth_abort(ks, buf, r); return r; } if (!szUserName[0]) /* Copy if not there */ strcpy(szUserName, cred.pname); return(1); }
int krb_sendauth_udp(long options, int fd, KTEXT_FP ticket, const LPSTR service, const LPSTR inst, LPSTR realm, LONG checksum, MSG_DAT *msg_data, CREDENTIALS *cred, Key_schedule *schedule, struct sockaddr_in *laddr, struct sockaddr_in *faddr, LPSTR version, LPSTR buffer, int sz) { int rem, i, cc; char srv_inst[INST_SZ]; char krb_realm[REALM_SZ]; char buf[BUFSIZ]; long tkt_len; u_char priv_buf[1024]; u_long cksum; rem = KSUCCESS; /* get current realm if not passed in */ if (!realm) { rem = krb_get_lrealm(krb_realm,1); if (rem != KSUCCESS) return (rem); realm = krb_realm; } /* Copy instance into local storage, canonicalizing if desired */ if (options & KOPT_DONT_CANON) (void) strncpy(srv_inst, inst, INST_SZ); else (void) strncpy((LPSTR)srv_inst, (LPSTR)krb_get_phost(inst), INST_SZ); /* Get the ticket if desired */ if (!(options & KOPT_DONT_MK_REQ)) { rem = krb_mk_req(ticket, service, srv_inst, realm, checksum); if (rem != KSUCCESS) return (rem); } #ifdef ATHENA_COMPAT /* this is only for compatibility with old servers */ if (options & KOPT_DO_OLDSTYLE) { (void) sprintf(buf, "%d ", ticket->length); (void) write(fd, buf, strlen(buf)); (void) write(fd, (char *) ticket->dat, ticket->length); return (rem); } #endif /* ATHENA_COMPAT */ /* if the mutual auth, get credentials so we have service session * keys for decryption below */ if (options & KOPT_DO_MUTUAL) { /*if (cc == 1) *{ * krb_get_cred(service, srv_inst, realm, cred); * return (cc); *} */ krb_get_cred(service, srv_inst, realm, cred); } /* Zero the buffer */ (void) bzero(buf, BUFSIZ); /* insert version strings */ (void) strncpy(buf, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN); /* increment past version strings */ i = 2*KRB_SENDAUTH_VLEN; /* put ticket length into buffer */ tkt_len = htonl((unsigned long) ticket->length); (void) bcopy((char *) &tkt_len, buf+i, ticket->length); i += ticket->length; /* Normally, we write the request to the server ** For udp, esp. TechNotify type protocols, we ** just return the buffer. */ if (sz < i) return HEY_PAUL_WHAT_ERROR; /* Buffer not big enough */ bcopy(buf, buffer, i); return (KSUCCESS); }
static int kerberos4_send(char *name, Authenticator *ap) { KTEXT_ST auth; char instance[INST_SZ]; char *realm; CREDENTIALS cred; int r; printf("[ Trying %s ... ]\r\n", name); if (!UserNameRequested) { if (auth_debug_mode) { printf("Kerberos V4: no user name supplied\r\n"); } return(0); } memset(instance, 0, sizeof(instance)); if ((realm = krb_get_phost(RemoteHostName))) strncpy(instance, realm, sizeof(instance)); instance[sizeof(instance)-1] = '\0'; realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName); if (!realm) { printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); return(0); } r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L); if (r) { printf("mk_req failed: %s\r\n", krb_get_err_text(r)); return(0); } r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred); if (r) { printf("get_cred failed: %s\r\n", krb_get_err_text(r)); return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { if (auth_debug_mode) printf("Not enough room for user name\r\n"); return(0); } if (auth_debug_mode) printf("Sent %d bytes of authentication data\r\n", auth.length); if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) { if (auth_debug_mode) printf("Not enough room for authentication data\r\n"); return(0); } #ifdef ENCRYPTION /* create challenge */ if ((ap->way & AUTH_HOW_MASK)==AUTH_HOW_MUTUAL) { int i; des_key_sched(&cred.session, sched); des_init_random_number_generator(&cred.session); des_new_random_key(&session_key); des_ecb_encrypt(&session_key, &session_key, sched, 0); des_ecb_encrypt(&session_key, &challenge, sched, 0); /* old code Some CERT Advisory thinks this is a bad thing... des_init_random_number_generator(&cred.session); des_new_random_key(&challenge); des_ecb_encrypt(&challenge, &session_key, sched, 1); */ /* * Increment the challenge by 1, and encrypt it for * later comparison. */ for (i = 7; i >= 0; --i) if(++challenge[i] != 0) /* No carry! */ break; des_ecb_encrypt(&challenge, &challenge, sched, 1); } #endif if (auth_debug_mode) { printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); printf("Sent Kerberos V4 credentials to server\r\n"); } return(1); }
/* * try krb4 authentication, * return 1 on success, 0 on failure, -1 if krb4 is not available */ int auth_krb4_password(Authctxt *authctxt, const char *password) { AUTH_DAT adata; KTEXT_ST tkt; struct hostent *hp; struct passwd *pw; char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ]; u_int32_t faddr; int r; if ((pw = authctxt->pw) == NULL) return (0); /* * Try Kerberos password authentication only for non-root * users and only if Kerberos is installed. */ if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) { /* Set up our ticket file. */ if (!krb4_init(authctxt)) { log("Couldn't initialize Kerberos ticket file for %s!", pw->pw_name); goto failure; } /* Try to get TGT using our password. */ r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm, "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password); if (r != INTK_OK) { debug("Kerberos v4 password authentication for %s " "failed: %s", pw->pw_name, krb_err_txt[r]); goto failure; } /* Successful authentication. */ chown(tkt_string(), pw->pw_uid, pw->pw_gid); /* * Now that we have a TGT, try to get a local * "rcmd" ticket to ensure that we are not talking * to a bogus Kerberos server. */ gethostname(localhost, sizeof(localhost)); strlcpy(phost, (char *)krb_get_phost(localhost), sizeof(phost)); r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33); if (r == KSUCCESS) { if ((hp = gethostbyname(localhost)) == NULL) { log("Couldn't get local host address!"); goto failure; } memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr)); /* Verify our "rcmd" ticket. */ r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, ""); if (r == RD_AP_UNDEC) { /* * Probably didn't have a srvtab on * localhost. Disallow login. */ log("Kerberos v4 TGT for %s unverifiable, " "no srvtab installed? krb_rd_req: %s", pw->pw_name, krb_err_txt[r]); goto failure; } else if (r != KSUCCESS) { log("Kerberos v4 %s ticket unverifiable: %s", KRB4_SERVICE_NAME, krb_err_txt[r]); goto failure; } } else if (r == KDC_PR_UNKNOWN) { /* * Disallow login if no rcmd service exists, and * log the error. */ log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s " "not registered, or srvtab is wrong?", pw->pw_name, krb_err_txt[r], KRB4_SERVICE_NAME, phost); goto failure; } else { /* * TGT is bad, forget it. Possibly spoofed! */ debug("WARNING: Kerberos v4 TGT possibly spoofed " "for %s: %s", pw->pw_name, krb_err_txt[r]); goto failure; } /* Authentication succeeded. */ return (1); } else /* Logging in as root or no local Kerberos realm. */ debug("Unable to authenticate to Kerberos."); failure: krb4_cleanup_proc(authctxt); if (!options.kerberos_or_local_passwd) return (0); /* Fall back to ordinary passwd authentication. */ return (-1); }
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; }