static int pg_krb5_init(void) { krb5_error_code retval; char *khostname; if (pg_krb5_initialised) return STATUS_OK; retval = krb5_init_context(&pg_krb5_context); if (retval) { ereport(LOG, (errmsg("Kerberos initialization returned error %d", retval))); com_err("postgres", retval, "while initializing krb5"); return STATUS_ERROR; } retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab); if (retval) { ereport(LOG, (errmsg("Kerberos keytab resolving returned error %d", retval))); com_err("postgres", retval, "while resolving keytab file \"%s\"", pg_krb_server_keyfile); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } /* * If no hostname was specified, pg_krb_server_hostname is already NULL. * If it's set to blank, force it to NULL. */ khostname = pg_krb_server_hostname; if (khostname && khostname[0] == '\0') khostname = NULL; retval = krb5_sname_to_principal(pg_krb5_context, khostname, pg_krb_srvnam, KRB5_NT_SRV_HST, &pg_krb5_server); if (retval) { ereport(LOG, (errmsg("Kerberos sname_to_principal(\"%s\", \"%s\") returned error %d", khostname ? khostname : "server hostname", pg_krb_srvnam, retval))); com_err("postgres", retval, "while getting server principal for server \"%s\" for service \"%s\"", khostname ? khostname : "server hostname", pg_krb_srvnam); krb5_kt_close(pg_krb5_context, pg_krb5_keytab); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } pg_krb5_initialised = 1; return STATUS_OK; }
int main(int argc, char **argv) { krb5_principal princ; krb5_int32 type; const char *service, *hostname; char *name; /* Parse arguments. */ assert(argc == 4); hostname = argv[1]; service = argv[2]; if (strcmp(argv[3], "unknown") == 0) type = KRB5_NT_UNKNOWN; else if (strcmp(argv[3], "srv-hst") == 0) type = KRB5_NT_SRV_HST; else abort(); check(krb5_init_context(&ctx)); check(krb5_sname_to_principal(ctx, hostname, service, type, &princ)); check(krb5_unparse_name(ctx, princ, &name)); printf("%s\n", name); krb5_free_unparsed_name(ctx, name); krb5_free_principal(ctx, princ); krb5_free_context(ctx); return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_validated_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *service) { krb5_verify_init_creds_opt vopt; krb5_principal server; krb5_error_code ret; if (krb5_principal_compare(context, creds->client, client) != TRUE) { krb5_set_error_message(context, KRB5_PRINC_NOMATCH, N_("Validation credentials and client " "doesn't match", "")); return KRB5_PRINC_NOMATCH; } ret = krb5_sname_to_principal (context, NULL, service, KRB5_NT_SRV_HST, &server); if(ret) return ret; krb5_verify_init_creds_opt_init(&vopt); ret = krb5_verify_init_creds(context, creds, server, NULL, NULL, &vopt); krb5_free_principal(context, server); return ret; }
static void get_creds(krb5_context context, const char *keytab_str, krb5_ccache *cache, const char *serverhost) { krb5_keytab keytab; krb5_principal client; krb5_error_code ret; krb5_get_init_creds_opt *init_opts; krb5_creds creds; char *server; char keytab_buf[256]; int aret; if (keytab_str == NULL) { ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); if (ret) krb5_err (context, 1, ret, "krb5_kt_default_name"); keytab_str = keytab_buf; } ret = krb5_kt_resolve(context, keytab_str, &keytab); if(ret) krb5_err(context, 1, ret, "%s", keytab_str); ret = krb5_sname_to_principal (context, slave_str, IPROP_NAME, KRB5_NT_SRV_HST, &client); if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); aret = asprintf (&server, "%s/%s", IPROP_NAME, serverhost); if (aret == -1 || server == NULL) krb5_errx (context, 1, "malloc: no memory"); ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, server, init_opts); free (server); krb5_get_init_creds_opt_free(context, init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, *cache, client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred(context, *cache, &creds); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents(context, &creds); krb5_free_principal(context, client); }
void kerberos5_forward(kstream ks) { krb5_error_code r; krb5_ccache ccache; krb5_principal client = 0; krb5_principal server = 0; krb5_data forw_creds; forw_creds.data = 0; if ((r = krb5_cc_default(k5_context, &ccache))) { com_err(NULL, r, "Kerberos V5: could not get default ccache"); return; } if ((r = krb5_cc_get_principal(k5_context, ccache, &client))) { com_err(NULL, r, "Kerberos V5: could not get default principal"); goto cleanup; } if ((r = krb5_sname_to_principal(k5_context, szHostName, KRB_SERVICE_NAME, KRB5_NT_SRV_HST, &server))) { com_err(NULL, r, "Kerberos V5: could not make server principal"); goto cleanup; } if ((r = krb5_auth_con_genaddrs(k5_context, auth_context, ks->fd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) { com_err(NULL, r, "Kerberos V5: could not gen local full address"); goto cleanup; } if (r = krb5_fwd_tgt_creds(k5_context, auth_context, 0, client, server, ccache, forwardable_flag, &forw_creds)) { com_err(NULL, r, "Kerberos V5: error getting forwarded creds"); goto cleanup; } /* Send forwarded credentials */ if (!Data(ks, KRB_FORWARD, forw_creds.data, forw_creds.length)) { MessageBox(HWND_DESKTOP, "Not enough room for authentication data", "", MB_OK | MB_ICONEXCLAMATION); } cleanup: if (client) krb5_free_principal(k5_context, client); if (server) krb5_free_principal(k5_context, server); #if 0 /* XXX */ if (forw_creds.data) free(forw_creds.data); #endif krb5_cc_close(k5_context, ccache); }
int kssl_keytab_is_available(KSSL_CTX *kssl_ctx) { krb5_context krb5context = NULL; krb5_keytab krb5keytab = NULL; krb5_keytab_entry entry; krb5_principal princ = NULL; krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; int rc = 0; if ((krb5rc = krb5_init_context(&krb5context))) return (0); /* kssl_ctx->keytab_file == NULL ==> use Kerberos default */ if (kssl_ctx->keytab_file) { krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file, &krb5keytab); if (krb5rc) goto exit; } else { krb5rc = krb5_kt_default(krb5context, &krb5keytab); if (krb5rc) goto exit; } /* the host key we are looking for */ krb5rc = krb5_sname_to_principal(krb5context, NULL, kssl_ctx->service_name ? kssl_ctx->service_name : KRB5SVC, KRB5_NT_SRV_HST, &princ); if (krb5rc) goto exit; krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, princ, 0 /* IGNORE_VNO */, 0 /* IGNORE_ENCTYPE */, &entry); if (krb5rc == KRB5_KT_NOTFOUND) { rc = 1; goto exit; } else if (krb5rc) goto exit; krb5_kt_free_entry(krb5context, &entry); rc = 1; exit: if (krb5keytab) krb5_kt_close(krb5context, krb5keytab); if (princ) krb5_free_principal(krb5context, princ); if (krb5context) krb5_free_context(krb5context); return (rc); }
static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) { PyKAdminObject *kadmin = PyKAdminObject_create(); PyObject *db_args_dict = NULL; kadm5_ret_t retval = KADM5_OK; krb5_error_code code = 0; krb5_principal princ = NULL; char *client_name = NULL; char *keytab_name = NULL; char **db_args = NULL; kadm5_config_params *params = calloc(0x1, sizeof(kadm5_config_params)); if (!PyArg_ParseTuple(args, "|zzO!", &client_name, &keytab_name, &PyDict_Type, &db_args_dict)) return NULL; db_args = _kadmin_dict_to_db_args(db_args_dict); if (keytab_name == NULL) { keytab_name = "/etc/krb5.keytab"; } if (client_name == NULL) { code = krb5_sname_to_principal(kadmin->context, NULL, "host", KRB5_NT_SRV_HST, &princ); if (code) { PyKAdmin_RETURN_ERROR(code, "krb5_sname_to_principal"); } code = krb5_unparse_name(kadmin->context, princ, &client_name); if (code) { PyKAdmin_RETURN_ERROR(code, "krb5_unparse_name"); } krb5_free_principal(kadmin->context, princ); } retval = kadm5_init_with_skey( kadmin->context, client_name, keytab_name, service_name, params, struct_version, api_version, db_args, &kadmin->server_handle); if (db_args) _kadmin_free_db_args(db_args); if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_init_with_skey"); } Py_XINCREF(kadmin); return kadmin; }
static int do_v5 (const char *host, int port, const char *user, const char *filename, const char *header_str, int leavep, int verbose, int forkp) { krb5_error_code ret; krb5_auth_context auth_context = NULL; krb5_principal server; const char *estr; int s; s = do_connect (host, port, 1); if (s < 0) return 1; ret = krb5_sname_to_principal (context, host, "pop", KRB5_NT_SRV_HST, &server); if (ret) { estr = krb5_get_error_message(context, ret); warnx ("krb5_sname_to_principal: %s", estr); krb5_free_error_message(context, estr); return 1; } ret = krb5_sendauth (context, &auth_context, &s, "KPOPV1.0", NULL, server, 0, NULL, NULL, NULL, NULL, NULL, NULL); krb5_free_principal (context, server); if (ret) { estr = krb5_get_error_message(context, ret); warnx ("krb5_sendauth: %s", estr); krb5_free_error_message(context, estr); return 1; } return doit (s, host, user, filename, header_str, leavep, verbose, forkp); }
int kssl_tgt_is_available(KSSL_CTX *kssl_ctx) { krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; krb5_context krb5context = NULL; krb5_ccache krb5ccdef = NULL; krb5_creds krb5creds, *krb5credsp = NULL; int rc = 0; memset((char *)&krb5creds, 0, sizeof(krb5creds)); if (!kssl_ctx) return (0); if (!kssl_ctx->service_host) return (0); if ((krb5rc = krb5_init_context(&krb5context)) != 0) goto err; if ((krb5rc = krb5_sname_to_principal( krb5context, kssl_ctx->service_host, (kssl_ctx->service_name) ? kssl_ctx->service_name : KRB5SVC, KRB5_NT_SRV_HST, &krb5creds.server)) != 0) goto err; if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) goto err; if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef, &krb5creds.client)) != 0) goto err; if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef, &krb5creds, &krb5credsp)) != 0) goto err; rc = 1; err: #ifdef KSSL_DEBUG kssl_ctx_show(kssl_ctx); #endif /* KSSL_DEBUG */ if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client); if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server); if (krb5context) krb5_free_context(krb5context); return (rc); }
static int pg_krb5_init(void) { krb5_error_code retval; if (pg_krb5_initialised) return STATUS_OK; retval = krb5_init_context(&pg_krb5_context); if (retval) { ereport(LOG, (errmsg("Kerberos initialization returned error %d", retval))); com_err("postgres", retval, "while initializing krb5"); return STATUS_ERROR; } retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab); if (retval) { ereport(LOG, (errmsg("Kerberos keytab resolving returned error %d", retval))); com_err("postgres", retval, "while resolving keytab file \"%s\"", pg_krb_server_keyfile); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } retval = krb5_sname_to_principal(pg_krb5_context, NULL, PG_KRB_SRVNAM, KRB5_NT_SRV_HST, &pg_krb5_server); if (retval) { ereport(LOG, (errmsg("Kerberos sname_to_principal(\"%s\") returned error %d", PG_KRB_SRVNAM, retval))); com_err("postgres", retval, "while getting server principal for service \"%s\"", PG_KRB_SRVNAM); krb5_kt_close(pg_krb5_context, pg_krb5_keytab); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } pg_krb5_initialised = 1; return STATUS_OK; }
static krb5_error_code verify_common (krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_keytab keytab, krb5_boolean secure, const char *service, krb5_creds cred) { krb5_error_code ret; krb5_principal server; krb5_verify_init_creds_opt vopt; krb5_ccache id; ret = krb5_sname_to_principal (context, NULL, service, KRB5_NT_SRV_HST, &server); if(ret) return ret; krb5_verify_init_creds_opt_init(&vopt); krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, secure); ret = krb5_verify_init_creds(context, &cred, server, keytab, NULL, &vopt); krb5_free_principal(context, server); if(ret) return ret; if(ccache == NULL) ret = krb5_cc_default (context, &id); else id = ccache; if(ret == 0){ ret = krb5_cc_initialize(context, id, principal); if(ret == 0){ ret = krb5_cc_store_cred(context, id, &cred); } if(ccache == NULL) krb5_cc_close(context, id); } krb5_free_cred_contents(context, &cred); return ret; }
OM_uint32 _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, int use_dns, krb5_const_principal sourcename, gss_name_t targetname, krb5_principal *out) { krb5_principal p = (krb5_principal)targetname; krb5_error_code ret; char *hostname = NULL, *service; *minor_status = 0; /* If its not a hostname */ if (krb5_principal_get_type(context, p) != MAGIC_HOSTBASED_NAME_TYPE) { ret = krb5_copy_principal(context, p, out); } else if (!use_dns) { ret = krb5_copy_principal(context, p, out); if (ret) goto out; krb5_principal_set_type(context, *out, KRB5_NT_SRV_HST); if (sourcename) ret = krb5_principal_set_realm(context, *out, sourcename->realm); } else { if (p->name.name_string.len == 0) return GSS_S_BAD_NAME; else if (p->name.name_string.len > 1) hostname = p->name.name_string.val[1]; service = p->name.name_string.val[0]; ret = krb5_sname_to_principal(context, hostname, service, KRB5_NT_SRV_HST, out); } out: if (ret) { *minor_status = ret; return GSS_S_FAILURE; } return 0; }
static int doit_v5 (char *host, int port) { krb5_error_code ret; krb5_context context; krb5_auth_context auth_context = NULL; krb5_principal server; int s = get_socket (host, port); ret = krb5_init_context (&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); ret = krb5_sname_to_principal (context, host, "pop", KRB5_NT_SRV_HST, &server); if (ret) { warnx ("krb5_sname_to_principal: %s", krb5_get_err_text (context, ret)); return 1; } ret = krb5_sendauth (context, &auth_context, &s, "KPOPV1.0", NULL, server, 0, NULL, NULL, NULL, NULL, NULL, NULL); if (ret) { warnx ("krb5_sendauth: %s", krb5_get_err_text (context, ret)); return 1; } loop (s); return 0; }
OM_uint32 _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, gss_const_name_t targetname, krb5_principal *out) { krb5_const_principal p = (krb5_const_principal)targetname; krb5_error_code ret; char *hostname = NULL, *service; int type; const char *comp; *minor_status = 0; /* If its not a hostname */ type = krb5_principal_get_type(context, p); comp = krb5_principal_get_comp_string(context, p, 0); if (type == KRB5_NT_SRV_HST || type == KRB5_NT_SRV_HST_NEEDS_CANON || (type == KRB5_NT_UNKNOWN && comp != NULL && strcmp(comp, "host") == 0)) { if (p->name.name_string.len == 0) return GSS_S_BAD_NAME; else if (p->name.name_string.len > 1) hostname = p->name.name_string.val[1]; service = p->name.name_string.val[0]; ret = krb5_sname_to_principal(context, hostname, service, KRB5_NT_SRV_HST, out); } else { ret = krb5_copy_principal(context, p, out); } if (ret) { *minor_status = ret; return GSS_S_FAILURE; } return 0; }
krb5_error_code KRB5_CALLCONV krb5_mk_req(krb5_context context, krb5_auth_context *auth_context, krb5_flags ap_req_options, char *service, char *hostname, krb5_data *in_data, krb5_ccache ccache, krb5_data *outbuf) { krb5_error_code retval; krb5_principal server; krb5_creds * credsp; krb5_creds creds; retval = krb5_sname_to_principal(context, hostname, service, KRB5_NT_SRV_HST, &server); if (retval) return retval; /* obtain ticket & session key */ memset((char *)&creds, 0, sizeof(creds)); if ((retval = krb5_copy_principal(context, server, &creds.server))) goto cleanup_princ; if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)) != 0) goto cleanup_creds; if ((retval = krb5_get_credentials(context, 0, ccache, &creds, &credsp)) != 0) goto cleanup_creds; retval = krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, credsp, outbuf); krb5_free_creds(context, credsp); cleanup_creds: krb5_free_cred_contents(context, &creds); cleanup_princ: krb5_free_principal(context, server); return retval; }
/* * pg_krb5_sendauth -- client routine to send authentication information to * the server */ static int pg_krb5_sendauth(PGconn *conn) { krb5_error_code retval; int ret; krb5_principal server; krb5_auth_context auth_context = NULL; krb5_error *err_ret = NULL; struct krb5_info info; info.pg_krb5_initialised = 0; if (!(conn->pghost && conn->pghost[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } ret = pg_krb5_init(&conn->errorMessage, &info); if (ret != STATUS_OK) return ret; retval = krb5_sname_to_principal(info.pg_krb5_context, conn->pghost, conn->krbsrvname, KRB5_NT_SRV_HST, &server); if (retval) { printfPQExpBuffer(&conn->errorMessage, "pg_krb5_sendauth: krb5_sname_to_principal: %s\n", error_message(retval)); pg_krb5_destroy(&info); return STATUS_ERROR; } /* * libpq uses a non-blocking socket. But kerberos needs a blocking socket, * and we have to block somehow to do mutual authentication anyway. So we * temporarily make it blocking. */ if (!pg_set_block(conn->sock)) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to blocking mode: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf))); krb5_free_principal(info.pg_krb5_context, server); pg_krb5_destroy(&info); return STATUS_ERROR; } retval = krb5_sendauth(info.pg_krb5_context, &auth_context, (krb5_pointer) & conn->sock, (char *) conn->krbsrvname, info.pg_krb5_client, server, AP_OPTS_MUTUAL_REQUIRED, NULL, 0, /* no creds, use ccache instead */ info.pg_krb5_ccache, &err_ret, NULL, NULL); if (retval) { if (retval == KRB5_SENDAUTH_REJECTED && err_ret) { #if defined(HAVE_KRB5_ERROR_TEXT_DATA) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Kerberos 5 authentication rejected: %*s\n"), (int) err_ret->text.length, err_ret->text.data); #elif defined(HAVE_KRB5_ERROR_E_DATA) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("Kerberos 5 authentication rejected: %*s\n"), (int) err_ret->e_data->length, (const char *) err_ret->e_data->data); #else #error "bogus configuration" #endif } else { printfPQExpBuffer(&conn->errorMessage, "krb5_sendauth: %s\n", error_message(retval)); } if (err_ret) krb5_free_error(info.pg_krb5_context, err_ret); ret = STATUS_ERROR; } krb5_free_principal(info.pg_krb5_context, server); if (!pg_set_noblock(conn->sock)) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not restore non-blocking mode on socket: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf))); ret = STATUS_ERROR; } pg_krb5_destroy(&info); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_verify_init_creds(krb5_context context, krb5_creds *creds, krb5_principal ap_req_server, krb5_keytab ap_req_keytab, krb5_ccache *ccache, krb5_verify_init_creds_opt *options) { krb5_error_code ret; krb5_data req; krb5_ccache local_ccache = NULL; krb5_creds *new_creds = NULL; krb5_auth_context auth_context = NULL; krb5_principal server = NULL; krb5_keytab keytab = NULL; krb5_data_zero (&req); if (ap_req_server == NULL) { char local_hostname[MAXHOSTNAMELEN]; if (gethostname (local_hostname, sizeof(local_hostname)) < 0) { ret = errno; krb5_set_error_message (context, ret, "gethostname: %s", strerror(ret)); return ret; } ret = krb5_sname_to_principal (context, local_hostname, "host", KRB5_NT_SRV_HST, &server); if (ret) goto cleanup; } else server = ap_req_server; if (ap_req_keytab == NULL) { ret = krb5_kt_default (context, &keytab); if (ret) goto cleanup; } else keytab = ap_req_keytab; if (ccache && *ccache) local_ccache = *ccache; else { ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &local_ccache); if (ret) goto cleanup; ret = krb5_cc_initialize (context, local_ccache, creds->client); if (ret) goto cleanup; ret = krb5_cc_store_cred (context, local_ccache, creds); if (ret) goto cleanup; } if (!krb5_principal_compare (context, server, creds->server)) { krb5_creds match_cred; memset (&match_cred, 0, sizeof(match_cred)); match_cred.client = creds->client; match_cred.server = server; ret = krb5_get_credentials (context, 0, local_ccache, &match_cred, &new_creds); if (ret) { if (fail_verify_is_ok (context, options)) ret = 0; goto cleanup; } creds = new_creds; } ret = krb5_mk_req_extended (context, &auth_context, 0, NULL, creds, &req); krb5_auth_con_free (context, auth_context); auth_context = NULL; if (ret) goto cleanup; ret = krb5_rd_req (context, &auth_context, &req, server, keytab, 0, NULL); if (ret == KRB5_KT_NOTFOUND && fail_verify_is_ok (context, options)) ret = 0; cleanup: if (auth_context) krb5_auth_con_free (context, auth_context); krb5_data_free (&req); if (new_creds != NULL) krb5_free_creds (context, new_creds); if (ap_req_server == NULL && server) krb5_free_principal (context, server); if (ap_req_keytab == NULL && keytab) krb5_kt_close (context, keytab); if (local_ccache != NULL && (ccache == NULL || (ret != 0 && *ccache == NULL))) krb5_cc_destroy (context, local_ccache); if (ret == 0 && ccache != NULL && *ccache == NULL) *ccache = local_ccache; return ret; }
static void add_slave (krb5_context context, krb5_keytab keytab, slave **root, int fd) { krb5_principal server; krb5_error_code ret; slave *s; socklen_t addr_len; krb5_ticket *ticket = NULL; char hostname[128]; s = malloc(sizeof(*s)); if (s == NULL) { krb5_warnx (context, "add_slave: no memory"); return; } s->name = NULL; s->ac = NULL; addr_len = sizeof(s->addr); s->fd = accept (fd, (struct sockaddr *)&s->addr, &addr_len); if (s->fd < 0) { krb5_warn (context, errno, "accept"); goto error; } gethostname(hostname, sizeof(hostname)); ret = krb5_sname_to_principal (context, hostname, IPROP_NAME, KRB5_NT_SRV_HST, &server); if (ret) { krb5_warn (context, ret, "krb5_sname_to_principal"); goto error; } ret = krb5_recvauth (context, &s->ac, &s->fd, IPROP_VERSION, server, 0, keytab, &ticket); krb5_free_principal (context, server); if (ret) { krb5_warn (context, ret, "krb5_recvauth"); goto error; } ret = krb5_unparse_name (context, ticket->client, &s->name); if (ret) { krb5_warn (context, ret, "krb5_unparse_name"); goto error; } if (check_acl (context, s->name)) { krb5_warnx (context, "%s not in acl", s->name); goto error; } krb5_free_ticket (context, ticket); ticket = NULL; { slave *l = *root; while (l) { if (strcmp(l->name, s->name) == 0) break; l = l->next; } if (l) { if (l->flags & SLAVE_F_DEAD) { remove_slave(context, l, root); } else { krb5_warnx (context, "second connection from %s", s->name); goto error; } } } krb5_warnx (context, "connection from %s", s->name); s->version = 0; s->flags = 0; slave_seen(s); s->next = *root; *root = s; return; error: remove_slave(context, s, root); }
static void get_tickets(krb5_context context) { char *def_realm, *server; krb5_error_code retval; krb5_keytab keytab = NULL; krb5_principal server_princ = NULL; /* Figure out what tickets we'll be using to send. */ retval = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST, &my_principal); if (retval) { com_err(progname, errno, _("while setting client principal name")); exit(1); } if (realm != NULL) { retval = krb5_set_principal_realm(context, my_principal, realm); if (retval) { com_err(progname, errno, _("while setting client principal realm")); exit(1); } } else if (krb5_is_referral_realm(krb5_princ_realm(context, my_principal))) { /* We're going to use this as a client principal, so it can't have the * referral realm. Use the default realm instead. */ retval = krb5_get_default_realm(context, &def_realm); if (retval) { com_err(progname, errno, _("while getting default realm")); exit(1); } retval = krb5_set_principal_realm(context, my_principal, def_realm); if (retval) { com_err(progname, errno, _("while setting client principal realm")); exit(1); } } /* Construct the principal name for the slave host. */ memset(&creds, 0, sizeof(creds)); retval = krb5_sname_to_principal(context, slave_host, KPROP_SERVICE_NAME, KRB5_NT_SRV_HST, &server_princ); if (retval) { com_err(progname, errno, _("while setting server principal name")); exit(1); } retval = krb5_unparse_name_flags(context, server_princ, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server); if (retval) { com_err(progname, retval, _("while unparsing server name")); exit(1); } /* Fill in the client. */ retval = krb5_copy_principal(context, my_principal, &creds.client); if (retval) { com_err(progname, retval, _("while copying client principal")); exit(1); } if (srvtab != NULL) { retval = krb5_kt_resolve(context, srvtab, &keytab); if (retval) { com_err(progname, retval, _("while resolving keytab")); exit(1); } } retval = krb5_get_init_creds_keytab(context, &creds, my_principal, keytab, 0, server, NULL); if (retval) { com_err(progname, retval, _("while getting initial credentials\n")); exit(1); } if (keytab != NULL) krb5_kt_close(context, keytab); krb5_free_unparsed_name(context, server); krb5_free_principal(context, server_princ); }
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; }
/* * Store the given private key (key) and certificate (cert) * into the Kerberos 5 credentials cache. The "lifetime" * of the certificate is also given in notBefore, and notAfter. */ int store_in_cc(RSA *key, BYTE *cert, DWORD cert_length, char *realm, ASN1_UTCTIME *notBefore, ASN1_UTCTIME *notAfter, #if defined(KX509_LIB) char *tkt_cache_name, #endif char **err_msg) { krb5_context k5_context; krb5_ccache cc; krb5_creds fake_creds; DWORD key_length; krb5_error_code k5_rc = 0; int retcode = KX509_STATUS_GOOD; BYTE *ptr = NULL; BYTE *memptr = NULL; /* * Use fake_creds.ticket for private key and * fake_creds.second_ticket for certificate */ memset(&fake_creds, '\0', sizeof(fake_creds)); if (k5_rc = krb5_init_context(&k5_context)) { log_printf("store_in_cc: unable to initialize Kerberos 5 context (%d)\n", k5_rc); *err_msg = "Error initializing kerberos 5 environment."; return KX509_STATUS_CLNT_FIX; } #if 0 /* DON'T NEED THIS, and it is a private function anyway... */ if (k5_rc = krb5_set_default_realm(k5_context, realm)) { log_printf("store_in_cc: failed to malloc space for k5 default_realm\n"); *err_msg = "Try re-authenticating. " "Hopefully temporary client-side problem"; return KX509_STATUS_CLNT_FIX; } #endif #if defined(KX509_LIB) if (k5_rc = krb5_cc_resolve(k5_context, tkt_cache_name, &cc)) { log_printf("store_in_cc: failed to resolve credential cache (%d)\n", k5_rc); *err_msg = "Try re-authenticating. " "Could not resolve your credential cache name."; return KX509_STATUS_CLNT_FIX; } #else if (k5_rc = krb5_cc_default(k5_context, &cc)) { log_printf("store_in_cc: failed to resolve credential cache (%d)\n", k5_rc); *err_msg = "Try re-authenticating. " "Could not resolve your credential cache name."; return KX509_STATUS_CLNT_FIX; } #endif #if defined(HAVE_HEIMDAL) if (k5_rc = krb5_make_principal(k5_context, &fake_creds.server, realm, KX509_CC_PRINCIPAL, KX509_CC_INSTANCE, NULL)) #else if (k5_rc = krb5_sname_to_principal(k5_context, KX509_CC_INSTANCE, KX509_CC_PRINCIPAL, KRB5_NT_UNKNOWN, &fake_creds.server)) #endif { log_printf("store_in_cc: unable to create server principal from sname (%d)\n", k5_rc); *err_msg = "Internal error with kerberos while creating fake server principal."; retcode = KX509_STATUS_CLNT_FIX; goto close_and_return; } #if defined(CC_REMOVE_IMPLEMENTED) /* * We really want to clear out any old private key/certificate entries * from the credentials cache. However, the function to do that is * not defined... */ if (k5_rc = kx509_clear_old_certificates(k5_context, cc, fake_creds)) { log_printf("store_in_cc: couldn't clear out old certificate " "from cred cache (%d)\n", k5_rc); *err_msg = "Error removing old certificate from your kerberos credentials cache."; retcode = KX509_STATUS_CLNT_FIX; goto close_and_return; } #endif /* CC_REMOVE_IMPLEMENTED */ if (k5_rc = krb5_cc_get_principal(k5_context, cc, &fake_creds.client)) { log_printf("store_in_cc: unable to create client principal from sname (%d)\n", k5_rc); *err_msg = "Internal error with kerberos while creating fake client principal."; retcode = KX509_STATUS_CLNT_FIX; goto close_and_return; } /* * Get the DER-encoded length of the private key. * Allocate storage to hold the private key and certificate. */ key_length = i2d_RSAPrivateKey(key, NULL); /* Get DER-encoded len of Private Key */ if (key_length <= 0) { log_printf("store_in_cc: unable to determine length of " "encoded private key (%d)\n", key_length); *err_msg = "Error determining encoded length of private key."; retcode = KX509_STATUS_CLNT_FIX; goto close_and_return; } ptr = Malloc(key_length + cert_length); if (!ptr) { log_printf("store_in_cc: error allocating %d bytes for " "private key (%d) and certificate (%d)\n", key_length+cert_length, key_length, cert_length); *err_msg = "Error allocating storage for private key and certificate."; retcode = KX509_STATUS_CLNT_FIX; goto close_and_return; } memptr = ptr; /* Save a ptr to the allocated area for later when we free it */ fake_creds.ticket.data = (char *)ptr; fake_creds.ticket.length = i2d_RSAPrivateKey(key, &ptr); /* Note that i2d_RSAPrivateKey() updates ptr!!! */ memcpy(ptr, cert, cert_length); fake_creds.second_ticket.data = (char *)ptr; fake_creds.second_ticket.length = cert_length; /* Set up the ticket lifetime according to the certificate lifetime */ fake_creds.times.starttime = utc2unix(notBefore, NULL); fake_creds.times.endtime = utc2unix(notAfter, NULL); /* * Store the fake ticket (containing the private key * and certificate) into the credentials cache. */ #if defined(WRITE_CERT) /* Write the key-pair and certificate to file (code lifted from kxlist -p) */ if (k5_rc = materialize_cert(k5_context, cc, &fake_creds)) #else /* WRITE_CERT */ /* Store the key-pair and certificate into the K5 credentials cache as a mock ticket */ if (k5_rc = krb5_cc_store_cred(k5_context, cc, &fake_creds)) #endif /* WRITE_CERT */ { log_printf("store_in_cc: krb5_cc_store_cred returned %0d\n", k5_rc); *err_msg = "Try re-authenticating. " "Currently unable to write your Kerberos credentials cache."; retcode = KX509_STATUS_CLNT_FIX; goto close_and_return; } close_and_return: if (memptr) { Free(memptr); memptr = NULL; } krb5_cc_close(k5_context, cc); /* ignore return code from close */ return(retcode); }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_auth_context auth_context; void *kadm_handle; kadm5_server_context *server_context; kadm5_config_params conf; int master_fd; krb5_ccache ccache; krb5_principal server; char **files; int optidx = 0; time_t reconnect_min; time_t backoff; time_t reconnect_max; time_t reconnect; time_t before = 0; const char *master; setprogname(argv[0]); if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); if(version_flag) { print_version(NULL); exit(0); } ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); setup_signal(); if (config_file == NULL) { asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); if (config_file == NULL) errx(1, "out of memory"); } ret = krb5_prepend_config_files_default(config_file, &files); if (ret) krb5_err(context, 1, ret, "getting configuration files"); ret = krb5_set_config_files(context, files); krb5_free_config_files(files); if (ret) krb5_err(context, 1, ret, "reading configuration files"); argc -= optidx; argv += optidx; if (argc != 1) usage(1); master = argv[0]; #ifdef SUPPORT_DETACH if (detach_from_console) daemon(0, 0); #endif pidfile (NULL); krb5_openlog (context, "ipropd-slave", &log_facility); krb5_set_warn_dest(context, log_facility); ret = krb5_kt_register(context, &hdb_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); time_before_lost = parse_time (server_time_lost, "s"); if (time_before_lost < 0) krb5_errx (context, 1, "couldn't parse time: %s", server_time_lost); memset(&conf, 0, sizeof(conf)); if(realm) { conf.mask |= KADM5_CONFIG_REALM; conf.realm = realm; } ret = kadm5_init_with_password_ctx (context, KADM5_ADMIN_SERVICE, NULL, KADM5_ADMIN_SERVICE, &conf, 0, 0, &kadm_handle); if (ret) krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); server_context = (kadm5_server_context *)kadm_handle; ret = kadm5_log_init (server_context); if (ret) krb5_err (context, 1, ret, "kadm5_log_init"); get_creds(context, keytab_str, &ccache, master); ret = krb5_sname_to_principal (context, master, IPROP_NAME, KRB5_NT_SRV_HST, &server); if (ret) krb5_err (context, 1, ret, "krb5_sname_to_principal"); auth_context = NULL; master_fd = -1; krb5_appdefault_time(context, config_name, NULL, "reconnect-min", 10, &reconnect_min); krb5_appdefault_time(context, config_name, NULL, "reconnect-max", 300, &reconnect_max); krb5_appdefault_time(context, config_name, NULL, "reconnect-backoff", 10, &backoff); reconnect = reconnect_min; while (!exit_flag) { time_t now, elapsed; int connected = FALSE; now = time(NULL); elapsed = now - before; if (elapsed < reconnect) { time_t left = reconnect - elapsed; krb5_warnx(context, "sleeping %d seconds before " "retrying to connect", (int)left); sleep(left); } before = now; master_fd = connect_to_master (context, master, port_str); if (master_fd < 0) goto retry; reconnect = reconnect_min; if (auth_context) { krb5_auth_con_free(context, auth_context); auth_context = NULL; krb5_cc_destroy(context, ccache); get_creds(context, keytab_str, &ccache, master); } ret = krb5_sendauth (context, &auth_context, &master_fd, IPROP_VERSION, NULL, server, AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, ccache, NULL, NULL, NULL); if (ret) { krb5_warn (context, ret, "krb5_sendauth"); goto retry; } krb5_warnx(context, "ipropd-slave started at version: %ld", (long)server_context->log_context.version); ret = ihave (context, auth_context, master_fd, server_context->log_context.version); if (ret) goto retry; connected = TRUE; while (connected && !exit_flag) { krb5_data out; krb5_storage *sp; int32_t tmp; fd_set readset; struct timeval to; #ifndef NO_LIMIT_FD_SETSIZE if (master_fd >= FD_SETSIZE) krb5_errx (context, 1, "fd too large"); #endif FD_ZERO(&readset); FD_SET(master_fd, &readset); to.tv_sec = time_before_lost; to.tv_usec = 0; ret = select (master_fd + 1, &readset, NULL, NULL, &to); if (ret < 0) { if (errno == EINTR) continue; else krb5_err (context, 1, errno, "select"); } if (ret == 0) krb5_errx (context, 1, "server didn't send a message " "in %d seconds", time_before_lost); ret = krb5_read_priv_message(context, auth_context, &master_fd, &out); if (ret) { krb5_warn (context, ret, "krb5_read_priv_message"); connected = FALSE; continue; } sp = krb5_storage_from_mem (out.data, out.length); krb5_ret_int32 (sp, &tmp); switch (tmp) { case FOR_YOU : receive (context, sp, server_context); ret = ihave (context, auth_context, master_fd, server_context->log_context.version); if (ret) connected = FALSE; break; case TELL_YOU_EVERYTHING : ret = receive_everything (context, master_fd, server_context, auth_context); if (ret) connected = FALSE; break; case ARE_YOU_THERE : send_im_here (context, master_fd, auth_context); break; case NOW_YOU_HAVE : case I_HAVE : case ONE_PRINC : case I_AM_HERE : default : krb5_warnx (context, "Ignoring command %d", tmp); break; } krb5_storage_free (sp); krb5_data_free (&out); } retry: if (connected == FALSE) krb5_warnx (context, "disconnected for server"); if (exit_flag) krb5_warnx (context, "got an exit signal"); if (master_fd >= 0) close(master_fd); reconnect += backoff; if (reconnect > reconnect_max) reconnect = reconnect_max; } if (0); #ifndef NO_SIGXCPU else if(exit_flag == SIGXCPU) krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); #endif else if(exit_flag == SIGINT || exit_flag == SIGTERM) krb5_warnx(context, "%s terminated", getprogname()); else krb5_warnx(context, "%s unexpected exit reason: %ld", getprogname(), (long)exit_flag); return 0; }
static int proto (int sock, const char *hostname, const char *service) { krb5_auth_context auth_context; krb5_error_code status; krb5_principal server; krb5_data data; krb5_data packet; u_int32_t len, net_len; 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_setaddrs_from_fd"); status = krb5_sname_to_principal (context, hostname, service, KRB5_NT_SRV_HST, &server); if (status) krb5_err (context, 1, status, "krb5_sname_to_principal"); status = krb5_sendauth (context, &auth_context, &sock, VERSION, NULL, server, AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, NULL, NULL, NULL, NULL); if (status) krb5_err (context, 1, status, "krb5_sendauth"); data.data = "hej"; data.length = 3; krb5_data_zero (&packet); status = krb5_mk_safe (context, auth_context, &data, &packet, NULL); if (status) krb5_err (context, 1, status, "krb5_mk_safe"); len = packet.length; net_len = htonl(len); if (krb5_net_write (context, &sock, &net_len, 4) != 4) err (1, "krb5_net_write"); if (krb5_net_write (context, &sock, packet.data, len) != len) err (1, "krb5_net_write"); data.data = "hemligt"; data.length = 7; krb5_data_free (&packet); status = krb5_mk_priv (context, auth_context, &data, &packet, NULL); if (status) krb5_err (context, 1, status, "krb5_mk_priv"); len = packet.length; net_len = htonl(len); if (krb5_net_write (context, &sock, &net_len, 4) != 4) err (1, "krb5_net_write"); if (krb5_net_write (context, &sock, packet.data, len) != len) err (1, "krb5_net_write"); return 0; }
/* call-seq: * krb5.get_init_creds_keytab(principal = nil, keytab = nil, service = nil, ccache = nil) * * Acquire credentials for +principal+ from +keytab+ using +service+. If * no principal is specified, then a principal is derived from the service * name. If no service name is specified, kerberos defaults to "host". * * If no keytab file is provided, the default keytab file is used. This is * typically /etc/krb5.keytab. * * If +ccache+ is supplied and is a Kerberos::Krb5::CredentialsCache, the * resulting credentials will be stored in the credential cache. */ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){ RUBY_KRB5* ptr; VALUE v_user, v_keytab_name, v_service, v_ccache; char* user; char* service; char keytab_name[MAX_KEYTAB_NAME_LEN]; krb5_error_code kerror; krb5_get_init_creds_opt* opt; krb5_creds cred; Data_Get_Struct(self, RUBY_KRB5, ptr); if(!ptr->ctx) rb_raise(cKrb5Exception, "no context has been established"); kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt); if(kerror) rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror)); rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache); // We need the service information for later. if(NIL_P(v_service)){ service = NULL; } else{ Check_Type(v_service, T_STRING); service = StringValueCStr(v_service); } // Convert the name (or service name) to a kerberos principal. if(NIL_P(v_user)){ kerror = krb5_sname_to_principal( ptr->ctx, NULL, service, KRB5_NT_SRV_HST, &ptr->princ ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_sname_to_principal: %s", error_message(kerror)); } } else{ Check_Type(v_user, T_STRING); user = StringValueCStr(v_user); kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror)); } } // Use the default keytab if none is specified. if(NIL_P(v_keytab_name)){ kerror = krb5_kt_default_name(ptr->ctx, keytab_name, MAX_KEYTAB_NAME_LEN); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror)); } } else{ Check_Type(v_keytab_name, T_STRING); strncpy(keytab_name, StringValueCStr(v_keytab_name), MAX_KEYTAB_NAME_LEN); } kerror = krb5_kt_resolve( ptr->ctx, keytab_name, &ptr->keytab ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_resolve: %s", error_message(kerror)); } // Set the credential cache from the supplied Kerberos::Krb5::CredentialsCache if(!NIL_P(v_ccache)){ RUBY_KRB5_CCACHE* ccptr; Data_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, ccptr); kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror)); } } kerror = krb5_get_init_creds_keytab( ptr->ctx, &cred, ptr->princ, ptr->keytab, 0, service, opt ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_keytab: %s", error_message(kerror)); } krb5_get_init_creds_opt_free(ptr->ctx, opt); return self; }
int main(int argc, char **argv) { krb5_context context; krb5_error_code retval; krb5_principal server; krb5_keytab keytab = NULL; /* Allow specification on command line*/ extern int opterr, optind; extern char *optarg; int ch; char *progname, *cfgfile, *cmddir; char *cfgname = AFSADMCONFIGNAME; char *cfgdir = AFSADMDIR; char *service = AFSADM_SERVICE; /*********************************************************************/ debug = 0; progname = *argv; /* open a log connection */ openlog("afsadmd", LOG_PID, LOG_DAEMON); retval = krb5_init_context(&context); if (retval) { syslog(LOG_ERR, "while initializing krb5: %s", error_message(retval)); exit(1); } /* * Parse command line arguments */ opterr = 0; while ((ch = getopt(argc, argv, "dS:s:c:")) != EOF) { switch (ch) { case 'c': cfgdir = optarg; break; case 's': service = optarg; break; case 'S': if (retval = krb5_kt_resolve(context, optarg, &keytab)) { syslog(LOG_ERR, "while resolving keytab file %s: %s", optarg, error_message(retval)); exit(2); } break; case 'd': debug++; break; case '?': default: usage(progname); exit(1); break; } } argc -= optind; argv += optind; if (retval = krb5_sname_to_principal(context, NULL, service, KRB5_NT_SRV_HST, &server)) { syslog(LOG_ERR, "while generating service name (%s): %s", service, error_message(retval)); exit(1); } /******************************************************************/ /* * Config file */ if ((cfgfile = malloc(sizeof(char) * (strlen(cfgdir) + strlen(cfgname) + 2))) == NULL) { syslog(LOG_ERR, "%m: while allocating buffer for configuration filename"); exit(1); } sprintf(cfgfile, "%s/%s", cfgdir, cfgname); /* cmddir = cfgdir/bin */ if ((cmddir = malloc(sizeof(char) * (strlen(cfgdir) + 4))) == NULL) { syslog(LOG_ERR, "%m: while allocating buffer for configuration directory"); exit(1); } sprintf(cmddir, "%s/bin", cfgdir); if (debug) syslog(LOG_DEBUG, "Parsing configfile %s", cfgfile); if (parse_config_file(cfgfile)) exit(1); /*********************************************************************/ do_krb5_comm(context, keytab, server, cmddir); free(cfgfile); free(cmddir); krb5_free_context(context); exit(0); }
/* * call-seq: * get_init_creds_keytab([principal][,keytab]) * * Call krb5_get_init_creds_keytab() to get credentials based on a keytab. With no parameters, gets the default principal (probably the username@DEFAULT_REALM) from the default keytab (as configured in /etc/krb5.conf). With one parameter, get the named principal from the default keytab (as configured in /etc/krb5.conf). With two parameters, get the named principal from the named keytab. Returns true on success, raises Krb5Auth::Krb5::Exception on failure. */ static VALUE Krb5_get_init_creds_keytab(int argc, VALUE *argv, VALUE self) { VALUE princ_val, keytab_val; char *princ; char *keytab_name; struct ruby_krb5 *kerb; krb5_error_code krbret; krb5_keytab keytab; keytab = NULL; rb_scan_args(argc, argv, "02", &princ_val, &keytab_val); princ = get_string_or_nil(princ_val); keytab_name = get_string_or_nil(keytab_val); Data_Get_Struct(self, struct ruby_krb5, kerb); if (!kerb) { NOSTRUCT_EXCEPT(); return Qfalse; } if (keytab_name != NULL) { krbret = krb5_kt_resolve(kerb->ctx, keytab_name, &keytab); if (krbret) { goto failed_keytab; } } // implicit else: if we weren't passed a keytab name, just leave keytab as // NULL to use the default if (princ != NULL) { krbret = krb5_parse_name(kerb->ctx, princ, &kerb->princ); } else { // if we weren't passed a principal, we just get the default principal // (which is generally the hostname) krbret = krb5_sname_to_principal(kerb->ctx, NULL, NULL, KRB5_NT_SRV_HST, &kerb->princ); } if (krbret) { goto failed_keytab; } krbret = krb5_get_init_creds_keytab(kerb->ctx, &kerb->creds, kerb->princ, keytab, 0, NULL, NULL); if (krbret) { goto failed_keytab; } if (keytab) krb5_kt_close(kerb->ctx, keytab); return Qtrue; failed_keytab: if (keytab) krb5_kt_close(kerb->ctx, keytab); Krb5_register_error(krbret); // we will never reach here, since Krb5_register_error will rb_raise(). just // leave it to shut the compiler up return Qfalse; }
static int proto (int sock, const char *hostname, const char *svc, char *message, size_t len) { krb5_auth_context auth_context; krb5_error_code status; krb5_principal server; krb5_data data; krb5_data data_send; krb5_ccache ccache; krb5_creds creds; krb5_kdc_flags flags; krb5_principal principal; status = krb5_auth_con_init (context, &auth_context); if (status) { krb5_warn (context, status, "krb5_auth_con_init"); return 1; } status = krb5_auth_con_setaddrs_from_fd (context, auth_context, &sock); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_auth_con_setaddr"); return 1; } status = krb5_sname_to_principal (context, hostname, svc, KRB5_NT_SRV_HST, &server); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_sname_to_principal"); return 1; } status = krb5_sendauth (context, &auth_context, &sock, KF_VERSION_1, NULL, server, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, NULL, NULL, NULL, NULL, NULL, NULL); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn(context, status, "krb5_sendauth"); return 1; } if (ccache_name == NULL) ccache_name = ""; data_send.data = (void *)remote_name; data_send.length = strlen(remote_name) + 1; status = krb5_write_priv_message(context, auth_context, &sock, &data_send); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_write_message"); return 1; } data_send.data = (void *)ccache_name; data_send.length = strlen(ccache_name)+1; status = krb5_write_priv_message(context, auth_context, &sock, &data_send); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_write_message"); return 1; } memset (&creds, 0, sizeof(creds)); status = krb5_cc_default (context, &ccache); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_cc_default"); return 1; } status = krb5_cc_get_principal (context, ccache, &principal); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_cc_get_principal"); return 1; } creds.client = principal; status = krb5_make_principal (context, &creds.server, principal->realm, KRB5_TGS_NAME, principal->realm, NULL); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_make_principal"); return 1; } creds.times.endtime = 0; flags.i = 0; flags.b.forwarded = 1; flags.b.forwardable = forwardable; status = krb5_get_forwarded_creds (context, auth_context, ccache, flags.i, hostname, &creds, &data); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_get_forwarded_creds"); return 1; } status = krb5_write_priv_message(context, auth_context, &sock, &data); if (status) { krb5_auth_con_free(context, auth_context); krb5_warn (context, status, "krb5_mk_priv"); return 1; } krb5_data_free (&data); status = krb5_read_priv_message(context, auth_context, &sock, &data); krb5_auth_con_free(context, auth_context); if (status) { krb5_warn (context, status, "krb5_mk_priv"); return 1; } if(data.length >= len) { krb5_warnx (context, "returned string is too long, truncating"); memcpy(message, data.data, len); message[len - 1] = '\0'; } else { memcpy(message, data.data, data.length); message[data.length] = '\0'; } krb5_data_free (&data); return(strcmp(message, "ok")); }
/* * Function: socket_connection * * Purpose: Opens the network connection with the mail host, without * doing any sort of I/O with it or anything. * * Arguments: * host The host to which to connect. * flags Option flags. * * Return value: A file descriptor indicating the connection, or -1 * indicating failure, in which case an error has been copied * into pop_error. */ static int socket_connection (char *host, int flags) { struct addrinfo *res, *it; struct addrinfo hints; int ret; struct servent *servent; struct sockaddr_in addr; char found_port = 0; const char *service; int sock; char *realhost; #ifdef KERBEROS #ifdef KERBEROS5 krb5_error_code rem; krb5_context kcontext = 0; krb5_auth_context auth_context = 0; krb5_ccache ccdef; krb5_principal client, server; krb5_error *err_ret; register char *cp; #else KTEXT ticket; MSG_DAT msg_data; CREDENTIALS cred; Key_schedule schedule; int rem; #endif /* KERBEROS5 */ #endif /* KERBEROS */ int try_count = 0; int connect_ok; #ifdef WINDOWSNT { WSADATA winsockData; if (WSAStartup (0x101, &winsockData) == 0) have_winsock = 1; } #endif memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; /** "kpop" service is never used: look for 20060515 to see why **/ #ifdef KERBEROS service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE; #else service = POP_SERVICE; #endif #ifdef HESIOD if (! (flags & POP_NO_HESIOD)) { servent = hes_getservbyname (service, "tcp"); if (servent) { addr.sin_port = servent->s_port; found_port = 1; } } #endif if (! found_port) { servent = getservbyname (service, "tcp"); if (servent) { addr.sin_port = servent->s_port; } else { /** "kpop" service is never used: look for 20060515 to see why **/ #ifdef KERBEROS addr.sin_port = htons ((flags & POP_NO_KERBEROS) ? POP_PORT : KPOP_PORT); #else addr.sin_port = htons (POP_PORT); #endif } } #define POP_SOCKET_ERROR "Could not create socket for POP connection: " sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0) { snprintf (pop_error, ERROR_MAX, "%s%s", POP_SOCKET_ERROR, strerror (errno)); return (-1); } memset (&hints, 0, sizeof (hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET; do { ret = getaddrinfo (host, service, &hints, &res); try_count++; if (ret != 0 && (ret != EAI_AGAIN || try_count == 5)) { strcpy (pop_error, "Could not determine POP server's address"); return (-1); } } while (ret != 0); for (it = res; it; it = it->ai_next) if (it->ai_addrlen == sizeof addr) { struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr; addr.sin_addr = in_a->sin_addr; if (! connect (sock, (struct sockaddr *) &addr, sizeof addr)) break; } connect_ok = it != NULL; if (connect_ok) { realhost = alloca (strlen (it->ai_canonname) + 1); strcpy (realhost, it->ai_canonname); } freeaddrinfo (res); #define CONNECT_ERROR "Could not connect to POP server: " if (! connect_ok) { CLOSESOCKET (sock); snprintf (pop_error, ERROR_MAX, "%s%s", CONNECT_ERROR, strerror (errno)); return (-1); } #ifdef KERBEROS #define KRB_ERROR "Kerberos error connecting to POP server: " if (! (flags & POP_NO_KERBEROS)) { #ifdef KERBEROS5 rem = krb5_init_context (&kcontext); if (rem) { krb5error: if (auth_context) krb5_auth_con_free (kcontext, auth_context); if (kcontext) krb5_free_context (kcontext); snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, error_message (rem)); CLOSESOCKET (sock); return (-1); } rem = krb5_auth_con_init (kcontext, &auth_context); if (rem) goto krb5error; rem = krb5_cc_default (kcontext, &ccdef); if (rem) goto krb5error; rem = krb5_cc_get_principal (kcontext, ccdef, &client); if (rem) goto krb5error; for (cp = realhost; *cp; cp++) *cp = c_tolower (*cp); rem = krb5_sname_to_principal (kcontext, realhost, POP_SERVICE, FALSE, &server); if (rem) goto krb5error; rem = krb5_sendauth (kcontext, &auth_context, (krb5_pointer) &sock, (char *) "KPOPV1.0", client, server, AP_OPTS_MUTUAL_REQUIRED, 0, /* no checksum */ 0, /* no creds, use ccache instead */ ccdef, &err_ret, 0, /* don't need subsession key */ 0); /* don't need reply */ krb5_free_principal (kcontext, server); if (rem) { int pop_error_len = snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, error_message (rem)); #if defined HAVE_KRB5_ERROR_TEXT if (err_ret && err_ret->text.length) { int errlen = err_ret->text.length; snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len, " [server says '%.*s']", errlen, err_ret->text.data); } #elif defined HAVE_KRB5_ERROR_E_TEXT if (err_ret && err_ret->e_text && **err_ret->e_text) snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len, " [server says '%s']", *err_ret->e_text); #endif if (err_ret) krb5_free_error (kcontext, err_ret); krb5_auth_con_free (kcontext, auth_context); krb5_free_context (kcontext); CLOSESOCKET (sock); return (-1); } #else /* ! KERBEROS5 */ ticket = (KTEXT) malloc (sizeof (KTEXT_ST)); rem = krb_sendauth (0L, sock, ticket, "pop", realhost, (char *) krb_realmofhost (realhost), (unsigned long) 0, &msg_data, &cred, schedule, (struct sockaddr_in *) 0, (struct sockaddr_in *) 0, "KPOPV0.1"); free ((char *) ticket); if (rem != KSUCCESS) { snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, krb_err_txt[rem]); CLOSESOCKET (sock); return (-1); } #endif /* KERBEROS5 */ } #endif /* KERBEROS */ return (sock); } /* socket_connection */
static int propagate_database (krb5_context context, int type, const char *database_name, HDB *db, krb5_ccache ccache, int optidx, int argc, char **argv) { krb5_principal server; krb5_error_code ret; int i, failed = 0; for(i = optidx; i < argc; i++){ krb5_auth_context auth_context; int fd; struct prop_data pd; krb5_data data; char *port, portstr[NI_MAXSERV]; char *host = argv[i]; port = strchr(host, ':'); if(port == NULL) { snprintf(portstr, sizeof(portstr), "%u", ntohs(krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT))); port = portstr; } else *port++ = '\0'; fd = open_socket(context, host, port); if(fd < 0) { failed++; krb5_warn (context, errno, "connect %s", host); continue; } ret = krb5_sname_to_principal(context, argv[i], HPROP_NAME, KRB5_NT_SRV_HST, &server); if(ret) { failed++; krb5_warn(context, ret, "krb5_sname_to_principal(%s)", host); close(fd); continue; } if (local_realm) { krb5_realm my_realm; krb5_get_default_realm(context,&my_realm); krb5_principal_set_realm(context,server,my_realm); krb5_xfree(my_realm); } auth_context = NULL; ret = krb5_sendauth(context, &auth_context, &fd, HPROP_VERSION, NULL, server, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, NULL, /* in_data */ NULL, /* in_creds */ ccache, NULL, NULL, NULL); krb5_free_principal(context, server); if(ret) { failed++; krb5_warn(context, ret, "krb5_sendauth (%s)", host); close(fd); goto next_host; } pd.context = context; pd.auth_context = auth_context; pd.sock = fd; ret = iterate (context, database_name, db, type, &pd); if (ret) { krb5_warnx(context, "iterate to host %s failed", host); failed++; goto next_host; } krb5_data_zero (&data); ret = krb5_write_priv_message(context, auth_context, &fd, &data); if(ret) { krb5_warn(context, ret, "krb5_write_priv_message"); failed++; goto next_host; } ret = krb5_read_priv_message(context, auth_context, &fd, &data); if(ret) { krb5_warn(context, ret, "krb5_read_priv_message: %s", host); failed++; goto next_host; } else krb5_data_free (&data); next_host: krb5_auth_con_free(context, auth_context); close(fd); } if (failed) return 1; return 0; }
/* returns boolean */ static int DEFAULT_CC k5_begin(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { krb5_error_code code = 0; code = krb5_init_context(&k5->ctx); if (code != 0) { g_printf("krb5_init_context failed in k5_begin\n"); return 0; } if (opts->k5_cache_name) { code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); if (code != 0) { g_printf("krb5_cc_resolve failed in k5_begin\n"); return 0; } } else { code = krb5_cc_default(k5->ctx, &k5->cc); if (code != 0) { g_printf("krb5_cc_default failed in k5_begin\n"); return 0; } } if (opts->principal_name) { /* Use specified name */ code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me); if (code != 0) { g_printf("krb5_parse_name failed in k5_begin\n"); return 0; } } else { /* No principal name specified */ if (opts->action == INIT_KT) { /* Use the default host/service name */ code = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST, &k5->me); if (code != 0) { g_printf("krb5_sname_to_principal failed in k5_begin\n"); return 0; } } else { /* Get default principal from cache if one exists */ code = krb5_cc_get_principal(k5->ctx, k5->cc, &k5->me); if (code != 0) { code = krb5_parse_name(k5->ctx, u_info->name, &k5->me); if (code != 0) { g_printf("krb5_parse_name failed in k5_begin\n"); return 0; } } } } code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); if (code != 0) { g_printf("krb5_unparse_name failed in k5_begin\n"); return 0; } opts->principal_name = k5->name; return 1; }