summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-slapi-plugins/ipa-dns/ipa_dns.c
blob: 0769a54aadc54a49909474cf86f8ebc0d228e759 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/** BEGIN COPYRIGHT BLOCK
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; version 2 of the License.
 *
 * This Program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
 * Copyright (C) 2013 Red Hat, Inc.
 *
 * Authors:
 * original authors of 389 example ldap/servers/slapd/test-plugins/testpreop.c
 * Petr Spacek <pspacek@redhat.com>
 *
 * All rights reserved.
 *
 * END COPYRIGHT BLOCK **/

/*
 * This is 389 DS plug-in with supporting functions for IPA-integrated DNS.
 *
 * To test this plug-in, stop the server, edit the dse.ldif file
 * (in the <server_root>/slapd-<server_id>/config directory)
 * and add the following lines before restarting the server:
 *
 * dn: cn=IPA DNS,cn=plugins,cn=config
 * objectClass: top
 * objectClass: nsslapdPlugin
 * objectClass: extensibleObject
 * cn: IPA DNS
 * nsslapd-pluginDescription: IPA DNS support plugin
 * nsslapd-pluginEnabled: on
 * nsslapd-pluginId: ipa_dns
 * nsslapd-pluginInitfunc: ipadns_init
 * nsslapd-pluginPath: libipa_dns.so
 * nsslapd-pluginType: preoperation
 * nsslapd-pluginVendor: Red Hat, Inc.
 * nsslapd-pluginVersion: 1.0
 * nsslapd-plugin-depends-on-type: database
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include "slapi-plugin.h"
#include "util.h"

#define IPA_PLUGIN_NAME "ipa_dns"
#define IPADNS_CLASS_ZONE "idnsZone"
#define IPADNS_ATTR_SERIAL "idnsSOASerial"
#define IPADNS_DEFAULT_SERIAL "1"

#define EFALSE 0
#define ETRUE 1

Slapi_PluginDesc ipadns_desc = { IPA_PLUGIN_NAME, "Red Hat, Inc.", "1.0",
				"IPA DNS support plugin" };

/* Global variable with "constant" = IPADNS_ZONE_SERIAL. */
Slapi_Value *value_zone = NULL;

/**
 * Determine if given entry represents IPA DNS zone.
 *
 * \return \c 0 when objectClass idnsZone is not present in the entry.
 * \return \c 1 when objectClass idnsZone is present in the entry.
 * \return \c -1 when some error occurred.
 */
int
ipadns_entry_iszone( Slapi_Entry *entry ) {
	Slapi_Attr *obj_class = NULL;
	Slapi_Value *value = NULL;
	char *dn = NULL;
	int hint = 0;

	dn = slapi_entry_get_dn( entry );

	if ( slapi_entry_attr_find( entry, SLAPI_ATTR_OBJECTCLASS, &obj_class )
	    != 0) {
		LOG( "Object without objectClass encountered: entry '%s'\n",
		    dn );
		return EFAIL;
	}

	if ( slapi_attr_first_value( obj_class, &value ) != 0 ) {
		LOG( "Cannot iterate over objectClass values in entry '%s'\n",
		    dn );
		return EOK;
	}

	do {
		if ( slapi_value_compare( obj_class, value, value_zone ) == 0 )
			return ETRUE; /* Entry is a DNS zone */

		hint = slapi_attr_next_value( obj_class, hint, &value );
	} while ( hint != -1 );

	return EFALSE; /* Entry is not a DNS zone */
}

/**
 * The server calls this plug-in function before executing LDAP ADD operation.
 *
 * ipadns_add function adds default value to idnsSOAserial attribute
 * in idnsZone objects if the the attribute is not present.
 *
 * Default value is added only to objects coming from other servers
 * via replication.
 */
int
ipadns_add( Slapi_PBlock *pb )
{
	Slapi_Entry	*e = NULL;
	Slapi_Attr	*a = NULL;
	char 		*dn = NULL;
	int		cnt;
	int 		ret;
	int		is_repl_op;

	if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION,
			      &is_repl_op ) != 0 ) {
		LOG_FATAL( "slapi_pblock_get SLAPI_IS_REPLICATED_OPERATION "
			  "failed!?\n" );
		return EFAIL;
	}

	/* Mangle only ADDs coming from replication. */
	if ( !is_repl_op )
		return EOK;

	/* Get the entry that is about to be added. */
	if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) != 0 ) {
		LOG( "Could not get entry\n" );
		return EFAIL;
	}
	dn = slapi_entry_get_dn( e );

	/* Do nothing if entry doesn't represent IPA DNS zone. */
	ret = ipadns_entry_iszone( e );
	if ( ret == EFALSE )
		return EOK;
	else if ( ret == EFAIL ) {
		LOG( "Could not check objectClasses in entry '%s'\n", dn );
		return EFAIL; /* TODO: Should I return OK to not block DS? */
	}

	/* Do nothing if the entry already has idnsSOASerial attribute set
	 * and a value is present. */
	if ( slapi_entry_attr_find( e, IPADNS_ATTR_SERIAL, &a ) == 0 ) {
		if ( slapi_attr_get_numvalues( a, &cnt ) != 0 ) {
			LOG( "Could not get value count for attribute '%s' "
			     "in entry '%s'\n", IPADNS_ATTR_SERIAL, dn );
			return EFAIL;
		} else if ( cnt != 0 ) {
			return EOK;
		}
	}

	if ( slapi_entry_add_string( e, IPADNS_ATTR_SERIAL,
				    IPADNS_DEFAULT_SERIAL ) != 0 ) {
		LOG( "Could not add default SOA serial to entry '%s'\n", dn );
		return EFAIL;
	}

	return EOK; /* allow the operation to continue */
}

static int
ipadns_close( Slapi_PBlock *pb )
{
	( void ) pb;
	if ( value_zone )
		slapi_value_free( &value_zone );

	return EOK;
}

/* Initialization function. */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
ipadns_init( Slapi_PBlock *pb )
{
	/* Register the two pre-operation plug-in functions,
	   and specify the server plug-in version. */
	if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
	    SLAPI_PLUGIN_VERSION_03 ) != 0 ||
	    slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
	    (void *)&ipadns_desc ) != 0 ||
	    slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN,
	    (void *) ipadns_close ) != 0 ||
	    slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ADD_FN,
	    (void *) ipadns_add ) != 0 ) {
		LOG_FATAL( "Failed to set version and function\n" );
		return EFAIL;
	}

	value_zone = slapi_value_new_string( IPADNS_CLASS_ZONE );

	return EOK;
}