static int ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) { krb5_principal princ; int retval; if (ssh_gssapi_krb5_init() == 0) return 0; if ((retval = krb5_parse_name(krb_context, client->exportedname.value, &princ))) { logit("krb5_parse_name(): %.100s", krb5_get_err_text(krb_context, retval)); return 0; } if (krb5_kuserok(krb_context, princ, name)) { retval = 1; logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", name, (char *)client->displayname.value); } else retval = 0; krb5_free_principal(krb_context, princ); return retval; }
krb5_error_code KRB5_LIB_FUNCTION krb5_aname_to_localname (krb5_context context, krb5_const_principal aname, size_t lnsize, char *lname) { krb5_error_code ret; krb5_realm *lrealms, *r; int valid; size_t len; const char *res; ret = krb5_get_default_realms (context, &lrealms); if (ret) return ret; valid = 0; for (r = lrealms; *r != NULL; ++r) { if (strcmp (*r, aname->realm) == 0) { valid = 1; break; } } krb5_free_host_realm (context, lrealms); if (valid == 0) return KRB5_NO_LOCALNAME; if (aname->name.name_string.len == 1) res = aname->name.name_string.val[0]; else if (aname->name.name_string.len == 2 && strcmp (aname->name.name_string.val[1], "root") == 0) { krb5_principal rootprinc; krb5_boolean userok; res = "root"; ret = krb5_copy_principal(context, aname, &rootprinc); if (ret) return ret; userok = krb5_kuserok(context, rootprinc, res); krb5_free_principal(context, rootprinc); if (!userok) return KRB5_NO_LOCALNAME; } else return KRB5_NO_LOCALNAME; len = strlen (res); if (len >= lnsize) return ERANGE; strlcpy (lname, res, lnsize); return 0; }
int ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client) { if (options.use_kuserok) return krb5_kuserok(krb5_ctx, krb5_user, client); else { char kuser[65]; if (krb5_aname_to_localname(krb5_ctx, krb5_user, sizeof(kuser), kuser)) return 0; return strcmp(kuser, client) == 0; } }
int main(int argc, char **argv) { krb5_context context; krb5_ccache ccache; krb5_principal p; char *name; char *pw; if (argc != 2) usage(); #ifdef HAVE_ALARM alarm( TIMEOUT ); #endif name = argv[1]; pw = read_pw(stdin); if (!pw) die("No proper password provided."); if (!strcmp(name, "root")) /* In this case, heimdal's su.c creates a principal for the * current uid, but I don't quite understand why. */ die("Won't log in root."); if (krb5_init_context (&context)) die("krb5_init_context failed."); if (krb5_make_principal(context, &p, NULL, name, NULL)) die("krb5_make_principal failed."); if (!krb5_kuserok(context, p, name)) die("krb5_kuserok doesn't know the user."); if (krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache)) die("krb5_cc_gen_new failed."); if (krb5_verify_user_lrealm(context, p, ccache, pw, TRUE, NULL)) die("krb5_verify_user_lrealm failed."); /* Authentication successful. */ /* TODO: Keep the credential cache in some way. Perhaps write it to * disk, and, write the file name used to stdout. */ return EXIT_SUCCESS; }
int main(int argc, char **argv) { krb5_context context; krb5_error_code ret; krb5_principal principal; char *p; int o = 0; setprogname(argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &o)) usage(1); if (help_flag) usage (0); if(version_flag){ print_version(NULL); exit(0); } argc -= o; argv += o; ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); if (argc != 2) usage(1); ret = krb5_parse_name(context, argv[0], &principal); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_unparse_name(context, principal, &p); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name"); ret = krb5_kuserok(context, principal, argv[1]); krb5_free_context(context); printf("%s is %sallowed to login as %s\n", p, ret ? "" : "NOT ", argv[1]); return 0; }
int kerberos5_status (TN_Authenticator * ap, char *name, int level) { if (level < AUTH_USER) return level; if (UserNameRequested && krb5_kuserok (telnet_context, ticket->enc_part2->client, UserNameRequested)) { /* FIXME: Check buffer length */ strcpy (name, UserNameRequested); return AUTH_VALID; } return AUTH_USER; }
int kerberos5_status(Authenticator *ap, char *name, int level) { if (level < AUTH_USER) return(level); if (UserNameRequested && krb5_kuserok(context, ticket->client, UserNameRequested)) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else return(AUTH_USER); }
int kerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level) { if (level < AUTH_USER) return(level); if (UserNameRequested && krb5_kuserok(context, ticket->client, UserNameRequested)) { strlcpy(name, UserNameRequested, name_sz); #if defined(DCE) dfsk5ok = 1; #endif return(AUTH_VALID); } else return(AUTH_USER); }
int do_krb5_login (int infd, struct auth_data *ap, const char **err_msg) { krb5_auth_context auth_ctx = NULL; krb5_error_code status; krb5_data inbuf; krb5_data version; krb5_authenticator *authenticator; krb5_rcache rcache; krb5_keyblock *key; krb5_ticket *ticket; struct sockaddr_in laddr; int len; struct passwd *pwd; char *name; if (status = krb5_init_context (&ap->context)) { syslog (LOG_ERR, "Error initializing krb5: %s", error_message (status)); return status; } if ((status = krb5_auth_con_init (ap->context, &auth_ctx)) || (status = krb5_auth_con_genaddrs (ap->context, auth_ctx, infd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) || (status = krb5_auth_con_getrcache (ap->context, auth_ctx, &rcache))) return status; if (!rcache) { krb5_principal server; status = krb5_sname_to_principal (ap->context, 0, 0, KRB5_NT_SRV_HST, &server); if (status) return status; status = krb5_get_server_rcache (ap->context, krb5_princ_component (ap->context, server, 0), &rcache); krb5_free_principal (ap->context, server); if (status) return status; status = krb5_auth_con_setrcache (ap->context, auth_ctx, rcache); if (status) return status; } len = sizeof (laddr); if (getsockname (infd, (struct sockaddr *) &laddr, &len)) return errno; status = krb5_recvauth (ap->context, &auth_ctx, &infd, NULL, 0, 0, ap->keytab, &ticket); if (status) return status; if ((status = krb5_auth_con_getauthenticator (ap->context, auth_ctx, &authenticator))) return status; getstr (infd, &ap->lusername, NULL); getstr (infd, &ap->term, "TERM="); pwd = getpwnam (ap->lusername); if (pwd == NULL) { *err_msg = "getpwnam failed"; syslog (LOG_ERR, "getpwnam failed: %m"); return 1; } getstr (infd, &ap->rusername, NULL); if ((status = krb5_copy_principal (ap->context, ticket->enc_part2->client, &ap->client))) return status; /*OK:: */ if (ap->client && !krb5_kuserok (ap->context, ap->client, ap->lusername)) return 1; krb5_unparse_name (ap->context, ap->client, &name); syslog (LOG_INFO | LOG_AUTH, "%sKerberos V login from %s on %s\n", (pwd->pw_uid == 0) ? "ROOT " : "", name, ap->hostname); free (name); return 0; }
/* * Verify the user authorization. Call krb5_kuserok if this is a local * account, or do the krb5_aname_to_localname verification if ignore_k5login * was requested. For non-local accounts, the principal must match the * authentication identity. */ int pamk5_authorized(struct pam_args *args) { struct context *ctx; krb5_context c; struct passwd *pwd; char kuser[65]; /* MAX_USERNAME == 65 (MIT Kerberos 1.4.1). */ if (args == NULL || args->ctx == NULL || args->ctx->context == NULL) return PAM_SERVICE_ERR; ctx = args->ctx; if (ctx->name == NULL) return PAM_SERVICE_ERR; c = ctx->context; /* * If alt_auth_map was set, authorize the user if the authenticated * principal matches the mapped principal. alt_auth_map essentially * serves as a supplemental .k5login. */ if (args->alt_auth_map != NULL) { char *mapped; char *authed; int retval; krb5_principal princ; if (pamk5_map_principal(args, ctx->name, &mapped) != PAM_SUCCESS) return PAM_SERVICE_ERR; retval = krb5_parse_name(c, mapped, &princ); if (retval != 0) { free(mapped); return PAM_SERVICE_ERR; } free(mapped); retval = krb5_unparse_name(c, princ, &mapped); if (retval != 0) return PAM_SERVICE_ERR; retval = krb5_unparse_name(c, ctx->princ, &authed); if (retval != 0) { free(mapped); return PAM_SERVICE_ERR; } if (strcmp(authed, mapped) == 0) { free(authed); free(mapped); return PAM_SUCCESS; } free(authed); free(mapped); } /* * If the name to which we're authenticating contains @ (is fully * qualified), it must match the principal exactly. */ if (strchr(ctx->name, '@') != NULL) { char *principal; int retval; retval = krb5_unparse_name(c, ctx->princ, &principal); if (retval != 0) return PAM_SERVICE_ERR; if (strcmp(principal, ctx->name) != 0) { free(principal); return PAM_AUTH_ERR; } return PAM_SUCCESS; } /* * Otherwise, apply either krb5_aname_to_localname or krb5_kuserok * depending on the situation. */ pwd = pam_modutil_getpwnam(args->pamh, ctx->name); if (args->ignore_k5login || pwd == NULL) { if (krb5_aname_to_localname(c, ctx->princ, sizeof(kuser), kuser) != 0) return PAM_AUTH_ERR; if (strcmp(kuser, ctx->name) != 0) return PAM_AUTH_ERR; } else { if (!krb5_kuserok(c, ctx->princ, ctx->name)) return PAM_AUTH_ERR; } return PAM_SUCCESS; }
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; }
static int krb5_verify(const struct passwd *login_info, const struct passwd *su_info, const char *instance) { krb5_error_code ret; krb5_principal p; krb5_realm *realms, *r; char *login_name = NULL; int user_ok = 0; #if defined(HAVE_GETLOGIN) && !defined(POSIX_GETLOGIN) login_name = getlogin(); #endif ret = krb5_init_context (&context); if (ret) { #if 0 warnx("krb5_init_context failed: %d", ret); #endif return 1; } ret = krb5_get_default_realms(context, &realms); if (ret) return 1; /* Check all local realms */ for (r = realms; *r != NULL && !user_ok; r++) { if (login_name == NULL || strcmp (login_name, "root") == 0) login_name = login_info->pw_name; if (strcmp (su_info->pw_name, "root") == 0) ret = krb5_make_principal(context, &p, *r, login_name, instance, NULL); else ret = krb5_make_principal(context, &p, *r, su_info->pw_name, NULL); if (ret) { krb5_free_host_realm(context, realms); return 1; } /* if we are su-ing too root, check with krb5_kuserok */ if (su_info->pw_uid == 0 && !krb5_kuserok(context, p, su_info->pw_name)) continue; ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if(ret) { krb5_free_host_realm(context, realms); krb5_free_principal (context, p); return 1; } ret = krb5_verify_user(context, p, ccache, NULL, TRUE, NULL); krb5_free_principal (context, p); switch (ret) { case 0: user_ok = 1; break; case KRB5_LIBOS_PWDINTR : krb5_cc_destroy(context, ccache); break; case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: krb5_cc_destroy(context, ccache); krb5_warnx(context, "Password incorrect"); break; default : krb5_cc_destroy(context, ccache); krb5_warn(context, ret, "krb5_verify_user"); break; } } krb5_free_host_realm(context, realms); if (!user_ok) return 1; return 0; }
int auth_krb5_password(Authctxt *authctxt, const char *password) { #ifndef HEIMDAL krb5_creds creds; krb5_principal server; #endif krb5_error_code problem; krb5_ccache ccache = NULL; int len; char *client, *platform_client; /* get platform-specific kerberos client principal name (if it exists) */ platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name); client = platform_client ? platform_client : authctxt->pw->pw_name; temporarily_use_uid(authctxt->pw); problem = krb5_init(authctxt); if (problem) goto out; problem = krb5_parse_name(authctxt->krb5_ctx, client, &authctxt->krb5_user); if (problem) goto out; #ifdef HEIMDAL problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto out; restore_uid(); problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, ccache, password, 1, NULL); temporarily_use_uid(authctxt->pw); if (problem) goto out; problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, authctxt->krb5_fwd_ccache); krb5_cc_destroy(authctxt->krb5_ctx, ccache); ccache = NULL; if (problem) goto out; #else problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); if (problem) goto out; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, KRB5_NT_SRV_HST, &server); if (problem) goto out; restore_uid(); problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, NULL, NULL, NULL); krb5_free_principal(authctxt->krb5_ctx, server); temporarily_use_uid(authctxt->pw); if (problem) goto out; if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { problem = -1; goto out; } problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, authctxt->krb5_user); if (problem) goto out; problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, &creds); if (problem) goto out; #endif authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); len = strlen(authctxt->krb5_ticket_file) + 6; authctxt->krb5_ccname = xmalloc(len); snprintf(authctxt->krb5_ccname, len, "FILE:%s", authctxt->krb5_ticket_file); #ifdef USE_PAM if (options.use_pam) do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); #endif out: restore_uid(); if (platform_client != NULL) xfree(platform_client); if (problem) { if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); if (authctxt->krb5_ctx != NULL && problem!=-1) debug("Kerberos password authentication failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); else debug("Kerberos password authentication failed: %d", problem); krb5_cleanup_proc(authctxt); if (options.kerberos_or_local_passwd) return (-1); else return (0); } return (authctxt->valid ? 1 : 0); }
int pop_pass (POP *p) { struct passwd *pw; int i; int status; /* Make one string of all these parameters */ for (i = 1; i < p->parm_count; ++i) p->pop_parm[i][strlen(p->pop_parm[i])] = ' '; /* Look for the user in the password file */ if ((pw = k_getpwnam(p->user)) == NULL) return (pop_msg(p,POP_FAILURE, "Password supplied for \"%s\" is incorrect.", p->user)); if (p->kerberosp) { #ifdef KRB5 if (p->version == 5) { char *name; if (!krb5_kuserok (p->context, p->principal, p->user)) { pop_log (p, POP_PRIORITY, "krb5 permission denied"); return pop_msg(p, POP_FAILURE, "Popping not authorized"); } if(krb5_unparse_name (p->context, p->principal, &name) == 0) { pop_log(p, POP_INFO, "%s: %s -> %s", p->ipaddr, name, p->user); free (name); } } else { pop_log (p, POP_PRIORITY, "kerberos authentication failed"); return pop_msg (p, POP_FAILURE, "kerberos authentication failed"); } #endif { } } else { /* We don't accept connections from users with null passwords */ if (pw->pw_passwd == NULL) return (pop_msg(p, POP_FAILURE, "Password supplied for \"%s\" is incorrect.", p->user)); #ifdef OTP if (otp_verify_user (&p->otp_ctx, p->pop_parm[1]) == 0) /* pass OK */; else #endif /* Compare the supplied password with the password file entry */ if (p->auth_level != AUTH_NONE) return pop_msg(p, POP_FAILURE, "Password supplied for \"%s\" is incorrect.", p->user); else if (!strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) /* pass OK */; else { int ret = -1; #ifdef KRB5 if(ret) ret = krb5_verify_password (p); #endif if(ret) return pop_msg(p, POP_FAILURE, "Password incorrect"); } } status = login_user(p); if(status != POP_SUCCESS) return status; /* Authorization completed successfully */ return (pop_msg (p, POP_SUCCESS, "%s has %d message(s) (%ld octets).", p->user, p->msg_count, p->drop_size)); }
int gsslib_put_credentials(gss_cred_id_t server_creds, gss_buffer_desc *cred, char *username) { gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_buffer_desc client_name; OM_uint32 maj_stat, min_stat; GSSAPI_INT ret_flags; gss_buffer_desc send_tok; gss_name_t client = NULL; gss_OID doid; int cc=0; gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL; gsslib_reset_error(); send_tok.length = 0; client_name.length = 0; if (cred->length <= 0) { gsslib_print_error(MSG_GSS_PRINTERROR_CREDENTIALBUFFERLENGTHISZERO ); cc = -1; goto error; } /* * establish and forward client credentials */ maj_stat = gss_accept_sec_context(&min_stat, &context, server_creds, cred, GSS_C_NO_CHANNEL_BINDINGS, &client, &doid, &send_tok, &ret_flags, NULL, /* ignore time_rec */ &delegated_cred); /* ignore del_cred_handle */ if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_ACCEPTINGCONTEXT, maj_stat, min_stat); cc = -1; goto error; } if (send_tok.length != 0) { fprintf(stderr, "%s\n", MSG_GSS_ACCEPTSECCONTEXTREQUIRESTOKENTOBESENTBACK ); /* cc = -1; goto error; */ } maj_stat = gss_display_name(&min_stat, client, &client_name, &doid); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_DISPLAYINGNAME, maj_stat, min_stat); cc = -1; goto error; } #ifdef KRBGSS #ifdef KRB5_EXPORTVAR /* this is required for later Kerberos versions */ /* check for delegated credential */ if (delegated_cred == GSS_C_NO_CREDENTIAL) { fprintf(stderr, "WARNING: Credentials were not forwarded\n"); #ifdef REQUIRE_FORWARDED_CREDENTIALS cc = 3; goto error; #endif } if (username && (ret_flags & GSS_C_DELEG_FLAG)) { char *principal = malloc(client_name.length + 1); strncpy(principal, client_name.value, client_name.length); principal[client_name.length] = 0; put_creds_in_ccache(principal, delegated_cred); free(principal); } #endif #endif /* display the flags */ if (verbose) gsslib_display_ctx_flags(ret_flags); if (verbose) printf("client: \"%.*s\"\n", (int) client_name.length, (char *) client_name.value); if (username) { gss_buffer_desc tok; gss_name_t user_name; int str_equal; tok.value = username; tok.length = strlen(tok.value)+1; maj_stat = gss_import_name(&min_stat, &tok, GSS_C_NULL_OID, &user_name); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_PARSINGNAME, maj_stat, min_stat); cc = -1; goto error; } maj_stat = gss_compare_name(&min_stat, client, user_name, &str_equal); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status( MSG_GSS_DISPLAYSTATUS_DISPLAYINGNAME, maj_stat, min_stat); cc = 6; goto error; } #ifdef KRBGSS if (!str_equal) { krb5_context context; maj_stat = krb5_init_context(&context); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GETTINGKRB5CONTEXT, maj_stat, GSS_S_COMPLETE); cc = -1; goto error; } /* see if this user is authorized by the krb5 client */ if (krb5_kuserok(context, (krb5_principal)client, username)) str_equal = 1; } /* Users from Kerberos cross-authenticated realms will not match, so we manually compare the user names */ if (!str_equal) { char *s; if ((s=strchr((char *)client_name.value, '@'))) str_equal = !strncmp(username, (char *)client_name.value, s-(char *)client_name.value); } #endif if (!str_equal) { char buf[1024]; snprintf(buf, sizeof(buf), MSG_GSS_CLIENTNAMEXDOESNOTMATCHUNAMEY_SS, (int)client_name.length, (char *)client_name.value, username); gsslib_print_error(buf); cc = 5; goto error; } } #ifdef DCE while (delegated_cred) { sec_login_handle_t login_context; error_status_t st; dce_error_string_t err_string; int lst; sec_login_auth_src_t auth_src=NULL; boolean32 reset_passwd=0; char errbuf[1024]; unsigned32 num_groups=0; signed32 *groups=NULL; unsigned32 flags; maj_stat = gssdce_set_cred_context_ownership(&min_stat, delegated_cred, GSSDCE_C_OWNERSHIP_APPLICATION); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GSSDCESETCREDCONTEXTOWNERSHIP, maj_stat, min_stat); break; } #if 0 gsslib_print_error(MSG_GSS_PRINTERROR_CREDENTIALDUMP); gsslib_print_error(dump_cred(delegated_cred)); #endif maj_stat = gssdce_cred_to_login_context(&min_stat, delegated_cred, &login_context); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GSSDCECREDTOLOGINCONTEXT, maj_stat, min_stat); break; } #ifdef TURN_OFF_DELEGATION { sec_login_handle_t *new_login_context; new_login_context = sec_login_disable_delegation(login_context, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &lst); snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_COULDNOTDISABLEDELEGATIONX_S, err_string); gsslib_print_error(errbuf); } else { login_context = *new_login_context; } } #endif flags = sec_login_get_context_flags(login_context, &st); sec_login_set_context_flags(login_context, flags & ~sec_login_credentials_private, &st); if (!sec_login_certify_identity(login_context, &st)) { dce_error_inq_text(st, err_string, &lst); snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_COULDNOTCERTIFYIDENTITYX_S, err_string); gsslib_print_error(errbuf); break; } sec_login_set_context(login_context, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &lst); snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_COULDNOTSETUPLOGINCONTEXTX_S, err_string); gsslib_print_error(errbuf); break; } { char *cp; cp = getenv("KRB5CCNAME"); if (cp) { snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_NEWKRB5CCNAMEISX_S , cp); gsslib_print_error(errbuf); } else { gsslib_print_error(MSG_GSS_PRINTERROR_KRB5CCNAMENOTFOUND ); } } break; } #endif /* DCE */ error: if (client) { maj_stat = gss_release_name(&min_stat, &client); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_RELEASINGNAME, maj_stat, min_stat); cc = -1; } } if (send_tok.length) (void) gss_release_buffer(&min_stat, &send_tok); if (client_name.length) (void) gss_release_buffer(&min_stat, &client_name); return cc; }
/* * Try krb5 authentication. server_user is passed for logging purposes * only, in auth is received ticket, in client is returned principal * from the ticket */ int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client) { krb5_error_code problem; krb5_principal server; krb5_data reply; krb5_ticket *ticket; int fd, ret; ret = 0; server = NULL; ticket = NULL; reply.length = 0; problem = krb5_init(authctxt); if (problem) goto err; problem = krb5_auth_con_init(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx); if (problem) goto err; fd = packet_get_connection_in(); #ifdef HEIMDAL problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, &fd); #else problem = krb5_auth_con_genaddrs(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,fd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR | KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR); #endif if (problem) goto err; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL , KRB5_NT_SRV_HST, &server); if (problem) goto err; problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, auth, server, NULL, NULL, &ticket); if (problem) goto err; #ifdef HEIMDAL problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, &authctxt->krb5_user); #else problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->enc_part2->client, &authctxt->krb5_user); #endif if (problem) goto err; /* if client wants mutual auth */ problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, &reply); if (problem) goto err; /* Check .k5login authorization now. */ if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name)) goto err; if (client) krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, client); packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); packet_put_string((char *) reply.data, reply.length); packet_send(); packet_write_wait(); ret = 1; err: if (server) krb5_free_principal(authctxt->krb5_ctx, server); if (ticket) krb5_free_ticket(authctxt->krb5_ctx, ticket); if (reply.length) xfree(reply.data); if (problem) { if (authctxt->krb5_ctx != NULL) debug("Kerberos v5 authentication failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); else debug("Kerberos v5 authentication failed: %d", problem); } return (ret); }
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 void do_krb_login(int f, char *host_addr, char *hostname, krb5_context krb_context, int encr_flag, krb5_keytab keytab) { krb5_error_code status; uint_t valid_checksum; krb5_ticket *ticket = NULL; int auth_sys = 0; int auth_sent = 0; krb5_principal client = NULL; if (getuid()) fatal(f, "Error authorizing KRB5 connection, " "server lacks privilege"); status = recvauth(f, krb_context, &valid_checksum, &ticket, &auth_sys, &client, encr_flag, keytab); if (status) { if (ticket) krb5_free_ticket(krb_context, ticket); if (status != 255) syslog(LOG_ERR, "Authentication failed from %s(%s): %s\n", host_addr, hostname, error_message(status)); fatal(f, "Kerberos authentication failed, exiting"); } if (auth_sys != KRB5_RECVAUTH_V5) { fatal(f, "This server only supports Kerberos V5"); } else { /* * Authenticated OK, now check authorization. */ if (client && krb5_kuserok(krb_context, client, lusername)) auth_sent = KRB5_RECVAUTH_V5; } if (auth_sent == KRB5_RECVAUTH_V5 && kcmd_protocol == KCMD_OLD_PROTOCOL && chksum_flag == CHKSUM_REQUIRED && !valid_checksum) { syslog(LOG_ERR, "Client did not supply required checksum, " "connection rejected."); fatal(f, "Client did not supply required checksum, " "connection rejected."); } if (auth_sys != auth_sent) { char *msg_fail = NULL; int msgsize = 0; if (ticket) krb5_free_ticket(krb_context, ticket); if (krusername != NULL) { /* * msgsize must be enough to hold * krusername, lusername and a brief * message describing the failure. */ msgsize = strlen(krusername) + strlen(lusername) + 80; msg_fail = (char *)malloc(msgsize); } if (msg_fail == NULL) { syslog(LOG_ERR, "User is not authorized to login to " "specified account"); fatal(f, "User is not authorized to login to " "specified account"); } if (auth_sent != 0) (void) snprintf(msg_fail, msgsize, "Access denied because of improper " "KRB5 credentials"); else (void) snprintf(msg_fail, msgsize, "User %s is not authorized to login " "to account %s", krusername, lusername); syslog(LOG_ERR, "%s", msg_fail); fatal(f, msg_fail); } }
static int proto (int sock, const char *svc) { krb5_auth_context auth_context; krb5_error_code status; krb5_principal server; krb5_ticket *ticket; char *name; char ret_string[10]; char hostname[MAXHOSTNAMELEN]; krb5_data data; krb5_data remotename; krb5_data tk_file; krb5_ccache ccache; char ccname[MAXPATHLEN]; struct passwd *pwd; status = krb5_auth_con_init (context, &auth_context); if (status) krb5_err(context, 1, status, "krb5_auth_con_init"); status = krb5_auth_con_setaddrs_from_fd (context, auth_context, &sock); if (status) krb5_err(context, 1, status, "krb5_auth_con_setaddr"); if(gethostname (hostname, sizeof(hostname)) < 0) krb5_err(context, 1, errno, "gethostname"); status = krb5_sname_to_principal (context, hostname, svc, KRB5_NT_SRV_HST, &server); if (status) krb5_err(context, 1, status, "krb5_sname_to_principal"); status = krb5_recvauth_match_version (context, &auth_context, &sock, kfd_match_version, NULL, server, 0, NULL, &ticket); if (status) krb5_err(context, 1, status, "krb5_recvauth"); status = krb5_unparse_name (context, ticket->client, &name); if (status) krb5_err(context, 1, status, "krb5_unparse_name"); if(protocol_version == 0) { data.data = "old clnt"; /* XXX old clients only had room for 10 bytes of message, and also didn't show it to the user */ data.length = strlen(data.data) + 1; krb5_write_message(context, &sock, &data); sleep(2); /* XXX give client time to finish */ krb5_errx(context, 1, "old client; exiting"); } status=krb5_read_priv_message (context, auth_context, &sock, &remotename); if (status) krb5_err(context, 1, status, "krb5_read_message"); status=krb5_read_priv_message (context, auth_context, &sock, &tk_file); if (status) krb5_err(context, 1, status, "krb5_read_message"); krb5_data_zero (&data); if(((char*)remotename.data)[remotename.length-1] != '\0') krb5_errx(context, 1, "unterminated received"); if(((char*)tk_file.data)[tk_file.length-1] != '\0') krb5_errx(context, 1, "unterminated received"); status = krb5_read_priv_message(context, auth_context, &sock, &data); if (status) { krb5_err(context, 1, errno, "krb5_read_priv_message"); goto out; } pwd = getpwnam ((char *)(remotename.data)); if (pwd == NULL) { status=1; krb5_warnx(context, "getpwnam: %s failed",(char *)(remotename.data)); goto out; } if(!krb5_kuserok (context, ticket->client, (char *)(remotename.data))) { status=1; krb5_warnx(context, "krb5_kuserok: permission denied"); goto out; } if (setgid(pwd->pw_gid) < 0) { krb5_warn(context, errno, "setgid"); goto out; } if (setuid(pwd->pw_uid) < 0) { krb5_warn(context, errno, "setuid"); goto out; } if (tk_file.length != 1) snprintf (ccname, sizeof(ccname), "%s", (char *)(tk_file.data)); else snprintf (ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid); status = krb5_cc_resolve (context, ccname, &ccache); if (status) { krb5_warn(context, status, "krb5_cc_resolve"); goto out; } status = krb5_cc_initialize (context, ccache, ticket->client); if (status) { krb5_warn(context, status, "krb5_cc_initialize"); goto out; } status = krb5_rd_cred2 (context, auth_context, ccache, &data); krb5_cc_close (context, ccache); if (status) { krb5_warn(context, status, "krb5_rd_cred"); goto out; } strlcpy(krb5_tkfile,ccname,sizeof(krb5_tkfile)); krb5_warnx(context, "%s forwarded ticket to %s,%s", name, (char *)(remotename.data),ccname); out: if (status) { strlcpy(ret_string, "no", sizeof(ret_string)); krb5_warnx(context, "failed"); } else { strlcpy(ret_string, "ok", sizeof(ret_string)); } krb5_data_free (&tk_file); krb5_data_free (&remotename); krb5_data_free (&data); free(name); data.data = ret_string; data.length = strlen(ret_string) + 1; status = krb5_write_priv_message(context, auth_context, &sock, &data); krb5_auth_con_free(context, auth_context); return status; }
/* * Try krb5 authentication. server_user is passed for logging purposes * only, in auth is received ticket, in client is returned principal * from the ticket */ int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *reply) { krb5_error_code problem; krb5_principal server; krb5_ticket *ticket; int fd, ret; const char *errtxt; ret = 0; server = NULL; ticket = NULL; reply->length = 0; problem = krb5_init(authctxt); if (problem) goto err; problem = krb5_auth_con_init(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx); if (problem) goto err; fd = packet_get_connection_in(); problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, &fd); if (problem) goto err; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, KRB5_NT_SRV_HST, &server); if (problem) goto err; problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, auth, server, NULL, NULL, &ticket); if (problem) goto err; problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, &authctxt->krb5_user); if (problem) goto err; /* if client wants mutual auth */ problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, reply); if (problem) goto err; /* Check .k5login authorization now. */ if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name)) goto err; if (client) krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, client); ret = 1; err: if (server) krb5_free_principal(authctxt->krb5_ctx, server); if (ticket) krb5_free_ticket(authctxt->krb5_ctx, ticket); if (!ret && reply->length) { free(reply->data); memset(reply, 0, sizeof(*reply)); } if (problem) { errtxt = NULL; if (authctxt->krb5_ctx != NULL) errtxt = krb5_get_error_message(authctxt->krb5_ctx, problem); if (errtxt != NULL) { debug("Kerberos v5 authentication failed: %s", errtxt); krb5_free_error_message(authctxt->krb5_ctx, errtxt); } else debug("Kerberos v5 authentication failed: %d", problem); } return (ret); }
int auth_krb5_password(Authctxt *authctxt, const char *password) { #ifndef HEIMDAL krb5_creds creds; krb5_principal server; char ccname[40]; int tmpfd; mode_t old_umask; #endif krb5_error_code problem; krb5_ccache ccache = NULL; int len; if (!authctxt->valid) return (0); temporarily_use_uid(authctxt->pw); problem = krb5_init(authctxt); if (problem) goto out; problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, &authctxt->krb5_user); if (problem) goto out; #ifdef HEIMDAL problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto out; restore_uid(); problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, ccache, password, 1, NULL); temporarily_use_uid(authctxt->pw); if (problem) goto out; problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, authctxt->krb5_fwd_ccache); krb5_cc_destroy(authctxt->krb5_ctx, ccache); ccache = NULL; if (problem) goto out; #else problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); if (problem) goto out; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, KRB5_NT_SRV_HST, &server); if (problem) goto out; restore_uid(); problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, NULL, NULL, NULL); krb5_free_principal(authctxt->krb5_ctx, server); temporarily_use_uid(authctxt->pw); if (problem) goto out; if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name)) { problem = -1; goto out; } snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid()); old_umask = umask(0177); tmpfd = mkstemp(ccname + strlen("FILE:")); umask(old_umask); if (tmpfd == -1) { logit("mkstemp(): %.100s", strerror(errno)); problem = errno; goto out; } if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { logit("fchmod(): %.100s", strerror(errno)); close(tmpfd); problem = errno; goto out; } close(tmpfd); problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, authctxt->krb5_user); if (problem) goto out; problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, &creds); if (problem) goto out; #endif authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); len = strlen(authctxt->krb5_ticket_file) + 6; authctxt->krb5_ccname = xmalloc(len); snprintf(authctxt->krb5_ccname, len, "FILE:%s", authctxt->krb5_ticket_file); out: restore_uid(); if (problem) { if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); if (authctxt->krb5_ctx != NULL && problem!=-1) debug("Kerberos password authentication failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); else debug("Kerberos password authentication failed: %d", problem); krb5_cleanup_proc(authctxt); if (options.kerberos_or_local_passwd) return (-1); else return (0); } return (1); }
static int gss_loop(POP *p, void *state, /* const */ void *input, size_t input_length, void **output, size_t *output_length) { struct gss_state *gs = state; gss_buffer_desc real_input_token, real_output_token; gss_buffer_t input_token = &real_input_token, output_token = &real_output_token; OM_uint32 maj_stat, min_stat; gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS; if(gs->stage == 0) { /* we require an initial response, so ask for one if not present */ gs->stage++; if(input == NULL && input_length == 0) { /* XXX this could be done better */ fputs("+ \r\n", p->output); fflush(p->output); return POP_AUTH_CONTINUE; } } if(gs->stage == 1) { input_token->value = input; input_token->length = input_length; maj_stat = gss_accept_sec_context (&min_stat, &gs->context_hdl, GSS_C_NO_CREDENTIAL, input_token, bindings, &gs->client_name, &gs->mech_oid, output_token, NULL, NULL, NULL); if (GSS_ERROR(maj_stat)) { gss_set_error(gs, min_stat); return POP_AUTH_FAILURE; } if (output_token->length != 0) { *output = output_token->value; *output_length = output_token->length; } if(maj_stat == GSS_S_COMPLETE) gs->stage++; return POP_AUTH_CONTINUE; } if(gs->stage == 2) { /* send wanted protection levels */ unsigned char x[4] = { 1, 0, 0, 0 }; input_token->value = x; input_token->length = 4; maj_stat = gss_wrap(&min_stat, gs->context_hdl, FALSE, GSS_C_QOP_DEFAULT, input_token, NULL, output_token); if (GSS_ERROR(maj_stat)) { gss_set_error(gs, min_stat); return POP_AUTH_FAILURE; } *output = output_token->value; *output_length = output_token->length; gs->stage++; return POP_AUTH_CONTINUE; } if(gs->stage == 3) { /* receive protection levels and username */ char *name; krb5_principal principal; gss_buffer_desc export_name; gss_OID oid; unsigned char *ptr; input_token->value = input; input_token->length = input_length; maj_stat = gss_unwrap (&min_stat, gs->context_hdl, input_token, output_token, NULL, NULL); if (GSS_ERROR(maj_stat)) { gss_set_error(gs, min_stat); return POP_AUTH_FAILURE; } if(output_token->length < 5) { pop_auth_set_error("response too short"); return POP_AUTH_FAILURE; } ptr = output_token->value; if(ptr[0] != 1) { pop_auth_set_error("must use clear text"); return POP_AUTH_FAILURE; } memmove(output_token->value, ptr + 4, output_token->length - 4); ptr[output_token->length - 4] = '\0'; maj_stat = gss_display_name(&min_stat, gs->client_name, &export_name, &oid); if(maj_stat != GSS_S_COMPLETE) { gss_set_error(gs, min_stat); return POP_AUTH_FAILURE; } /* XXX kerberos */ if(oid != GSS_KRB5_NT_PRINCIPAL_NAME) { pop_auth_set_error("unexpected gss name type"); gss_release_buffer(&min_stat, &export_name); return POP_AUTH_FAILURE; } name = malloc(export_name.length + 1); if(name == NULL) { pop_auth_set_error("out of memory"); gss_release_buffer(&min_stat, &export_name); return POP_AUTH_FAILURE; } memcpy(name, export_name.value, export_name.length); name[export_name.length] = '\0'; gss_release_buffer(&min_stat, &export_name); krb5_parse_name(gssapi_krb5_context, name, &principal); if(!krb5_kuserok(gssapi_krb5_context, principal, ptr)) { pop_auth_set_error("Permission denied"); return POP_AUTH_FAILURE; } strlcpy(p->user, ptr, sizeof(p->user)); return POP_AUTH_COMPLETE; } return POP_AUTH_FAILURE; }