summaryrefslogtreecommitdiff
path: root/lib/addns
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2011-01-06 14:53:04 +0100
committerGünther Deschner <gd@samba.org>2011-01-06 16:42:56 +0100
commit7ee75c95481f0d13598577361d18e96cb8394b9c (patch)
tree9dc79864581847d17d7c74fe63cf3bba6970cced /lib/addns
parent4e0d0af9e89e23a5daea8048deff5c9057f08bb9 (diff)
downloadsamba-7ee75c95481f0d13598577361d18e96cb8394b9c.tar.gz
samba-7ee75c95481f0d13598577361d18e96cb8394b9c.tar.bz2
samba-7ee75c95481f0d13598577361d18e96cb8394b9c.zip
lib/addns: move DNS client library to the main directory.
Guenther
Diffstat (limited to 'lib/addns')
-rw-r--r--lib/addns/addns.h30
-rw-r--r--lib/addns/dns.h540
-rw-r--r--lib/addns/dnserr.h87
-rw-r--r--lib/addns/dnsgss.c334
-rw-r--r--lib/addns/dnsmarshall.c530
-rw-r--r--lib/addns/dnsrecord.c422
-rw-r--r--lib/addns/dnssock.c377
-rw-r--r--lib/addns/dnsutils.c151
-rw-r--r--lib/addns/error.c59
-rw-r--r--lib/addns/wscript_build7
10 files changed, 2537 insertions, 0 deletions
diff --git a/lib/addns/addns.h b/lib/addns/addns.h
new file mode 100644
index 0000000000..6ef9329df8
--- /dev/null
+++ b/lib/addns/addns.h
@@ -0,0 +1,30 @@
+/*
+ Public Interface file for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _ADDNS_H
+#define _ADDNS_H
+
+
+#endif /* _ADDNS_H */
+
diff --git a/lib/addns/dns.h b/lib/addns/dns.h
new file mode 100644
index 0000000000..29f1ed3e99
--- /dev/null
+++ b/lib/addns/dns.h
@@ -0,0 +1,540 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DNS_H
+#define _DNS_H
+
+#include "../replace/replace.h"
+#include "system/network.h"
+
+/* make sure we have included the correct config.h */
+#ifndef NO_CONFIG_H /* for some tests */
+#ifndef CONFIG_H_IS_FROM_SAMBA
+#error "make sure you have removed all config.h files from standalone builds!"
+#error "the included config.h isn't from samba!"
+#endif
+#endif /* NO_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+
+#ifdef HAVE_UUID_UUID_H
+#include <uuid/uuid.h>
+#endif
+
+#ifdef HAVE_KRB5_H
+#include <krb5.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+
+#ifndef int16
+#define int16 int16_t
+#endif
+
+#ifndef uint16
+#define uint16 uint16_t
+#endif
+
+#ifndef int32
+#define int32 int32_t
+#endif
+
+#ifndef uint32
+#define uint32 uint32_t
+#endif
+#endif
+
+#ifdef HAVE_KRB5_H
+#include <krb5.h>
+#endif
+
+#if HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif HAVE_GSSAPI_GSSAPI_GENERIC_H
+#include <gssapi/gssapi_generic.h>
+#elif HAVE_GSSAPI_H
+#include <gssapi.h>
+#endif
+
+#if defined(HAVE_GSSAPI_H) || defined(HAVE_GSSAPI_GSSAPI_H) || defined(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+#define HAVE_GSSAPI_SUPPORT 1
+#endif
+
+#include <talloc.h>
+
+#if 0
+
+Disable these now we have checked all code paths and ensured
+NULL returns on zero request. JRA.
+
+void *_talloc_zero_zeronull(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup_zeronull(const void *t, const void *p, size_t size, const char *name);
+void *_talloc_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *talloc_zeronull(const void *context, size_t size, const char *name);
+
+#define TALLOC(ctx, size) talloc_zeronull(ctx, size, __location__)
+#define TALLOC_P(ctx, type) (type *)talloc_zeronull(ctx, sizeof(type), #type)
+#define TALLOC_ARRAY(ctx, type, count) (type *)_talloc_array_zeronull(ctx, sizeof(type), count, #type)
+#define TALLOC_MEMDUP(ctx, ptr, size) _talloc_memdup_zeronull(ctx, ptr, size, __location__)
+#define TALLOC_ZERO(ctx, size) _talloc_zero_zeronull(ctx, size, __location__)
+#define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero_zeronull(ctx, sizeof(type), #type)
+#define TALLOC_ZERO_ARRAY(ctx, type, count) (type *)_talloc_zero_array_zeronull(ctx, sizeof(type), count, #type)
+#define TALLOC_SIZE(ctx, size) talloc_zeronull(ctx, size, __location__)
+#define TALLOC_ZERO_SIZE(ctx, size) _talloc_zero_zeronull(ctx, size, __location__)
+
+#else
+
+#define TALLOC(ctx, size) talloc_named_const(ctx, size, __location__)
+#define TALLOC_P(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define TALLOC_ARRAY(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define TALLOC_MEMDUP(ctx, ptr, size) _talloc_memdup(ctx, ptr, size, __location__)
+#define TALLOC_ZERO(ctx, size) _talloc_zero(ctx, size, __location__)
+#define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define TALLOC_ZERO_ARRAY(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define TALLOC_SIZE(ctx, size) talloc_named_const(ctx, size, __location__)
+#define TALLOC_ZERO_SIZE(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#endif
+
+#define TALLOC_REALLOC(ctx, ptr, count) _talloc_realloc(ctx, ptr, count, __location__)
+#define TALLOC_REALLOC_ARRAY(ctx, ptr, type, count) (type *)_talloc_realloc_array(ctx, ptr, sizeof(type), count, #type)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#ifndef TALLOC_FREE
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+#endif
+
+/*******************************************************************
+ Type definitions for int16, int32, uint16 and uint32. Needed
+ for Samba coding style
+*******************************************************************/
+
+#ifndef uint8
+# define uint8 unsigned char
+#endif
+
+#if !defined(int16) && !defined(HAVE_INT16_FROM_RPC_RPC_H)
+# if (SIZEOF_SHORT == 4)
+# define int16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+# else /* SIZEOF_SHORT != 4 */
+# define int16 short
+# endif /* SIZEOF_SHORT != 4 */
+ /* needed to work around compile issue on HP-UX 11.x */
+# define _INT16 1
+#endif
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int16 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H)
+# if (SIZEOF_SHORT == 4)
+# define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+# else /* SIZEOF_SHORT != 4 */
+# define uint16 unsigned short
+# endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#if !defined(int32) && !defined(HAVE_INT32_FROM_RPC_RPC_H)
+# if (SIZEOF_INT == 4)
+# define int32 int
+# elif (SIZEOF_LONG == 4)
+# define int32 long
+# elif (SIZEOF_SHORT == 4)
+# define int32 short
+# else
+ /* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+# define int32 int
+# endif
+# ifndef _INT32
+ /* needed to work around compile issue on HP-UX 11.x */
+# define _INT32 1
+# endif
+#endif
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int32 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint32) && !defined(HAVE_UINT32_FROM_RPC_RPC_H)
+# if (SIZEOF_INT == 4)
+# define uint32 unsigned int
+# elif (SIZEOF_LONG == 4)
+# define uint32 unsigned long
+# elif (SIZEOF_SHORT == 4)
+# define uint32 unsigned short
+# else
+ /* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+# define uint32 unsigned
+# endif
+#endif
+
+/*
+ * check for 8 byte long long
+ */
+
+#if !defined(uint64)
+# if (SIZEOF_LONG == 8)
+# define uint64 unsigned long
+# elif (SIZEOF_LONG_LONG == 8)
+# define uint64 unsigned long long
+# endif /* don't lie. If we don't have it, then don't use it */
+#endif
+
+/* needed on Sun boxes */
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xFFFFFFFF
+#endif
+
+#include "dnserr.h"
+
+
+#define DNS_TCP 1
+#define DNS_UDP 2
+
+#define DNS_OPCODE_UPDATE 1
+
+/* DNS Class Types */
+
+#define DNS_CLASS_IN 1
+#define DNS_CLASS_ANY 255
+#define DNS_CLASS_NONE 254
+
+/* DNS RR Types */
+
+#define DNS_RR_A 1
+
+#define DNS_TCP_PORT 53
+#define DNS_UDP_PORT 53
+
+#define QTYPE_A 1
+#define QTYPE_NS 2
+#define QTYPE_MD 3
+#define QTYPE_CNAME 5
+#define QTYPE_SOA 6
+#define QTYPE_ANY 255
+#define QTYPE_TKEY 249
+#define QTYPE_TSIG 250
+
+/*
+MF 4 a mail forwarder (Obsolete - use MX)
+CNAME 5 the canonical name for an alias
+SOA 6 marks the start of a zone of authority
+MB 7 a mailbox domain name (EXPERIMENTAL)
+MG 8 a mail group member (EXPERIMENTAL)
+MR 9 a mail rename domain name (EXPERIMENTAL)
+NULL 10 a null RR (EXPERIMENTAL)
+WKS 11 a well known service description
+PTR 12 a domain name pointer
+HINFO 13 host information
+MINFO 14 mailbox or mail list information
+MX 15 mail exchange
+TXT 16 text strings
+*/
+
+#define QR_QUERY 0x0000
+#define QR_RESPONSE 0x0001
+
+#define OPCODE_QUERY 0x00
+#define OPCODE_IQUERY 0x01
+#define OPCODE_STATUS 0x02
+
+#define AA 1
+
+#define RECURSION_DESIRED 0x01
+
+#define RCODE_NOERROR 0
+#define RCODE_FORMATERROR 1
+#define RCODE_SERVER_FAILURE 2
+#define RCODE_NAME_ERROR 3
+#define RCODE_NOTIMPLEMENTED 4
+#define RCODE_REFUSED 5
+
+#define SENDBUFFER_SIZE 65536
+#define RECVBUFFER_SIZE 65536
+
+/*
+ * TKEY Modes from rfc2930
+ */
+
+#define DNS_TKEY_MODE_SERVER 1
+#define DNS_TKEY_MODE_DH 2
+#define DNS_TKEY_MODE_GSSAPI 3
+#define DNS_TKEY_MODE_RESOLVER 4
+#define DNS_TKEY_MODE_DELETE 5
+
+
+#define DNS_ONE_DAY_IN_SECS 86400
+#define DNS_TEN_HOURS_IN_SECS 36000
+
+#define SOCKET_ERROR -1
+#define INVALID_SOCKET -1
+
+#define DNS_NO_ERROR 0
+#define DNS_FORMAT_ERROR 1
+#define DNS_SERVER_FAILURE 2
+#define DNS_NAME_ERROR 3
+#define DNS_NOT_IMPLEMENTED 4
+#define DNS_REFUSED 5
+
+typedef long HANDLE;
+
+enum dns_ServerType { DNS_SRV_ANY, DNS_SRV_WIN2000, DNS_SRV_WIN2003 };
+
+struct dns_domain_label {
+ struct dns_domain_label *next;
+ char *label;
+ size_t len;
+};
+
+struct dns_domain_name {
+ struct dns_domain_label *pLabelList;
+};
+
+struct dns_question {
+ struct dns_domain_name *name;
+ uint16 q_type;
+ uint16 q_class;
+};
+
+/*
+ * Before changing the definition of dns_zone, look
+ * dns_marshall_update_request(), we rely on this being the same as
+ * dns_question right now.
+ */
+
+struct dns_zone {
+ struct dns_domain_name *name;
+ uint16 z_type;
+ uint16 z_class;
+};
+
+struct dns_rrec {
+ struct dns_domain_name *name;
+ uint16 type;
+ uint16 r_class;
+ uint32 ttl;
+ uint16 data_length;
+ uint8 *data;
+};
+
+struct dns_tkey_record {
+ struct dns_domain_name *algorithm;
+ time_t inception;
+ time_t expiration;
+ uint16 mode;
+ uint16 error;
+ uint16 key_length;
+ uint8 *key;
+};
+
+struct dns_request {
+ uint16 id;
+ uint16 flags;
+ uint16 num_questions;
+ uint16 num_answers;
+ uint16 num_auths;
+ uint16 num_additionals;
+ struct dns_question **questions;
+ struct dns_rrec **answers;
+ struct dns_rrec **auths;
+ struct dns_rrec **additionals;
+};
+
+/*
+ * Before changing the definition of dns_update_request, look
+ * dns_marshall_update_request(), we rely on this being the same as
+ * dns_request right now.
+ */
+
+struct dns_update_request {
+ uint16 id;
+ uint16 flags;
+ uint16 num_zones;
+ uint16 num_preqs;
+ uint16 num_updates;
+ uint16 num_additionals;
+ struct dns_zone **zones;
+ struct dns_rrec **preqs;
+ struct dns_rrec **updates;
+ struct dns_rrec **additionals;
+};
+
+struct dns_connection {
+ int32 hType;
+ int s;
+ struct sockaddr RecvAddr;
+};
+
+struct dns_buffer {
+ uint8 *data;
+ size_t size;
+ size_t offset;
+ DNS_ERROR error;
+};
+
+/* from dnsutils.c */
+
+DNS_ERROR dns_domain_name_from_string( TALLOC_CTX *mem_ctx,
+ const char *pszDomainName,
+ struct dns_domain_name **presult );
+char *dns_generate_keyname( TALLOC_CTX *mem_ctx );
+
+/* from dnsrecord.c */
+
+DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
+ uint16 q_type, uint16 q_class,
+ struct dns_request **preq );
+DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
+ struct dns_update_request **preq );
+DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
+ const char *host, int num_ips,
+ const struct sockaddr_storage *sslist,
+ struct dns_update_request **preq);
+DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class, uint32 ttl,
+ uint16 data_length, uint8 *data,
+ struct dns_rrec **prec);
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16 *num_records, struct dns_rrec ***records);
+DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name, time_t inception,
+ time_t expiration, uint16 mode, uint16 error,
+ uint16 key_length, const uint8 *key,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct sockaddr_storage *ip,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name, uint32 type,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32 ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec);
+DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ struct dns_tkey_record **ptkey);
+DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name,
+ time_t time_signed, uint16 fudge,
+ uint16 mac_length, const uint8 *mac,
+ uint16 original_id, uint16 error,
+ struct dns_rrec **prec);
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16 *num_records, struct dns_rrec ***records);
+DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *hostname,
+ const struct sockaddr_storage *ip_addr,
+ size_t num_adds,
+ struct dns_update_request **preq);
+
+/* from dnssock.c */
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **conn );
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf);
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ struct dns_buffer **presult);
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ const struct dns_request *req,
+ struct dns_request **resp);
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_update_request *up_req,
+ struct dns_update_request **up_resp);
+
+/* from dnsmarshall.c */
+
+struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx);
+void dns_marshall_buffer(struct dns_buffer *buf, const uint8 *data,
+ size_t len);
+void dns_marshall_uint16(struct dns_buffer *buf, uint16 val);
+void dns_marshall_uint32(struct dns_buffer *buf, uint32 val);
+void dns_unmarshall_buffer(struct dns_buffer *buf, uint8 *data,
+ size_t len);
+void dns_unmarshall_uint16(struct dns_buffer *buf, uint16 *val);
+void dns_unmarshall_uint32(struct dns_buffer *buf, uint32 *val);
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname);
+void dns_marshall_domain_name(struct dns_buffer *buf,
+ const struct dns_domain_name *name);
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname);
+DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
+ const struct dns_request *req,
+ struct dns_buffer **pbuf);
+DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_request **preq);
+DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_update_request *update,
+ struct dns_buffer **pbuf);
+DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_update_request **pupreq);
+struct dns_request *dns_update2request(struct dns_update_request *update);
+struct dns_update_request *dns_request2update(struct dns_request *request);
+uint16 dns_response_code(uint16 flags);
+const char *dns_errstr(DNS_ERROR err);
+
+/* from dnsgss.c */
+
+#ifdef HAVE_GSSAPI_SUPPORT
+
+void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat );
+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_sign_update(struct dns_update_request *req,
+ gss_ctx_id_t gss_ctx,
+ const char *keyname,
+ const char *algorithmname,
+ time_t time_signed, uint16 fudge);
+
+#endif /* HAVE_GSSAPI_SUPPORT */
+
+#endif /* _DNS_H */
diff --git a/lib/addns/dnserr.h b/lib/addns/dnserr.h
new file mode 100644
index 0000000000..9e049ac3a9
--- /dev/null
+++ b/lib/addns/dnserr.h
@@ -0,0 +1,87 @@
+/*
+ Error codes for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DNSERR_H
+#define _DNSERR_H
+
+
+/* The Splint code analysis tool (http://www.splint.org.) doesn't
+ like immediate structures. */
+
+#ifdef _SPLINT_
+#undef HAVE_IMMEDIATE_STRUCTURES
+#endif
+
+/* Setup the DNS_ERROR typedef. Technique takes from nt_status.h */
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} DNS_ERROR;
+#define ERROR_DNS(x) ((DNS_ERROR) { x })
+#define ERROR_DNS_V(x) ((x).v)
+#else
+typedef uint32 DNS_ERROR;
+#define ERROR_DNS(x) (x)
+#define ERROR_DNS_V(x) (x)
+#endif
+
+#define ERR_DNS_IS_OK(x) (ERROR_DNS_V(x) == 0)
+#define ERR_DNS_EQUAL(x,y) (ERROR_DNS_V(x) == ERROR_DNS_V(y))
+
+/*************************************************
+ * Define the error codes here
+ *************************************************/
+
+#define ERROR_DNS_SUCCESS ERROR_DNS(0)
+#define ERROR_DNS_RECORD_NOT_FOUND ERROR_DNS(1)
+#define ERROR_DNS_BAD_RESPONSE ERROR_DNS(2)
+#define ERROR_DNS_INVALID_PARAMETER ERROR_DNS(3)
+#define ERROR_DNS_NO_MEMORY ERROR_DNS(4)
+#define ERROR_DNS_INVALID_NAME_SERVER ERROR_DNS(5)
+#define ERROR_DNS_CONNECTION_FAILED ERROR_DNS(6)
+#define ERROR_DNS_GSS_ERROR ERROR_DNS(7)
+#define ERROR_DNS_INVALID_NAME ERROR_DNS(8)
+#define ERROR_DNS_INVALID_MESSAGE ERROR_DNS(9)
+#define ERROR_DNS_SOCKET_ERROR ERROR_DNS(10)
+#define ERROR_DNS_UPDATE_FAILED ERROR_DNS(11)
+
+/*
+ * About to be removed, transitional error
+ */
+#define ERROR_DNS_UNSUCCESSFUL ERROR_DNS(999)
+
+
+#define ERROR_BAD_RESPONSE 1
+#define ERROR_RECORD_NOT_FOUND 2
+#define ERROR_OUTOFMEMORY 8
+#if !defined(ERROR_INVALID_PARAMETER)
+#define ERROR_INVALID_PARAMETER 87
+#endif
+
+/*
+ * About to be removed, transitional error
+ */
+#define ERROR_UNSUCCESSFUL 999
+
+#endif /* _DNSERR_H */
+
diff --git a/lib/addns/dnsgss.c b/lib/addns/dnsgss.c
new file mode 100644
index 0000000000..c9037417da
--- /dev/null
+++ b/lib/addns/dnsgss.c
@@ -0,0 +1,334 @@
+/*
+ Public Interface file for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <ctype.h>
+
+
+#ifdef HAVE_GSSAPI_SUPPORT
+
+/*********************************************************************
+*********************************************************************/
+
+#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;
+ }
+}
+
+/*********************************************************************
+*********************************************************************/
+
+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 )
+{
+ struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
+ OM_uint32 major, minor;
+ OM_uint32 ret_flags;
+ DNS_ERROR err;
+
+ gss_OID_desc krb5_oid_desc =
+ { 9, (char *)"\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);
+ }
+
+ if (output_desc.length != 0) {
+
+ struct dns_request *req;
+ struct dns_rrec *rec;
+ struct dns_buffer *buf;
+
+ time_t t = time(NULL);
+
+ err = dns_create_query(mem_ctx, 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 *)output_desc.value,
+ &rec );
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /* Windows 2000 DNS is broken and requires the
+ TKEY payload in the Answer section instead
+ of the Additional seciton like Windows 2003 */
+
+ if ( srv_type == DNS_SRV_WIN2000 ) {
+ err = dns_add_rrec(req, rec, &req->num_answers,
+ &req->answers);
+ } else {
+ err = dns_add_rrec(req, rec, &req->num_additionals,
+ &req->additionals);
+ }
+
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_marshall_request(req, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_send(conn, buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ TALLOC_FREE(req);
+ }
+
+ gss_release_buffer(&minor, &output_desc);
+
+ if ((major != GSS_S_COMPLETE) &&
+ (major != GSS_S_CONTINUE_NEEDED)) {
+ return ERROR_DNS_GSS_ERROR;
+ }
+
+ if (major == GSS_S_CONTINUE_NEEDED) {
+
+ struct dns_request *resp;
+ struct dns_buffer *buf;
+ struct dns_tkey_record *tkey;
+
+ err = dns_receive(mem_ctx, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_unmarshall_request(buf, buf, &resp);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * TODO: Compare id and keyname
+ */
+
+ if ((resp->num_additionals != 1) ||
+ (resp->num_answers == 0) ||
+ (resp->answers[0]->type != QTYPE_TKEY)) {
+ err = ERROR_DNS_INVALID_MESSAGE;
+ goto error;
+ }
+
+ err = dns_unmarshall_tkey_record(
+ mem_ctx, 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;
+
+ TALLOC_FREE(buf);
+ }
+
+ } while ( major == GSS_S_CONTINUE_NEEDED );
+
+ /* If we arrive here, we have a valid security context */
+
+ err = ERROR_DNS_SUCCESS;
+
+ error:
+
+ 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 )
+{
+ OM_uint32 major, minor;
+
+ char *upcaserealm, *targetname;
+ DNS_ERROR err;
+
+ gss_buffer_desc input_name;
+ struct dns_connection *conn;
+
+ gss_name_t targ_name;
+
+ gss_OID_desc nt_host_oid_desc =
+ {10, (char *)"\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 );
+ 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 );
+
+ error:
+ TALLOC_FREE(mem_ctx);
+
+ return err;
+}
+
+DNS_ERROR dns_sign_update(struct dns_update_request *req,
+ gss_ctx_id_t gss_ctx,
+ const char *keyname,
+ const char *algorithmname,
+ time_t time_signed, uint16 fudge)
+{
+ 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;
+
+ err = dns_marshall_update_request(req, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ err = dns_domain_name_from_string(buf, keyname, &key);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, key);
+ dns_marshall_uint16(buf, DNS_CLASS_ANY);
+ dns_marshall_uint32(buf, 0); /* TTL */
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
+ dns_marshall_uint32(buf, time_signed);
+ dns_marshall_uint16(buf, fudge);
+ dns_marshall_uint16(buf, 0); /* error */
+ dns_marshall_uint16(buf, 0); /* other len */
+
+ 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) {
+ 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 *)mic.value,
+ 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->additionals);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+#endif /* HAVE_GSSAPI_SUPPORT */
diff --git a/lib/addns/dnsmarshall.c b/lib/addns/dnsmarshall.c
new file mode 100644
index 0000000000..5530290c57
--- /dev/null
+++ b/lib/addns/dnsmarshall.c
@@ -0,0 +1,530 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include "assert.h"
+
+struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
+{
+ struct dns_buffer *result;
+
+ if (!(result = talloc(mem_ctx, struct dns_buffer))) {
+ return NULL;
+ }
+
+ result->offset = 0;
+ result->error = ERROR_DNS_SUCCESS;
+
+ /*
+ * Small inital size to excercise the realloc code
+ */
+ result->size = 2;
+
+ if (!(result->data = TALLOC_ARRAY(result, uint8, result->size))) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+void dns_marshall_buffer(struct dns_buffer *buf, const uint8 *data,
+ size_t len)
+{
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (buf->offset + len < buf->offset) {
+ /*
+ * Wraparound!
+ */
+ buf->error = ERROR_DNS_INVALID_PARAMETER;
+ return;
+ }
+
+ if ((buf->offset + len) > 0xffff) {
+ /*
+ * Only 64k possible
+ */
+ buf->error = ERROR_DNS_INVALID_PARAMETER;
+ return;
+ }
+
+ if (buf->offset + len > buf->size) {
+ size_t new_size = buf->offset + len;
+ uint8 *new_data;
+
+ /*
+ * Don't do too many reallocs, round up to some multiple
+ */
+
+ new_size += (64 - (new_size % 64));
+
+ if (!(new_data = TALLOC_REALLOC_ARRAY(buf, buf->data, uint8,
+ new_size))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ buf->size = new_size;
+ buf->data = new_data;
+ }
+
+ memcpy(buf->data + buf->offset, data, len);
+ buf->offset += len;
+ return;
+}
+
+void dns_marshall_uint16(struct dns_buffer *buf, uint16 val)
+{
+ uint16 n_val = htons(val);
+ dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+}
+
+void dns_marshall_uint32(struct dns_buffer *buf, uint32 val)
+{
+ uint32 n_val = htonl(val);
+ dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+}
+
+void dns_unmarshall_buffer(struct dns_buffer *buf, uint8 *data,
+ size_t len)
+{
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if ((len > buf->size) || (buf->offset + len > buf->size)) {
+ buf->error = ERROR_DNS_INVALID_MESSAGE;
+ return;
+ }
+
+ memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
+ buf->offset += len;
+
+ return;
+}
+
+void dns_unmarshall_uint16(struct dns_buffer *buf, uint16 *val)
+{
+ uint16 n_val;
+
+ dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *val = ntohs(n_val);
+}
+
+void dns_unmarshall_uint32(struct dns_buffer *buf, uint32 *val)
+{
+ uint32 n_val;
+
+ dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *val = ntohl(n_val);
+}
+
+void dns_marshall_domain_name(struct dns_buffer *buf,
+ const struct dns_domain_name *name)
+{
+ struct dns_domain_label *label;
+ char end_char = '\0';
+
+ /*
+ * TODO: Implement DNS compression
+ */
+
+ for (label = name->pLabelList; label != NULL; label = label->next) {
+ uint8 len = label->len;
+
+ dns_marshall_buffer(buf, (uint8 *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ dns_marshall_buffer(buf, (uint8 *)label->label, len);
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+ }
+
+ dns_marshall_buffer(buf, (uint8 *)&end_char, 1);
+}
+
+static void dns_unmarshall_label(TALLOC_CTX *mem_ctx,
+ int level,
+ struct dns_buffer *buf,
+ struct dns_domain_label **plabel)
+{
+ struct dns_domain_label *label;
+ uint8 len;
+
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (level > 128) {
+ /*
+ * Protect against recursion
+ */
+ buf->error = ERROR_DNS_INVALID_MESSAGE;
+ return;
+ }
+
+ dns_unmarshall_buffer(buf, &len, sizeof(len));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (len == 0) {
+ *plabel = NULL;
+ return;
+ }
+
+ if ((len & 0xc0) == 0xc0) {
+ /*
+ * We've got a compressed name. Build up a new "fake" buffer
+ * and using the calculated offset.
+ */
+ struct dns_buffer new_buf;
+ uint8 low;
+
+ dns_unmarshall_buffer(buf, &low, sizeof(low));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ new_buf = *buf;
+ new_buf.offset = len & 0x3f;
+ new_buf.offset <<= 8;
+ new_buf.offset |= low;
+
+ dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
+ buf->error = new_buf.error;
+ return;
+ }
+
+ if ((len & 0xc0) != 0) {
+ buf->error = ERROR_DNS_INVALID_NAME;
+ return;
+ }
+
+ if (!(label = talloc(mem_ctx, struct dns_domain_label))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ label->len = len;
+
+ if (!(label->label = TALLOC_ARRAY(label, char, len+1))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ dns_unmarshall_buffer(buf, (uint8 *)label->label, len);
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ dns_unmarshall_label(label, level+1, buf, &label->next);
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ *plabel = label;
+ return;
+
+ error:
+ TALLOC_FREE(label);
+ return;
+}
+
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname)
+{
+ struct dns_domain_name *name;
+
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (!(name = talloc(mem_ctx, struct dns_domain_name))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_label(name, 0, buf, &name->pLabelList);
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ return;
+ }
+
+ *pname = name;
+ return;
+}
+
+static void dns_marshall_question(struct dns_buffer *buf,
+ const struct dns_question *q)
+{
+ dns_marshall_domain_name(buf, q->name);
+ dns_marshall_uint16(buf, q->q_type);
+ dns_marshall_uint16(buf, q->q_class);
+}
+
+static void dns_unmarshall_question(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_question **pq)
+{
+ struct dns_question *q;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (!(q = talloc(mem_ctx, struct dns_question))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_domain_name(q, buf, &q->name);
+ dns_unmarshall_uint16(buf, &q->q_type);
+ dns_unmarshall_uint16(buf, &q->q_class);
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *pq = q;
+}
+
+static void dns_marshall_rr(struct dns_buffer *buf,
+ const struct dns_rrec *r)
+{
+ dns_marshall_domain_name(buf, r->name);
+ dns_marshall_uint16(buf, r->type);
+ dns_marshall_uint16(buf, r->r_class);
+ dns_marshall_uint32(buf, r->ttl);
+ dns_marshall_uint16(buf, r->data_length);
+ dns_marshall_buffer(buf, r->data, r->data_length);
+}
+
+static void dns_unmarshall_rr(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_rrec **pr)
+{
+ struct dns_rrec *r;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (!(r = talloc(mem_ctx, struct dns_rrec))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_domain_name(r, buf, &r->name);
+ dns_unmarshall_uint16(buf, &r->type);
+ dns_unmarshall_uint16(buf, &r->r_class);
+ dns_unmarshall_uint32(buf, &r->ttl);
+ dns_unmarshall_uint16(buf, &r->data_length);
+ r->data = NULL;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (r->data_length != 0) {
+ if (!(r->data = TALLOC_ARRAY(r, uint8, r->data_length))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+ dns_unmarshall_buffer(buf, r->data, r->data_length);
+ }
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *pr = r;
+}
+
+DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
+ const struct dns_request *req,
+ struct dns_buffer **pbuf)
+{
+ struct dns_buffer *buf;
+ uint16 i;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ dns_marshall_uint16(buf, req->id);
+ dns_marshall_uint16(buf, req->flags);
+ dns_marshall_uint16(buf, req->num_questions);
+ dns_marshall_uint16(buf, req->num_answers);
+ dns_marshall_uint16(buf, req->num_auths);
+ dns_marshall_uint16(buf, req->num_additionals);
+
+ for (i=0; i<req->num_questions; i++) {
+ dns_marshall_question(buf, req->questions[i]);
+ }
+ for (i=0; i<req->num_answers; i++) {
+ dns_marshall_rr(buf, req->answers[i]);
+ }
+ for (i=0; i<req->num_auths; i++) {
+ dns_marshall_rr(buf, req->auths[i]);
+ }
+ for (i=0; i<req->num_additionals; i++) {
+ dns_marshall_rr(buf, req->additionals[i]);
+ }
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ DNS_ERROR err = buf->error;
+ TALLOC_FREE(buf);
+ return err;
+ }
+
+ *pbuf = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_request **preq)
+{
+ struct dns_request *req;
+ uint16 i;
+ DNS_ERROR err;
+
+ if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ dns_unmarshall_uint16(buf, &req->id);
+ dns_unmarshall_uint16(buf, &req->flags);
+ dns_unmarshall_uint16(buf, &req->num_questions);
+ dns_unmarshall_uint16(buf, &req->num_answers);
+ dns_unmarshall_uint16(buf, &req->num_auths);
+ dns_unmarshall_uint16(buf, &req->num_additionals);
+
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ err = ERROR_DNS_NO_MEMORY;
+
+ if ((req->num_questions != 0) &&
+ !(req->questions = TALLOC_ARRAY(req, struct dns_question *,
+ req->num_questions))) {
+ goto error;
+ }
+ if ((req->num_answers != 0) &&
+ !(req->answers = TALLOC_ARRAY(req, struct dns_rrec *,
+ req->num_answers))) {
+ goto error;
+ }
+ if ((req->num_auths != 0) &&
+ !(req->auths = TALLOC_ARRAY(req, struct dns_rrec *,
+ req->num_auths))) {
+ goto error;
+ }
+ if ((req->num_additionals != 0) &&
+ !(req->additionals = TALLOC_ARRAY(req, struct dns_rrec *,
+ req->num_additionals))) {
+ goto error;
+ }
+
+ for (i=0; i<req->num_questions; i++) {
+ dns_unmarshall_question(req->questions, buf,
+ &req->questions[i]);
+ }
+ for (i=0; i<req->num_answers; i++) {
+ dns_unmarshall_rr(req->answers, buf,
+ &req->answers[i]);
+ }
+ for (i=0; i<req->num_auths; i++) {
+ dns_unmarshall_rr(req->auths, buf,
+ &req->auths[i]);
+ }
+ for (i=0; i<req->num_additionals; i++) {
+ dns_unmarshall_rr(req->additionals, buf,
+ &req->additionals[i]);
+ }
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ err = buf->error;
+ TALLOC_FREE(req);
+ return err;
+}
+
+struct dns_request *dns_update2request(struct dns_update_request *update)
+{
+ struct dns_request *req;
+
+ /*
+ * This is a non-specified construct that happens to work on Linux/gcc
+ * and I would expect it to work everywhere else. dns_request and
+ * dns_update_request are essentially the same structures with
+ * different names, so any difference would mean that the compiler
+ * applied two different variations of padding given the same types in
+ * the structures.
+ */
+
+ req = (struct dns_request *)(void *)update;
+
+ /*
+ * The assert statement here looks like we could do the equivalent
+ * assignments to get portable, but it would mean that we have to
+ * allocate the dns_question record for the dns_zone records. We
+ * assume that if this assert works then the same holds true for
+ * dns_zone<>dns_question as well.
+ */
+
+#ifdef DEVELOPER
+ assert((req->id == update->id) && (req->flags == update->flags) &&
+ (req->num_questions == update->num_zones) &&
+ (req->num_answers == update->num_preqs) &&
+ (req->num_auths == update->num_updates) &&
+ (req->num_additionals == update->num_additionals) &&
+ (req->questions ==
+ (struct dns_question **)(void *)update->zones) &&
+ (req->answers == update->preqs) &&
+ (req->auths == update->updates) &&
+ (req->additionals == update->additionals));
+#endif
+
+ return req;
+}
+
+struct dns_update_request *dns_request2update(struct dns_request *request)
+{
+ /*
+ * For portability concerns see dns_update2request;
+ */
+ return (struct dns_update_request *)(void *)request;
+}
+
+DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_update_request *update,
+ struct dns_buffer **pbuf)
+{
+ return dns_marshall_request(mem_ctx, dns_update2request(update), pbuf);
+}
+
+DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_update_request **pupreq)
+{
+ /*
+ * See comments above about portability. If the above works, this will
+ * as well.
+ */
+
+ return dns_unmarshall_request(mem_ctx, buf,
+ (struct dns_request **)(void *)pupreq);
+}
+
+uint16 dns_response_code(uint16 flags)
+{
+ return flags & 0xF;
+}
diff --git a/lib/addns/dnsrecord.c b/lib/addns/dnsrecord.c
new file mode 100644
index 0000000000..559c2644d4
--- /dev/null
+++ b/lib/addns/dnsrecord.c
@@ -0,0 +1,422 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+
+DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
+ uint16 q_type, uint16 q_class,
+ struct dns_request **preq )
+{
+ struct dns_request *req;
+ struct dns_question *q;
+ DNS_ERROR err;
+
+ if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request)) ||
+ !(req->questions = TALLOC_ARRAY(req, struct dns_question *, 1)) ||
+ !(req->questions[0] = talloc(req->questions,
+ struct dns_question))) {
+ TALLOC_FREE(req);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ req->id = random();
+
+ req->num_questions = 1;
+ q = req->questions[0];
+
+ err = dns_domain_name_from_string(q, name, &q->name);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(req);
+ return err;
+ }
+
+ q->q_type = q_type;
+ q->q_class = q_class;
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
+ struct dns_update_request **preq )
+{
+ struct dns_update_request *req;
+ struct dns_zone *z;
+ DNS_ERROR err;
+
+ if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_update_request)) ||
+ !(req->zones = TALLOC_ARRAY(req, struct dns_zone *, 1)) ||
+ !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
+ TALLOC_FREE(req);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ req->id = random();
+ req->flags = 0x2800; /* Dynamic update */
+
+ req->num_zones = 1;
+ z = req->zones[0];
+
+ err = dns_domain_name_from_string(z, name, &z->name);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(req);
+ return err;
+ }
+
+ z->z_type = QTYPE_SOA;
+ z->z_class = DNS_CLASS_IN;
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class, uint32 ttl,
+ uint16 data_length, uint8 *data,
+ struct dns_rrec **prec)
+{
+ struct dns_rrec *rec;
+ DNS_ERROR err;
+
+ if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(rec, name, &rec->name);
+ if (!(ERR_DNS_IS_OK(err))) {
+ TALLOC_FREE(rec);
+ return err;
+ }
+
+ rec->type = type;
+ rec->r_class = r_class;
+ rec->ttl = ttl;
+ rec->data_length = data_length;
+ rec->data = talloc_move(rec, &data);
+
+ *prec = rec;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32 ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec)
+{
+ uint8 *data;
+ DNS_ERROR err;
+ struct in_addr ip;
+
+ if (pss->ss_family != AF_INET) {
+ /* Silently ignore this. */
+ return ERROR_DNS_SUCCESS;
+ }
+
+ ip = ((struct sockaddr_in *)pss)->sin_addr;
+ if (!(data = (uint8 *)TALLOC_MEMDUP(mem_ctx, (const void *)&ip.s_addr,
+ sizeof(ip.s_addr)))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
+ sizeof(ip.s_addr), data, prec);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(data);
+ }
+
+ return err;
+}
+
+DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct sockaddr_storage *ss,
+ struct dns_rrec **prec)
+{
+ if (ss != NULL) {
+ return dns_create_a_record(mem_ctx, name, 0, ss, prec);
+ }
+
+ return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
+ NULL, prec);
+}
+
+DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name, uint32 type,
+ struct dns_rrec **prec)
+{
+ return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
+ 0, NULL, prec);
+}
+
+DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class,
+ struct dns_rrec **prec)
+{
+ return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
+}
+
+DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name, time_t inception,
+ time_t expiration, uint16 mode, uint16 error,
+ uint16 key_length, const uint8 *key,
+ struct dns_rrec **prec)
+{
+ struct dns_buffer *buf;
+ struct dns_domain_name *algorithm;
+ DNS_ERROR err;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint32(buf, inception);
+ dns_marshall_uint32(buf, expiration);
+ dns_marshall_uint16(buf, mode);
+ dns_marshall_uint16(buf, error);
+ dns_marshall_uint16(buf, key_length);
+ dns_marshall_buffer(buf, key, key_length);
+ dns_marshall_uint16(buf, 0); /* Other Size */
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
+ buf->offset, buf->data, prec);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ struct dns_tkey_record **ptkey)
+{
+ struct dns_tkey_record *tkey;
+ struct dns_buffer buf;
+ uint32 tmp_inception, tmp_expiration;
+
+ if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ buf.data = rec->data;
+ buf.size = rec->data_length;
+ buf.offset = 0;
+ buf.error = ERROR_DNS_SUCCESS;
+
+ dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
+ dns_unmarshall_uint32(&buf, &tmp_inception);
+ dns_unmarshall_uint32(&buf, &tmp_expiration);
+ dns_unmarshall_uint16(&buf, &tkey->mode);
+ dns_unmarshall_uint16(&buf, &tkey->error);
+ dns_unmarshall_uint16(&buf, &tkey->key_length);
+
+ if (!ERR_DNS_IS_OK(buf.error)) goto error;
+
+ if (tkey->key_length) {
+ if (!(tkey->key = TALLOC_ARRAY(tkey, uint8, tkey->key_length))) {
+ buf.error = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+ } else {
+ tkey->key = NULL;
+ }
+
+ dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
+ if (!ERR_DNS_IS_OK(buf.error)) goto error;
+
+ tkey->inception = (time_t)tmp_inception;
+ tkey->expiration = (time_t)tmp_expiration;
+
+ *ptkey = tkey;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(tkey);
+ return buf.error;
+}
+
+DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name,
+ time_t time_signed, uint16 fudge,
+ uint16 mac_length, const uint8 *mac,
+ uint16 original_id, uint16 error,
+ struct dns_rrec **prec)
+{
+ struct dns_buffer *buf;
+ struct dns_domain_name *algorithm;
+ DNS_ERROR err;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint16(buf, 0); /* time prefix */
+ dns_marshall_uint32(buf, time_signed);
+ dns_marshall_uint16(buf, fudge);
+ dns_marshall_uint16(buf, mac_length);
+ dns_marshall_buffer(buf, mac, mac_length);
+ dns_marshall_uint16(buf, original_id);
+ dns_marshall_uint16(buf, error);
+ dns_marshall_uint16(buf, 0); /* Other Size */
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
+ buf->offset, buf->data, prec);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16 *num_records, struct dns_rrec ***records)
+{
+ struct dns_rrec **new_records;
+
+ if (!(new_records = TALLOC_REALLOC_ARRAY(mem_ctx, *records,
+ struct dns_rrec *,
+ (*num_records)+1))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ new_records[*num_records] = talloc_move(new_records, &rec);
+
+ *num_records += 1;
+ *records = new_records;
+ return ERROR_DNS_SUCCESS;
+}
+
+/*
+ * Create a request that probes a server whether the list of IP addresses
+ * provides meets our expectations
+ */
+
+DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
+ const char *host, int num_ips,
+ const struct sockaddr_storage *sslist,
+ struct dns_update_request **preq)
+{
+ struct dns_update_request *req;
+ struct dns_rrec *rec;
+ DNS_ERROR err;
+ uint16 i;
+
+ err = dns_create_update(mem_ctx, zone, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ for (i=0; i<num_ips; i++) {
+ err = dns_create_name_in_use_record(req, host,
+ &sslist[i], &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
+
+DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *hostname,
+ const struct sockaddr_storage *ss_addrs,
+ size_t num_addrs,
+ struct dns_update_request **preq)
+{
+ struct dns_update_request *req;
+ struct dns_rrec *rec;
+ DNS_ERROR err;
+ size_t i;
+
+ err = dns_create_update(mem_ctx, domainname, &req);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ /*
+ * Use the same prereq as WinXP -- No CNAME records for this host.
+ */
+
+ err = dns_create_rrec(req, hostname, QTYPE_CNAME, DNS_CLASS_NONE,
+ 0, 0, NULL, &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * Delete any existing A records
+ */
+
+ err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
+ &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * .. and add our IPs
+ */
+
+ for ( i=0; i<num_addrs; i++ ) {
+ err = dns_create_a_record(req, hostname, 3600, &ss_addrs[i], &rec);
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
diff --git a/lib/addns/dnssock.c b/lib/addns/dnssock.c
new file mode 100644
index 0000000000..7c8bd418e5
--- /dev/null
+++ b/lib/addns/dnssock.c
@@ -0,0 +1,377 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <sys/time.h>
+#include <unistd.h>
+
+static int destroy_dns_connection(struct dns_connection *conn)
+{
+ return close(conn->s);
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_tcp_open( const char *nameserver,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **result )
+{
+ uint32_t ulAddress;
+ struct hostent *pHost;
+ struct sockaddr_in s_in;
+ struct dns_connection *conn;
+ int res;
+
+ if (!(conn = talloc(mem_ctx, struct dns_connection))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
+ if ( (pHost = gethostbyname( nameserver )) == NULL ) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_INVALID_NAME_SERVER;
+ }
+ memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+ }
+
+ conn->s = socket( PF_INET, SOCK_STREAM, 0 );
+ if (conn->s == -1) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ talloc_set_destructor(conn, destroy_dns_connection);
+
+ s_in.sin_family = AF_INET;
+ s_in.sin_addr.s_addr = ulAddress;
+ s_in.sin_port = htons( DNS_TCP_PORT );
+
+ res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
+ if (res == -1) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ conn->hType = DNS_TCP;
+
+ *result = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_udp_open( const char *nameserver,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **result )
+{
+ unsigned long ulAddress;
+ struct hostent *pHost;
+ struct sockaddr_in RecvAddr;
+ struct dns_connection *conn;
+
+ if (!(conn = talloc(NULL, struct dns_connection))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
+ if ( (pHost = gethostbyname( nameserver )) == NULL ) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_INVALID_NAME_SERVER;
+ }
+ memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+ }
+
+ /* Create a socket for sending data */
+
+ conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ if (conn->s == -1) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ talloc_set_destructor(conn, destroy_dns_connection);
+
+ /* Set up the RecvAddr structure with the IP address of
+ the receiver (in this example case "123.456.789.1")
+ and the specified port number. */
+
+ ZERO_STRUCT(RecvAddr);
+ RecvAddr.sin_family = AF_INET;
+ RecvAddr.sin_port = htons( DNS_UDP_PORT );
+ RecvAddr.sin_addr.s_addr = ulAddress;
+
+ conn->hType = DNS_UDP;
+ memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
+
+ *result = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **conn )
+{
+ switch ( dwType ) {
+ case DNS_TCP:
+ return dns_tcp_open( nameserver, mem_ctx, conn );
+ case DNS_UDP:
+ return dns_udp_open( nameserver, mem_ctx, conn );
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
+{
+ size_t total = 0;
+
+ while (total < len) {
+
+ ssize_t ret = write(fd, data + total, len - total);
+
+ if (ret <= 0) {
+ /*
+ * EOF or error
+ */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ total += ret;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
+ const struct dns_buffer *buf)
+{
+ uint16 len = htons(buf->offset);
+ DNS_ERROR err;
+
+ err = write_all(conn->s, (uint8 *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ return write_all(conn->s, buf->data, buf->offset);
+}
+
+static DNS_ERROR dns_send_udp(struct dns_connection *conn,
+ const struct dns_buffer *buf)
+{
+ ssize_t ret;
+
+ ret = sendto(conn->s, buf->data, buf->offset, 0,
+ (struct sockaddr *)&conn->RecvAddr,
+ sizeof(conn->RecvAddr));
+
+ if (ret != buf->offset) {
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
+{
+ if (conn->hType == DNS_TCP) {
+ return dns_send_tcp(conn, buf);
+ }
+
+ if (conn->hType == DNS_UDP) {
+ return dns_send_udp(conn, buf);
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
+{
+ size_t total = 0;
+ fd_set rfds;
+ struct timeval tv;
+
+ while (total < len) {
+ ssize_t ret;
+ int fd_ready;
+
+ FD_ZERO( &rfds );
+ FD_SET( fd, &rfds );
+
+ /* 10 second timeout */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
+ if ( fd_ready == 0 ) {
+ /* read timeout */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ ret = read(fd, data + total, len - total);
+ if (ret <= 0) {
+ /* EOF or error */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ total += ret;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ struct dns_buffer *buf;
+ DNS_ERROR err;
+ uint16 len;
+
+ if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = read_all(conn->s, (uint8 *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(err)) {
+ return err;
+ }
+
+ buf->size = ntohs(len);
+
+ if (buf->size) {
+ if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_NO_MEMORY;
+ }
+ } else {
+ buf->data = NULL;
+ }
+
+ err = read_all(conn->s, buf->data, buf->size);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(buf);
+ return err;
+ }
+
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ struct dns_buffer *buf;
+ ssize_t received;
+
+ if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ /*
+ * UDP based DNS can only be 512 bytes
+ */
+
+ if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ received = recv(conn->s, (void *)buf->data, 512, 0);
+
+ if (received == -1) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ if (received > 512) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_BAD_RESPONSE;
+ }
+
+ buf->size = received;
+ buf->offset = 0;
+
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ if (conn->hType == DNS_TCP) {
+ return dns_receive_tcp(mem_ctx, conn, presult);
+ }
+
+ if (conn->hType == DNS_UDP) {
+ return dns_receive_udp(mem_ctx, conn, presult);
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ const struct dns_request *req,
+ struct dns_request **resp)
+{
+ struct dns_buffer *buf = NULL;
+ DNS_ERROR err;
+
+ err = dns_marshall_request(conn, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_send(conn, buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+ TALLOC_FREE(buf);
+
+ err = dns_receive(mem_ctx, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_unmarshall_request(mem_ctx, buf, resp);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_update_request *up_req,
+ struct dns_update_request **up_resp)
+{
+ struct dns_request *resp;
+ DNS_ERROR err;
+
+ err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
+ &resp);
+
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ *up_resp = dns_request2update(resp);
+ return ERROR_DNS_SUCCESS;
+}
diff --git a/lib/addns/dnsutils.c b/lib/addns/dnsutils.c
new file mode 100644
index 0000000000..37b862c7f0
--- /dev/null
+++ b/lib/addns/dnsutils.c
@@ -0,0 +1,151 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <ctype.h>
+
+static DNS_ERROR LabelList( TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct dns_domain_label **presult )
+{
+ struct dns_domain_label *result;
+ const char *dot;
+
+ for (dot = name; *dot != '\0'; dot += 1) {
+ char c = *dot;
+
+ if (c == '.')
+ break;
+
+ if (c == '-') continue;
+ if ((c >= 'a') && (c <= 'z')) continue;
+ if ((c >= 'A') && (c <= 'Z')) continue;
+ if ((c >= '0') && (c <= '9')) continue;
+
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if ((dot - name) > 63) {
+ /*
+ * DNS labels can only be 63 chars long
+ */
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct dns_domain_label))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if (*dot == '\0') {
+ /*
+ * No dot around, so this is the last component
+ */
+
+ if (!(result->label = talloc_strdup(result, name))) {
+ TALLOC_FREE(result);
+ return ERROR_DNS_NO_MEMORY;
+ }
+ result->len = strlen(result->label);
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+ }
+
+ if (dot[1] == '.') {
+ /*
+ * Two dots in a row, reject
+ */
+
+ TALLOC_FREE(result);
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if (dot[1] != '\0') {
+ /*
+ * Something follows, get the rest
+ */
+
+ DNS_ERROR err = LabelList(result, dot+1, &result->next);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(result);
+ return err;
+ }
+ }
+
+ result->len = (dot - name);
+
+ if (!(result->label = talloc_strndup(result, name, result->len))) {
+ TALLOC_FREE(result);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_domain_name_from_string( TALLOC_CTX *mem_ctx,
+ const char *pszDomainName,
+ struct dns_domain_name **presult )
+{
+ struct dns_domain_name *result;
+ DNS_ERROR err;
+
+ if (!(result = talloc(mem_ctx, struct dns_domain_name))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = LabelList( result, pszDomainName, &result->pLabelList );
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(result);
+ return err;
+ }
+
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+char *dns_generate_keyname( TALLOC_CTX *mem_ctx )
+{
+ char *result = NULL;
+#if defined(WITH_DNS_UPDATES)
+
+ uuid_t uuid;
+
+ /*
+ * uuid_unparse gives 36 bytes plus '\0'
+ */
+ if (!(result = TALLOC_ARRAY(mem_ctx, char, 37))) {
+ return NULL;
+ }
+
+ uuid_generate( uuid );
+ uuid_unparse( uuid, result );
+
+#endif
+
+ return result;
+}
diff --git a/lib/addns/error.c b/lib/addns/error.c
new file mode 100644
index 0000000000..361388cea3
--- /dev/null
+++ b/lib/addns/error.c
@@ -0,0 +1,59 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2010 Guenther Deschner
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include "dnserr.h"
+
+typedef struct {
+ const char *dns_errstr;
+ DNS_ERROR dns_errcode;
+} dns_err_code_struct;
+
+static const dns_err_code_struct dns_errs[] =
+{
+ { "ERROR_DNS_SUCCESS", ERROR_DNS_SUCCESS },
+ { "ERROR_DNS_RECORD_NOT_FOUND", ERROR_DNS_RECORD_NOT_FOUND },
+ { "ERROR_DNS_BAD_RESPONSE", ERROR_DNS_BAD_RESPONSE },
+ { "ERROR_DNS_INVALID_PARAMETER", ERROR_DNS_INVALID_PARAMETER },
+ { "ERROR_DNS_NO_MEMORY", ERROR_DNS_NO_MEMORY },
+ { "ERROR_DNS_INVALID_NAME_SERVER", ERROR_DNS_INVALID_NAME_SERVER },
+ { "ERROR_DNS_CONNECTION_FAILED", ERROR_DNS_CONNECTION_FAILED },
+ { "ERROR_DNS_GSS_ERROR", ERROR_DNS_GSS_ERROR },
+ { "ERROR_DNS_INVALID_NAME", ERROR_DNS_INVALID_NAME },
+ { "ERROR_DNS_INVALID_MESSAGE", ERROR_DNS_INVALID_MESSAGE },
+ { "ERROR_DNS_SOCKET_ERROR", ERROR_DNS_SOCKET_ERROR },
+ { "ERROR_DNS_UPDATE_FAILED", ERROR_DNS_UPDATE_FAILED },
+ { NULL, ERROR_DNS_SUCCESS },
+};
+
+const char *dns_errstr(DNS_ERROR err)
+{
+ int i;
+
+ for (i=0; dns_errs[i].dns_errstr != NULL; i++) {
+ if (ERR_DNS_EQUAL(err, dns_errs[i].dns_errcode)) {
+ return dns_errs[i].dns_errstr;
+ }
+ }
+
+ return NULL;
+}
diff --git a/lib/addns/wscript_build b/lib/addns/wscript_build
new file mode 100644
index 0000000000..69a4716245
--- /dev/null
+++ b/lib/addns/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('addns',
+ source='dnsrecord.c dnsutils.c dnssock.c dnsgss.c dnsmarshall.c error.c',
+ public_deps='talloc krb5 k5crypto com_err gssapi gssapi_krb5 uuid',
+ private_library=True,
+ vars=locals())