License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "dns.h"
-#include <ctype.h>
-
-
-#ifdef HAVE_GSSAPI
-
-/*********************************************************************
-*********************************************************************/
-
-#ifndef HAVE_STRUPR
-static int strupr( char *szDomainName )
-{
- if ( !szDomainName ) {
- return ( 0 );
- }
- while ( *szDomainName != '\0' ) {
- *szDomainName = toupper( *szDomainName );
- szDomainName++;
- }
- return ( 0 );
-}
-#endif
-
-#if 0
-/*********************************************************************
-*********************************************************************/
-
-static void display_status_1( const char *m, OM_uint32 code, int type )
-{
- OM_uint32 maj_stat, min_stat;
- gss_buffer_desc msg;
- OM_uint32 msg_ctx;
-
- msg_ctx = 0;
- while ( 1 ) {
- maj_stat = gss_display_status( &min_stat, code,
- type, GSS_C_NULL_OID,
- &msg_ctx, &msg );
- fprintf( stdout, "GSS-API error %s: %s\n", m,
- ( char * ) msg.value );
- ( void ) gss_release_buffer( &min_stat, &msg );
-
- if ( !msg_ctx )
- break;
- }
-}
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "lib/util/charset/charset.h"
+#include "libcli/util/ntstatus.h"
+#include "auth/gensec/gensec.h"
-/*********************************************************************
-*********************************************************************/
+#include "dns.h"
-void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
-{
- display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
- display_status_1( msg, min_stat, GSS_C_MECH_CODE );
-}
-#endif
-
-static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
- struct dns_connection *conn,
- const char *keyname,
- const gss_name_t target_name,
- gss_ctx_id_t *ctx,
- enum dns_ServerType srv_type )
+static DNS_ERROR dns_negotiate_gss_ctx_int(struct dns_connection *conn,
+ const char *keyname,
+ struct gensec_security *gensec,
+ enum dns_ServerType srv_type)
{
- struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
- OM_uint32 major, minor;
- OM_uint32 ret_flags;
+ TALLOC_CTX *frame = talloc_stackframe();
struct dns_request *req = NULL;
struct dns_buffer *buf = NULL;
+ DATA_BLOB in = { .length = 0, };
+ DATA_BLOB out = { .length = 0, };
+ NTSTATUS status;
DNS_ERROR err;
- gss_OID_desc krb5_oid_desc =
- { 9, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
-
- *ctx = GSS_C_NO_CONTEXT;
- input_ptr = NULL;
-
do {
- major = gss_init_sec_context(
- &minor, NULL, ctx, target_name, &krb5_oid_desc,
- GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
- GSS_C_CONF_FLAG |
- GSS_C_INTEG_FLAG,
- 0, NULL, input_ptr, NULL, &output_desc,
- &ret_flags, NULL );
-
- if (input_ptr != NULL) {
- TALLOC_FREE(input_desc.value);
+ status = gensec_update(gensec, frame, in, &out);
+ data_blob_free(&in);
+ if (GENSEC_UPDATE_IS_NTERROR(status)) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
}
- if (output_desc.length != 0) {
-
+ if (out.length != 0) {
struct dns_rrec *rec;
time_t t = time(NULL);
- err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
+ err = dns_create_query(frame, keyname, QTYPE_TKEY,
DNS_CLASS_IN, &req);
if (!ERR_DNS_IS_OK(err)) goto error;
err = dns_create_tkey_record(
req, keyname, "gss.microsoft.com", t,
t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
- output_desc.length, (uint8_t *)output_desc.value,
+ out.length, out.data,
&rec );
if (!ERR_DNS_IS_OK(err)) goto error;
if (!ERR_DNS_IS_OK(err)) goto error;
- err = dns_marshall_request(mem_ctx, req, &buf);
+ err = dns_marshall_request(frame, req, &buf);
if (!ERR_DNS_IS_OK(err)) goto error;
err = dns_send(conn, buf);
TALLOC_FREE(buf);
TALLOC_FREE(req);
- }
-
- gss_release_buffer(&minor, &output_desc);
- if ((major != GSS_S_COMPLETE) &&
- (major != GSS_S_CONTINUE_NEEDED)) {
- return ERROR_DNS_GSS_ERROR;
+ err = dns_receive(frame, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
}
- if (major == GSS_S_CONTINUE_NEEDED) {
-
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
struct dns_request *resp;
struct dns_tkey_record *tkey;
struct dns_rrec *tkey_answer = NULL;
uint16_t i;
- err = dns_receive(mem_ctx, conn, &buf);
- if (!ERR_DNS_IS_OK(err)) goto error;
+ if (buf == NULL) {
+ err = ERROR_DNS_BAD_RESPONSE;
+ goto error;
+ }
err = dns_unmarshall_request(buf, buf, &resp);
if (!ERR_DNS_IS_OK(err)) goto error;
}
err = dns_unmarshall_tkey_record(
- mem_ctx, resp->answers[0], &tkey);
+ frame, resp->answers[0], &tkey);
if (!ERR_DNS_IS_OK(err)) goto error;
- input_desc.length = tkey->key_length;
- input_desc.value = talloc_move(mem_ctx, &tkey->key);
-
- input_ptr = &input_desc;
+ in = data_blob_const(tkey->key, tkey->key_length);
TALLOC_FREE(buf);
}
- } while ( major == GSS_S_CONTINUE_NEEDED );
+ } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
/* If we arrive here, we have a valid security context */
error:
- TALLOC_FREE(buf);
- TALLOC_FREE(req);
+ TALLOC_FREE(frame);
return err;
}
-DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
- const char *servername,
- const char *keyname,
- gss_ctx_id_t *gss_ctx,
- enum dns_ServerType srv_type )
+DNS_ERROR dns_negotiate_sec_ctx(const char *servername,
+ const char *keyname,
+ struct gensec_security *gensec,
+ enum dns_ServerType srv_type)
{
- OM_uint32 major, minor;
-
- char *upcaserealm, *targetname;
+ TALLOC_CTX *frame = talloc_stackframe();
DNS_ERROR err;
+ struct dns_connection *conn = NULL;
- gss_buffer_desc input_name;
- struct dns_connection *conn;
-
- gss_name_t targ_name;
-
- gss_OID_desc nt_host_oid_desc =
- {10, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
-
- TALLOC_CTX *mem_ctx;
-
- if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
- return ERROR_DNS_NO_MEMORY;
- }
-
- err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
+ err = dns_open_connection( servername, DNS_TCP, frame, &conn );
if (!ERR_DNS_IS_OK(err)) goto error;
- if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
- err = ERROR_DNS_NO_MEMORY;
- goto error;
- }
-
- strupr(upcaserealm);
-
- if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
- servername, upcaserealm))) {
- err = ERROR_DNS_NO_MEMORY;
- goto error;
- }
-
- input_name.value = targetname;
- input_name.length = strlen(targetname);
-
- major = gss_import_name( &minor, &input_name,
- &nt_host_oid_desc, &targ_name );
-
- if (major) {
- err = ERROR_DNS_GSS_ERROR;
- goto error;
- }
-
- err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
- targ_name, gss_ctx, srv_type );
-
- gss_release_name( &minor, &targ_name );
+ err = dns_negotiate_gss_ctx_int(conn, keyname,
+ gensec,
+ srv_type);
+ if (!ERR_DNS_IS_OK(err)) goto error;
error:
- TALLOC_FREE(mem_ctx);
+ TALLOC_FREE(frame);
return err;
}
DNS_ERROR dns_sign_update(struct dns_update_request *req,
- gss_ctx_id_t gss_ctx,
+ struct gensec_security *gensec,
const char *keyname,
const char *algorithmname,
time_t time_signed, uint16_t fudge)
{
+ TALLOC_CTX *frame = talloc_stackframe();
struct dns_buffer *buf;
DNS_ERROR err;
struct dns_domain_name *key, *algorithm;
- struct gss_buffer_desc_struct msg, mic;
- OM_uint32 major, minor;
struct dns_rrec *rec;
+ DATA_BLOB mic = { .length = 0, };
+ NTSTATUS status;
- err = dns_marshall_update_request(req, req, &buf);
+ err = dns_marshall_update_request(frame, req, &buf);
if (!ERR_DNS_IS_OK(err)) return err;
- err = dns_domain_name_from_string(buf, keyname, &key);
+ err = dns_domain_name_from_string(frame, keyname, &key);
if (!ERR_DNS_IS_OK(err)) goto error;
- err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
+ err = dns_domain_name_from_string(frame, algorithmname, &algorithm);
if (!ERR_DNS_IS_OK(err)) goto error;
dns_marshall_domain_name(buf, key);
err = buf->error;
if (!ERR_DNS_IS_OK(buf->error)) goto error;
- msg.value = (void *)buf->data;
- msg.length = buf->offset;
-
- major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
- if (major != 0) {
+ status = gensec_sign_packet(gensec,
+ frame,
+ buf->data,
+ buf->offset,
+ buf->data,
+ buf->offset,
+ &mic);
+ if (!NT_STATUS_IS_OK(status)) {
err = ERROR_DNS_GSS_ERROR;
goto error;
}
if (mic.length > 0xffff) {
- gss_release_buffer(&minor, &mic);
err = ERROR_DNS_GSS_ERROR;
goto error;
}
- err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
- fudge, mic.length, (uint8_t *)mic.value,
+ err = dns_create_tsig_record(frame, keyname, algorithmname, time_signed,
+ fudge, mic.length, mic.data,
req->id, 0, &rec);
- gss_release_buffer(&minor, &mic);
if (!ERR_DNS_IS_OK(err)) goto error;
err = dns_add_rrec(req, rec, &req->num_additionals, &req->additional);
error:
- TALLOC_FREE(buf);
+ TALLOC_FREE(frame);
return err;
}
-
-#endif /* HAVE_GSSAPI */
#include "includes.h"
#include "utils/net.h"
#include "../lib/addns/dnsquery.h"
-#include "secrets.h"
+#include "passdb.h"
#include "krb5_env.h"
#include "utils/net_dns.h"
#include "lib/util/string_wrappers.h"
}
static NTSTATUS net_update_dns_internal(struct net_context *c,
- TALLOC_CTX *ctx, ADS_STRUCT *ads,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads,
+ struct cli_credentials *creds,
const char *machine_name,
const struct sockaddr_storage *addrs,
int num_addrs, bool remove_host)
ADS_STATUS ads_status;
if ( !ads->ldap.ld ) {
- ads_status = ads_connect( ads );
+ ads_status = ads_connect_creds(ads, creds);
if ( !ADS_ERR_OK(ads_status) ) {
DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
status = ads_ntstatus(ads_status);
dns_err = DoDNSUpdate(dns_server,
dnsdomain,
machine_name,
+ creds,
addrs,
num_addrs,
flags,
}
NTSTATUS net_update_dns_ext(struct net_context *c,
- TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ ADS_STRUCT *ads,
+ struct cli_credentials *creds,
const char *hostname,
struct sockaddr_storage *iplist,
int num_addrs, bool remove_host)
iplist = iplist_alloc;
}
- status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
- iplist, num_addrs, remove_host);
+ status = net_update_dns_internal(c,
+ mem_ctx,
+ ads,
+ creds,
+ machine_name,
+ iplist,
+ num_addrs,
+ remove_host);
SAFE_FREE(iplist_alloc);
return status;
}
-static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
-{
- NTSTATUS status;
-
- status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
- return status;
-}
#endif
void net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
{
#if defined(HAVE_KRB5)
ADS_STRUCT *ads_dns = NULL;
- int ret;
+ struct cli_credentials *creds = NULL;
NTSTATUS status;
- char *machine_password = NULL;
/*
* In a clustered environment, don't do dynamic dns updates:
ads_dns = ads_init(ctx,
lp_realm(),
- NULL,
+ lp_workgroup(),
r->in.dc_name,
ADS_SASL_PLAIN);
if (ads_dns == NULL) {
goto done;
}
- use_in_memory_ccache();
-
- ads_dns->auth.user_name = talloc_asprintf(ads_dns,
- "%s$",
- lp_netbios_name());
- if (ads_dns->auth.user_name == NULL) {
- d_fprintf(stderr, _("DNS update failed: out of memory\n"));
- goto done;
- }
-
- machine_password = secrets_fetch_machine_password(
- r->out.netbios_domain_name, NULL, NULL);
- if (machine_password != NULL) {
- ads_dns->auth.password = talloc_strdup(ads_dns,
- machine_password);
- SAFE_FREE(machine_password);
- if (ads_dns->auth.password == NULL) {
- d_fprintf(stderr,
- _("DNS update failed: out of memory\n"));
- goto done;
- }
- }
-
- ads_dns->auth.realm = talloc_asprintf_strupper_m(ads_dns, "%s", r->out.dns_domain_name);
- if (ads_dns->auth.realm == NULL) {
- d_fprintf(stderr, _("talloc_asprintf_strupper_m %s failed\n"),
- ads_dns->auth.realm);
- goto done;
- }
-
- ret = ads_kinit_password(ads_dns);
- if (ret != 0) {
- d_fprintf(stderr,
- _("DNS update failed: kinit failed: %s\n"),
- error_message(ret));
+ status = pdb_get_trust_credentials(ads_dns->server.workgroup,
+ ads_dns->server.realm,
+ ads_dns,
+ &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "pdb_get_trust_credentials() failed: %s\n",
+ nt_errstr(status));
goto done;
}
- status = net_update_dns(c, ctx, ads_dns, NULL);
+ status = net_update_dns_ext(c,
+ ads_dns,
+ ads_dns,
+ creds,
+ NULL,
+ NULL,
+ 0,
+ false);
if (!NT_STATUS_IS_OK(status)) {
d_fprintf( stderr, _("DNS update failed: %s\n"),
nt_errstr(status));
#include "utils/net.h"
#include "../lib/addns/dns.h"
#include "utils/net_dns.h"
+#include "auth/gensec/gensec.h"
+#include "auth_generic.h"
#if defined(HAVE_KRB5)
/*********************************************************************
*********************************************************************/
+static DNS_ERROR DoDNSUpdateNegotiateGensec(const char *pszServerName,
+ const char *pszDomainName,
+ const char *keyname,
+ enum dns_ServerType srv_type,
+ struct cli_credentials *creds,
+ TALLOC_CTX *mem_ctx,
+ struct gensec_security **_gensec)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct auth_generic_state *ans = NULL;
+ NTSTATUS status;
+ DNS_ERROR err;
+
+ status = auth_generic_client_prepare(mem_ctx, &ans);
+ if (!NT_STATUS_IS_OK(status)) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+ talloc_steal(frame, ans);
+
+ status = auth_generic_set_creds(ans, creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ status = gensec_set_target_service(ans->gensec_security,
+ "dns");
+ if (!NT_STATUS_IS_OK(status)) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ status = gensec_set_target_hostname(ans->gensec_security,
+ pszServerName);
+ if (!NT_STATUS_IS_OK(status)) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ gensec_want_feature(ans->gensec_security, GENSEC_FEATURE_SIGN);
+
+ status = auth_generic_client_start(ans, GENSEC_OID_KERBEROS5);
+ if (!NT_STATUS_IS_OK(status)) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ err = dns_negotiate_sec_ctx(pszServerName,
+ keyname,
+ ans->gensec_security,
+ srv_type);
+ if (!ERR_DNS_IS_OK(err)) {
+ goto error;
+ }
+
+ *_gensec = talloc_move(mem_ctx, &ans->gensec_security);
+ error:
+ TALLOC_FREE(frame);
+
+ return err;
+}
+
DNS_ERROR DoDNSUpdate(char *pszServerName,
const char *pszDomainName,
const char *pszHostName,
+ struct cli_credentials *creds,
const struct sockaddr_storage *sslist,
size_t num_addrs,
uint32_t flags,
DNS_ERROR err;
struct dns_connection *conn;
TALLOC_CTX *mem_ctx;
- OM_uint32 minor;
struct dns_update_request *req, *resp;
DEBUG(10,("DoDNSUpdate called with flags: 0x%08x\n", flags));
* Okay, we have to try with signing
*/
if (flags & DNS_UPDATE_SIGNED) {
- gss_ctx_id_t gss_context;
- char *keyname;
+ struct gensec_security *gensec = NULL;
+ char *keyname = NULL;
err = dns_create_update_request(mem_ctx,
pszDomainName,
goto error;
}
- err = dns_negotiate_sec_ctx( pszDomainName, pszServerName,
- keyname, &gss_context, DNS_SRV_ANY );
+ err = DoDNSUpdateNegotiateGensec(pszServerName,
+ pszDomainName,
+ keyname,
+ DNS_SRV_ANY,
+ creds,
+ mem_ctx,
+ &gensec);
/* retry using the Windows 2000 DNS hack */
if (!ERR_DNS_IS_OK(err)) {
- err = dns_negotiate_sec_ctx( pszDomainName, pszServerName,
- keyname, &gss_context,
- DNS_SRV_WIN2000 );
+ err = DoDNSUpdateNegotiateGensec(pszServerName,
+ pszDomainName,
+ keyname,
+ DNS_SRV_WIN2000,
+ creds,
+ mem_ctx,
+ &gensec);
}
if (!ERR_DNS_IS_OK(err))
goto error;
- err = dns_sign_update(req, gss_context, keyname,
+ err = dns_sign_update(req, gensec, keyname,
"gss.microsoft.com", time(NULL), 3600);
- gss_delete_sec_context(&minor, &gss_context, GSS_C_NO_BUFFER);
-
if (!ERR_DNS_IS_OK(err)) goto error;
err = dns_update_transaction(mem_ctx, conn, req, &resp);