📄 krb5-security.c
字号:
} set_root_privs(1); server_socket = stream_client(rc->hostname, (in_port_t)(ntohs(port)), STREAM_BUFSIZE, STREAM_BUFSIZE, &my_port, 0); set_root_privs(0); if(server_socket < 0) { security_seterror(&rh->sech, "%s", strerror(errno)); return -1; } rc->read = rc->write = server_socket; if (gss_client(rh) < 0) { return -1; } return 0;}/* * Negotiate a krb5 gss context from the client end. */static intgss_client( struct sec_handle *rh){ struct sec_stream *rs = rh->rs; struct tcp_conn *rc = rs->rc; gss_buffer_desc send_tok, recv_tok, AA; gss_OID doid; OM_uint32 maj_stat, min_stat; unsigned int ret_flags; int rval = -1; int rvalue; gss_name_t gss_name; char *errmsg = NULL; auth_debug(1, "gss_client\n"); send_tok.value = vstralloc("host/", rs->rc->hostname, NULL); send_tok.length = strlen(send_tok.value) + 1; maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID, &gss_name); if (maj_stat != (OM_uint32)GSS_S_COMPLETE) { security_seterror(&rh->sech, _("can't import name %s: %s"), (char *)send_tok.value, gss_error(maj_stat, min_stat)); amfree(send_tok.value); return (-1); } amfree(send_tok.value); rc->gss_context = GSS_C_NO_CONTEXT; maj_stat = gss_display_name(&min_stat, gss_name, &AA, &doid); dbprintf(_("gss_name %s\n"), (char *)AA.value); /* * Perform the context-establishement loop. * * Every generated token is stored in send_tok which is then * transmitted to the server; every received token is stored in * recv_tok (empty on the first pass) to be processed by * the next call to gss_init_sec_context. * * GSS-API guarantees that send_tok's length will be non-zero * if and only if the server is expecting another token from us, * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if * and only if the server has another token to send us. */ recv_tok.value = NULL; for (recv_tok.length = 0;;) { min_stat = 0; maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &rc->gss_context, gss_name, GSS_C_NULL_OID, (OM_uint32)GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG, 0, NULL, /* no channel bindings */ (recv_tok.length == 0 ? GSS_C_NO_BUFFER : &recv_tok), NULL, /* ignore mech type */ &send_tok, &ret_flags, NULL); /* ignore time_rec */ if (recv_tok.length != 0) { amfree(recv_tok.value); recv_tok.length = 0; } if (maj_stat != (OM_uint32)GSS_S_COMPLETE && maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) { security_seterror(&rh->sech, _("error getting gss context: %s %s"), gss_error(maj_stat, min_stat), (char *)send_tok.value); goto done; } /* * Send back the response */ if (send_tok.length != 0 && tcpm_send_token(rc, rc->write, rs->handle, &errmsg, send_tok.value, send_tok.length) < 0) { security_seterror(&rh->sech, rc->errmsg); gss_release_buffer(&min_stat, &send_tok); goto done; } gss_release_buffer(&min_stat, &send_tok); /* * If we need to continue, then register for more packets */ if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) break; rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg, (void *)&recv_tok.value, (ssize_t *)&recv_tok.length, 60); if (rvalue <= 0) { if (rvalue < 0) security_seterror(&rh->sech, _("recv error in gss loop: %s"), rc->errmsg); else security_seterror(&rh->sech, _("EOF in gss loop")); goto done; } } rval = 0; rc->auth = 1;done: gss_release_name(&min_stat, &gss_name); return (rval);}/* * Negotiate a krb5 gss context from the server end. */static intgss_server( struct tcp_conn *rc){ OM_uint32 maj_stat, min_stat, ret_flags; gss_buffer_desc send_tok, recv_tok, AA; gss_OID doid; gss_name_t gss_name; gss_cred_id_t gss_creds; char *p, *realm, *msg; uid_t euid; int rval = -1; int rvalue; char errbuf[256]; char *errmsg = NULL; auth_debug(1, "gss_server\n"); assert(rc != NULL); /* * We need to be root while in gss_acquire_cred() to read the host key * out of the default keytab. We also need to be root in * gss_accept_context() thanks to the replay cache code. */ euid = geteuid(); if (getuid() != 0) { g_snprintf(errbuf, SIZEOF(errbuf), _("real uid is %ld, needs to be 0 to read krb5 host key"), (long)getuid()); goto out; } if (!set_root_privs(0)) { g_snprintf(errbuf, SIZEOF(errbuf), _("can't seteuid to uid 0: %s"), strerror(errno)); goto out; } rc->gss_context = GSS_C_NO_CONTEXT; send_tok.value = vstralloc("host/", myhostname, NULL); send_tok.length = strlen(send_tok.value) + 1; for (p = send_tok.value; *p != '\0'; p++) { if (isupper((int)*p)) *p = tolower(*p); } maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID, &gss_name); if (maj_stat != (OM_uint32)GSS_S_COMPLETE) { set_root_privs(0); g_snprintf(errbuf, SIZEOF(errbuf), _("can't import name %s: %s"), (char *)send_tok.value, gss_error(maj_stat, min_stat)); amfree(send_tok.value); goto out; } amfree(send_tok.value); maj_stat = gss_display_name(&min_stat, gss_name, &AA, &doid); dbprintf(_("gss_name %s\n"), (char *)AA.value); maj_stat = gss_acquire_cred(&min_stat, gss_name, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_creds, NULL, NULL); if (maj_stat != (OM_uint32)GSS_S_COMPLETE) { g_snprintf(errbuf, SIZEOF(errbuf), _("can't acquire creds for host key host/%s: %s"), myhostname, gss_error(maj_stat, min_stat)); gss_release_name(&min_stat, &gss_name); set_root_privs(0); goto out; } gss_release_name(&min_stat, &gss_name); for (recv_tok.length = 0;;) { recv_tok.value = NULL; rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg, /* (void *) is to avoid type-punning warning */ (char **)(void *)&recv_tok.value, (ssize_t *)&recv_tok.length, 60); if (rvalue <= 0) { if (rvalue < 0) { g_snprintf(errbuf, SIZEOF(errbuf), _("recv error in gss loop: %s"), rc->errmsg); amfree(rc->errmsg); } else g_snprintf(errbuf, SIZEOF(errbuf), _("EOF in gss loop")); goto out; } maj_stat = gss_accept_sec_context(&min_stat, &rc->gss_context, gss_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &gss_name, &doid, &send_tok, &ret_flags, NULL, NULL); if (maj_stat != (OM_uint32)GSS_S_COMPLETE && maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) { g_snprintf(errbuf, SIZEOF(errbuf), _("error accepting context: %s"), gss_error(maj_stat, min_stat)); amfree(recv_tok.value); goto out; } amfree(recv_tok.value); if (send_tok.length != 0 && tcpm_send_token(rc, rc->write, 0, &errmsg, send_tok.value, send_tok.length) < 0) { strncpy(errbuf, rc->errmsg, SIZEOF(errbuf) - 1); errbuf[SIZEOF(errbuf) - 1] = '\0'; amfree(rc->errmsg); gss_release_buffer(&min_stat, &send_tok); goto out; } gss_release_buffer(&min_stat, &send_tok); /* * If we need to get more from the client, then register for * more packets. */ if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) break; } maj_stat = gss_display_name(&min_stat, gss_name, &send_tok, &doid); if (maj_stat != (OM_uint32)GSS_S_COMPLETE) { g_snprintf(errbuf, SIZEOF(errbuf), _("can't display gss name: %s"), gss_error(maj_stat, min_stat)); gss_release_name(&min_stat, &gss_name); goto out; } gss_release_name(&min_stat, &gss_name); /* get rid of the realm */ if ((p = strchr(send_tok.value, '@')) == NULL) { g_snprintf(errbuf, SIZEOF(errbuf), _("malformed gss name: %s"), (char *)send_tok.value); amfree(send_tok.value); goto out; } *p = '\0'; realm = ++p; /* * If the principal doesn't match, complain */ if ((msg = krb5_checkuser(rc->hostname, send_tok.value, realm)) != NULL) { g_snprintf(errbuf, SIZEOF(errbuf), _("access not allowed from %s: %s"), (char *)send_tok.value, msg); amfree(send_tok.value); goto out; } amfree(send_tok.value); rval = 0;out: set_root_privs(0); if (rval != 0) { rc->errmsg = stralloc(errbuf); } else { rc->auth = 1; } auth_debug(1, _("gss_server returning %d\n"), rval); return (rval);}/* * Setup some things about krb5. This should only be called once. */static voidkrb5_init(void){ static int beenhere = 0; char *p; char *myfqhostname=NULL; if (beenhere) return; beenhere = 1;#ifndef BROKEN_MEMORY_CCACHE putenv(stralloc("KRB5_ENV_CCNAME=MEMORY:amanda_ccache"));#else /* * MEMORY ccaches seem buggy and cause a lot of internal heap * corruption. malloc has been known to core dump. This behavior * has been witnessed in Cygnus' kerbnet 1.2, MIT's krb V 1.0.5 and * MIT's krb V -current as of 3/17/1999. * * We just use a lame ccache scheme with a uid suffix. */ atexit(cleanup); { char *ccache; ccache = malloc(128); g_snprintf(ccache, SIZEOF(ccache), "KRB5_ENV_CCNAME=FILE:/tmp/amanda_ccache.%ld.%ld", (long)geteuid(), (long)getpid()); putenv(ccache); }#endif gethostname(myhostname, SIZEOF(myhostname) - 1); myhostname[SIZEOF(myhostname) - 1] = '\0'; /* * In case it isn't fully qualified, do a DNS lookup. Ignore * any errors (this is best-effort). */ if (resolve_hostname(myhostname, SOCK_STREAM, NULL, &myfqhostname) == 0 && myfqhostname != NULL) { strncpy(myhostname, myfqhostname, SIZEOF(myhostname)-1); myhostname[SIZEOF(myhostname)-1] = '\0'; amfree(myfqhostname); } /* * Lowercase the results. We assume all host/ principals will be * lowercased. */ for (p = myhostname; *p != '\0'; p++) { if (isupper((int)*p)) *p = tolower(*p); }}#ifdef BROKEN_MEMORY_CCACHEstatic voidcleanup(void){#ifdef KDESTROY_VIA_UNLINK char ccache[64]; g_snprintf(ccache, SIZEOF(ccache), "/tmp/amanda_ccache.%ld.%ld", (long)geteuid(), (long)getpid()); unlink(ccache);#else kdestroy();#endif}#endif/* * Get a ticket granting ticket and stuff it in the cache */static const char *get_tgt( char * keytab_name, char * principal_name){ krb5_context context; krb5_error_code ret; krb5_principal client = NULL, server = NULL; krb5_creds creds; krb5_keytab keytab; krb5_ccache ccache; krb5_timestamp now;#ifdef KRB5_HEIMDAL_INCLUDES krb5_data tgtname = { KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };#else krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };#endif static char *error = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -