1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * As of BIND 8.2.2, ISC (a) removed res_mkupdate(), res_update(), and
8  * res_mkupdrec() from what they consider the supported interface. The
9  * functions still exist, but their calling interface has changed, since
10  * the ns_updrec structure has changed.
11  *
12  * It seems probable that res_mkupdate()  etc. will return, though possibly
13  * with other changes, in some future BIND release. In order to avoid
14  * going to PSARC twice (once to remove the functions, and then again to
15  * add them back), we retain the old interface as a wrapper around the
16  * new one.
17  */
18 
19 #include <port_before.h>
20 
21 #include <malloc.h>
22 #include <strings.h>
23 #include <sys/types.h>
24 #include <netinet/in.h>
25 
26 /* get the Solaris ns_updrec before any renaming happens */
27 #include <arpa/nameser.h>
28 
29 /* get the __ISC_ns_updrec */
30 #include <res_update.h>
31 
32 #include <port_after.h>
33 
34 /* un-rename ns_updrec and res_* functions so we can wrap them */
35 #undef	ns_updrec
36 #undef	res_mkupdate
37 #undef	res_update
38 #undef	res_mkupdrec
39 #undef	res_freeupdrec
40 #undef	res_nmkupdate
41 #undef	res_nupdate
42 
43 void	res_freeupdrec(ns_updrec *);
44 
45 static int
old2new(ns_updrec * old,__ISC_ns_updrec * new)46 old2new(ns_updrec *old, __ISC_ns_updrec *new) {
47 
48 	if (old->r_dname != 0) {
49 		if ((new->r_dname = strdup(old->r_dname)) == 0)
50 			return (-1);
51 	} else {
52 		new->r_dname = 0;
53 	}
54 
55 	new->r_glink.prev =
56 	new->r_glink.next =
57 	new->r_link.prev  =
58 	new->r_link.next  = 0;
59 
60 	new->r_section	= old->r_section;
61 	new->r_class	= old->r_class;
62 	new->r_type	= old->r_type;
63 	new->r_ttl	= old->r_ttl;
64 	new->r_data	= old->r_data;
65 	new->r_size	= old->r_size;
66 	new->r_opcode	= old->r_opcode;
67 	new->r_dp	= old->r_dp;
68 	new->r_deldp	= old->r_deldp;
69 	new->r_zone	= old->r_zone;
70 
71 	return (0);
72 }
73 
74 
75 static int
new2old(__ISC_ns_updrec * new,ns_updrec * old)76 new2old(__ISC_ns_updrec *new, ns_updrec *old) {
77 	/* XXX r_prev and r_next unchanged */
78 	if (new->r_dname != 0) {
79 		if ((old->r_dname = strdup(new->r_dname)) == 0)
80 			return (-1);
81 	} else {
82 		old->r_dname = 0;
83 	}
84 	old->r_section	= new->r_section;
85 	old->r_class	= new->r_class;
86 	old->r_type	= new->r_type;
87 	old->r_ttl	= new->r_ttl;
88 	old->r_data	= new->r_data;
89 	old->r_size	= new->r_size;
90 	old->r_opcode	= new->r_opcode;
91 	old->r_grpnext	= 0;			/* XXX */
92 	old->r_dp	= new->r_dp;
93 	old->r_deldp	= new->r_deldp;
94 	old->r_zone	= new->r_zone;
95 
96 	return (0);
97 }
98 
99 
100 static void
delete_list(__ISC_ns_updrec * list)101 delete_list(__ISC_ns_updrec *list) {
102 
103 	__ISC_ns_updrec	*next;
104 
105 	for (; list != 0; list = next) {
106 		next = list->r_link.next;
107 		__ISC_res_freeupdrec(list);
108 	}
109 }
110 
111 
112 static __ISC_ns_updrec *
copy_list(ns_updrec * old,int do_glink)113 copy_list(ns_updrec *old, int do_glink) {
114 
115 	__ISC_ns_updrec *list = 0, *r, *p;
116 
117 	if (old == 0)
118 		return (0);
119 
120 	for (p = 0; old != 0; old = old->r_next, p = r) {
121 		if ((r = calloc(1, sizeof (*r))) == 0 ||
122 			old2new(old, r) != 0) {
123 			free(r);
124 			delete_list(list);
125 			return (0);
126 		}
127 		r->r_link.prev = p;
128 		r->r_link.next = 0;
129 		/* res_update and res_nupdate want r_glink set up like this */
130 		if (do_glink) {
131 			r->r_glink.prev = p;
132 			r->r_glink.next = 0;
133 		} else {
134 			r->r_glink.prev = (void *)-1;
135 			r->r_glink.next = (void *)-1;
136 		}
137 		if (p != 0) {
138 			p->r_link.next = r;
139 			if (do_glink) {
140 				p->r_glink.next = r;
141 			}
142 		} else {
143 			list = r;
144 		}
145 	}
146 	return (list);
147 }
148 
149 
150 int
res_mkupdate(ns_updrec * rrecp_in,uchar_t * buf,int length)151 res_mkupdate(ns_updrec  *rrecp_in, uchar_t *buf, int length) {
152 
153 	__ISC_ns_updrec	*r;
154 	int		ret;
155 
156 	if ((r = copy_list(rrecp_in, 1)) == 0)
157 		return (-1);
158 
159 	ret = __ISC_res_mkupdate(r, buf, length);
160 
161 	delete_list(r);
162 
163 	return (ret);
164 }
165 
166 int
res_nmkupdate(res_state statp,ns_updrec * rrecp_in,uchar_t * buf,int length)167 res_nmkupdate(res_state statp, ns_updrec  *rrecp_in, uchar_t *buf, int length) {
168 
169 	__ISC_ns_updrec	*r;
170 	int		ret;
171 
172 	if ((r = copy_list(rrecp_in, 1)) == 0)
173 		return (-1);
174 
175 	ret = __ISC_res_nmkupdate(statp, r, buf, length);
176 
177 	delete_list(r);
178 
179 	return (ret);
180 }
181 
182 
183 int
res_update(ns_updrec * rrecp_in)184 res_update(ns_updrec *rrecp_in) {
185 
186 	__ISC_ns_updrec	*r;
187 	int		ret;
188 
189 	if ((r = copy_list(rrecp_in, 0)) == 0)
190 		return (-1);
191 
192 	ret = __ISC_res_update(r);
193 
194 	delete_list(r);
195 
196 	return (ret);
197 }
198 
199 int
res_nupdate(res_state statp,ns_updrec * rrecp_in,ns_tsig_key * key)200 res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
201 
202 	__ISC_ns_updrec	*r;
203 	int		ret;
204 
205 	if ((r = copy_list(rrecp_in, 0)) == 0)
206 		return (-1);
207 
208 	ret = __ISC_res_nupdate(statp, r, key);
209 
210 	delete_list(r);
211 
212 	return (ret);
213 }
214 
215 
216 
217 ns_updrec *
res_mkupdrec(int section,const char * dname,uint_t class,uint_t type,uint_t ttl)218 res_mkupdrec(int section, const char *dname, uint_t class, uint_t type,
219 		uint_t ttl) {
220 
221 	__ISC_ns_updrec	*n;
222 	ns_updrec	*o;
223 
224 	n = __ISC_res_mkupdrec(section, dname, class, type, ttl);
225 	if (n == 0)
226 		return (0);
227 
228 	if ((o = calloc(1, sizeof (*o))) != 0) {
229 		if (new2old(n, o) != 0) {
230 			res_freeupdrec(o);
231 			o = 0;
232 		}
233 	}
234 
235 	__ISC_res_freeupdrec(n);
236 
237 	return (o);
238 }
239 
240 
241 void
res_freeupdrec(ns_updrec * rrecp)242 res_freeupdrec(ns_updrec *rrecp) {
243 	if (rrecp == 0)
244 		return;
245 	/* Note: freeing r_dp is the caller's responsibility. */
246 	if (rrecp->r_dname != NULL)
247 		free(rrecp->r_dname);
248 	free(rrecp);
249 }
250