diff options
author | Günther Deschner <gd@samba.org> | 2011-01-06 14:53:04 +0100 |
---|---|---|
committer | Günther Deschner <gd@samba.org> | 2011-01-06 16:42:56 +0100 |
commit | 7ee75c95481f0d13598577361d18e96cb8394b9c (patch) | |
tree | 9dc79864581847d17d7c74fe63cf3bba6970cced /lib | |
parent | 4e0d0af9e89e23a5daea8048deff5c9057f08bb9 (diff) | |
download | samba-7ee75c95481f0d13598577361d18e96cb8394b9c.tar.gz |
lib/addns: move DNS client library to the main directory.
Guenther
Diffstat (limited to 'lib')
-rw-r--r-- | lib/addns/addns.h | 30 | ||||
-rw-r--r-- | lib/addns/dns.h | 540 | ||||
-rw-r--r-- | lib/addns/dnserr.h | 87 | ||||
-rw-r--r-- | lib/addns/dnsgss.c | 334 | ||||
-rw-r--r-- | lib/addns/dnsmarshall.c | 530 | ||||
-rw-r--r-- | lib/addns/dnsrecord.c | 422 | ||||
-rw-r--r-- | lib/addns/dnssock.c | 377 | ||||
-rw-r--r-- | lib/addns/dnsutils.c | 151 | ||||
-rw-r--r-- | lib/addns/error.c | 59 | ||||
-rw-r--r-- | lib/addns/wscript_build | 7 |
10 files changed, 2537 insertions, 0 deletions
diff --git a/lib/addns/addns.h b/lib/addns/addns.h new file mode 100644 index 00000000000..6ef9329df8a --- /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 00000000000..29f1ed3e997 --- /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 00000000000..9e049ac3a9a --- /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 00000000000..c9037417da9 --- /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 00000000000..5530290c57a --- /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 00000000000..559c2644d44 --- /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 00000000000..7c8bd418e57 --- /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 00000000000..37b862c7f07 --- /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 00000000000..361388cea3c --- /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 00000000000..69a47162451 --- /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()) |