void kerberos5_is(Authenticator *ap, unsigned char *data, int cnt) { krb5_error_code ret; krb5_data outbuf; krb5_keyblock *key_block; char *name; krb5_principal server; krb5_authenticator authenticator; int zero = 0; if (cnt-- < 1) return; switch (*data++) { case KRB_AUTH: auth.data = (char *)data; auth.length = cnt; auth_context = NULL; ret = krb5_auth_con_init (context, &auth_context); if (ret) { Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } ret = krb5_auth_con_setaddrs_from_fd (context, auth_context, &zero); if (ret) { Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: " "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } ret = krb5_sock_to_principal (context, 0, "host", KRB5_NT_SRV_HST, &server); if (ret) { Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: " "krb5_sock_to_principal failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } ret = krb5_rd_req(context, &auth_context, &auth, server, NULL, NULL, &ticket); krb5_free_principal (context, server); if (ret) { char *errbuf; asprintf(&errbuf, "Read req failed: %s", krb5_get_err_text(context, ret)); Data(ap, KRB_REJECT, errbuf, -1); if (auth_debug_mode) printf("%s\r\n", errbuf); free (errbuf); return; } ret = krb5_auth_con_getkey(context, auth_context, &key_block); if (ret) { Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: " "krb5_auth_con_getkey failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } ret = krb5_auth_getauthenticator (context, auth_context, &authenticator); if (ret) { Data(ap, KRB_REJECT, "krb5_auth_getauthenticator failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: " "krb5_auth_getauthenticator failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } if (authenticator->cksum) { char foo[2]; foo[0] = ap->type; foo[1] = ap->way; ret = krb5_verify_checksum (context, foo, sizeof(foo), key_block, authenticator->cksum); if (ret) { Data(ap, KRB_REJECT, "No checksum", -1); if (auth_debug_mode) printf ("No checksum\r\n"); krb5_free_authenticator (context, &authenticator); return; } } krb5_free_authenticator (context, &authenticator); ret = krb5_auth_con_getremotesubkey (context, auth_context, &key_block); if (ret) { Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: " "krb5_auth_con_getremotesubkey failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { ret = krb5_mk_rep(context, &auth_context, &outbuf); if (ret) { Data(ap, KRB_REJECT, "krb5_mk_rep failed", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("Kerberos V5: " "krb5_mk_rep failed (%s)\r\n", krb5_get_err_text(context, ret)); return; } Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); } if (krb5_unparse_name(context, ticket->client, &name)) name = 0; if(UserNameRequested && krb5_kuserok(context, ticket->client, UserNameRequested)) { Data(ap, KRB_ACCEPT, name, name ? -1 : 0); if (auth_debug_mode) { printf("Kerberos5 identifies him as ``%s''\r\n", name ? name : ""); } if(key_block->keytype == KEYTYPE_DES) { Session_Key skey; skey.type = SK_DES; skey.length = 8; skey.data = key_block->keyvalue.data; encrypt_session_key(&skey, 0); } } else { char *msg; asprintf (&msg, "user `%s' is not authorized to " "login as `%s'", name ? name : "<unknown>", UserNameRequested ? UserNameRequested : "<nobody>"); if (msg == NULL) Data(ap, KRB_REJECT, NULL, 0); else { Data(ap, KRB_REJECT, (void *)msg, -1); free(msg); } } auth_finished(ap, AUTH_USER); krb5_free_keyblock_contents(context, key_block); break; #ifdef FORWARD case KRB_FORWARD: { struct passwd *pwd; char ccname[1024]; /* XXX */ krb5_data inbuf; krb5_ccache ccache; inbuf.data = (char *)data; inbuf.length = cnt; pwd = getpwnam (UserNameRequested); if (pwd == NULL) break; snprintf (ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%u", pwd->pw_uid); ret = krb5_cc_resolve (context, ccname, &ccache); if (ret) { if (auth_debug_mode) printf ("Kerberos V5: could not get ccache: %s\r\n", krb5_get_err_text(context, ret)); break; } ret = krb5_cc_initialize (context, ccache, ticket->client); if (ret) { if (auth_debug_mode) printf ("Kerberos V5: could not init ccache: %s\r\n", krb5_get_err_text(context, ret)); break; } ret = krb5_rd_cred (context, auth_context, ccache, &inbuf); if(ret) { char *errbuf; asprintf (&errbuf, "Read forwarded creds failed: %s", krb5_get_err_text (context, ret)); if(errbuf == NULL) Data(ap, KRB_FORWARD_REJECT, NULL, 0); else Data(ap, KRB_FORWARD_REJECT, errbuf, -1); if (auth_debug_mode) printf("Could not read forwarded credentials: %s\r\n", errbuf); free (errbuf); } else Data(ap, KRB_FORWARD_ACCEPT, 0, 0); chown (ccname + 5, pwd->pw_uid, -1); if (auth_debug_mode) printf("Forwarded credentials obtained\r\n"); break; } #endif /* FORWARD */ default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); Data(ap, KRB_REJECT, 0, 0); break; } }
static int recv_krb5_auth (int s, u_char *buf, struct sockaddr *thisaddr, struct sockaddr *thataddr, char **client_username, char **server_username, char **cmd) { uint32_t len; krb5_auth_context auth_context = NULL; krb5_ticket *ticket; krb5_error_code status; krb5_data cksum_data; krb5_principal server; char *str; if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0) return -1; len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); if (net_read(s, buf, len) != len) syslog_and_die ("reading auth info: %s", strerror(errno)); if (len != sizeof(KRB5_SENDAUTH_VERSION) || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0) syslog_and_die ("bad sendauth version: %.8s", buf); status = krb5_sock_to_principal (context, s, "host", KRB5_NT_SRV_HST, &server); if (status) syslog_and_die ("krb5_sock_to_principal: %s", krb5_get_err_text(context, status)); status = krb5_recvauth_match_version(context, &auth_context, &s, match_kcmd_version, NULL, server, KRB5_RECVAUTH_IGNORE_VERSION, NULL, &ticket); krb5_free_principal (context, server); if (status) syslog_and_die ("krb5_recvauth: %s", krb5_get_err_text(context, status)); *server_username = read_str (s, USERNAME_SZ, "remote username"); *cmd = read_str (s, ARG_MAX + 1, "command"); *client_username = read_str (s, ARG_MAX + 1, "local username"); if(protocol_version == 2) { status = krb5_auth_con_getremotesubkey(context, auth_context, &keyblock); if(status != 0 || keyblock == NULL) syslog_and_die("failed to get remote subkey"); } else if(protocol_version == 1) { status = krb5_auth_con_getkey (context, auth_context, &keyblock); if(status != 0 || keyblock == NULL) syslog_and_die("failed to get key"); } if (status != 0 || keyblock == NULL) syslog_and_die ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); status = krb5_crypto_init(context, keyblock, 0, &crypto); if(status) syslog_and_die("krb5_crypto_init: %s", krb5_get_err_text(context, status)); cksum_data.length = asprintf (&str, "%u:%s%s", ntohs(socket_get_port (thisaddr)), *cmd, *server_username); if (str == NULL) syslog_and_die ("asprintf: out of memory"); cksum_data.data = str; status = krb5_verify_authenticator_checksum(context, auth_context, cksum_data.data, cksum_data.length); if (status) syslog_and_die ("krb5_verify_authenticator_checksum: %s", krb5_get_err_text(context, status)); free (cksum_data.data); if (strncmp (*client_username, "-u ", 3) == 0) { do_unique_tkfile = 1; memmove (*client_username, *client_username + 3, strlen(*client_username) - 2); } if (strncmp (*client_username, "-U ", 3) == 0) { char *end, *temp_tkfile; do_unique_tkfile = 1; if (strncmp (*client_username + 3, "FILE:", 5) == 0) { temp_tkfile = tkfile; } else { strlcpy (tkfile, "FILE:", sizeof(tkfile)); temp_tkfile = tkfile + 5; } end = strchr(*client_username + 3,' '); if (end == NULL) syslog_and_die("missing argument after -U"); snprintf(temp_tkfile, sizeof(tkfile) - (temp_tkfile - tkfile), "%.*s", (int)(end - *client_username - 3), *client_username + 3); memmove (*client_username, end + 1, strlen(end+1)+1); } kerberos_status = save_krb5_creds (s, auth_context, ticket->client); if(!krb5_kuserok (context, ticket->client, *server_username)) fatal (s, NULL, "Permission denied."); if (strncmp (*cmd, "-x ", 3) == 0) { do_encrypt = 1; memmove (*cmd, *cmd + 3, strlen(*cmd) - 2); } else { if(do_encrypt) fatal (s, NULL, "Encryption is required."); do_encrypt = 0; } { char *name; if (krb5_unparse_name (context, ticket->client, &name) == 0) { char addr_str[256]; if (inet_ntop (thataddr->sa_family, socket_get_address (thataddr), addr_str, sizeof(addr_str)) == NULL) strlcpy (addr_str, "unknown address", sizeof(addr_str)); syslog(LOG_INFO|LOG_AUTH, "kerberos v5 shell from %s on %s as %s, cmd '%.80s'", name, addr_str, *server_username, *cmd); free (name); } } krb5_auth_con_free(context, auth_context); return 0; }