xref: /freebsd-src/crypto/heimdal/lib/kadm5/log.c (revision 8373020d34ceb1ac55d8f43333c1ca3680185b39)
1b528cefcSMark Murray /*
2*8373020dSJacques Vidrine  * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "kadm5_locl.h"
35b528cefcSMark Murray 
36*8373020dSJacques Vidrine RCSID("$Id: log.c,v 1.19 2002/05/24 15:19:21 joda Exp $");
37b528cefcSMark Murray 
38b528cefcSMark Murray /*
39b528cefcSMark Murray  * A log record consists of:
40b528cefcSMark Murray  *
41b528cefcSMark Murray  * version number		4 bytes
42b528cefcSMark Murray  * time in seconds		4 bytes
43b528cefcSMark Murray  * operation (enum kadm_ops)	4 bytes
44b528cefcSMark Murray  * length of record		4 bytes
45b528cefcSMark Murray  * data...			n bytes
46b528cefcSMark Murray  * length of record		4 bytes
47b528cefcSMark Murray  * version number		4 bytes
48b528cefcSMark Murray  *
49b528cefcSMark Murray  */
50b528cefcSMark Murray 
51b528cefcSMark Murray kadm5_ret_t
525e9cd1aeSAssar Westerlund kadm5_log_get_version_fd (int fd,
53b528cefcSMark Murray 			  u_int32_t *ver)
54b528cefcSMark Murray {
55b528cefcSMark Murray     int ret;
56b528cefcSMark Murray     krb5_storage *sp;
57b528cefcSMark Murray     int32_t old_version;
58b528cefcSMark Murray 
59b528cefcSMark Murray     ret = lseek (fd, 0, SEEK_END);
60b528cefcSMark Murray     if(ret < 0)
61b528cefcSMark Murray 	return errno;
62b528cefcSMark Murray     if(ret == 0) {
63b528cefcSMark Murray 	*ver = 0;
64b528cefcSMark Murray 	return 0;
65b528cefcSMark Murray     }
66b528cefcSMark Murray     sp = krb5_storage_from_fd (fd);
67*8373020dSJacques Vidrine     krb5_storage_seek(sp, -4, SEEK_CUR);
68b528cefcSMark Murray     krb5_ret_int32 (sp, &old_version);
69b528cefcSMark Murray     *ver = old_version;
70b528cefcSMark Murray     krb5_storage_free(sp);
71b528cefcSMark Murray     lseek (fd, 0, SEEK_END);
72b528cefcSMark Murray     return 0;
73b528cefcSMark Murray }
74b528cefcSMark Murray 
75b528cefcSMark Murray kadm5_ret_t
765e9cd1aeSAssar Westerlund kadm5_log_get_version (kadm5_server_context *context, u_int32_t *ver)
775e9cd1aeSAssar Westerlund {
785e9cd1aeSAssar Westerlund     return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
795e9cd1aeSAssar Westerlund }
805e9cd1aeSAssar Westerlund 
815e9cd1aeSAssar Westerlund kadm5_ret_t
825e9cd1aeSAssar Westerlund kadm5_log_set_version (kadm5_server_context *context, u_int32_t vno)
835e9cd1aeSAssar Westerlund {
845e9cd1aeSAssar Westerlund     kadm5_log_context *log_context = &context->log_context;
855e9cd1aeSAssar Westerlund 
865e9cd1aeSAssar Westerlund     log_context->version = vno;
875e9cd1aeSAssar Westerlund     return 0;
885e9cd1aeSAssar Westerlund }
895e9cd1aeSAssar Westerlund 
905e9cd1aeSAssar Westerlund kadm5_ret_t
91b528cefcSMark Murray kadm5_log_init (kadm5_server_context *context)
92b528cefcSMark Murray {
93b528cefcSMark Murray     int fd;
94b528cefcSMark Murray     kadm5_ret_t ret;
95b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
96b528cefcSMark Murray 
97b528cefcSMark Murray     if (log_context->log_fd != -1)
98b528cefcSMark Murray 	return 0;
99b528cefcSMark Murray     fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
100b528cefcSMark Murray     if (fd < 0)
101b528cefcSMark Murray 	return errno;
102b528cefcSMark Murray     if (flock (fd, LOCK_EX) < 0) {
103b528cefcSMark Murray 	close (fd);
104b528cefcSMark Murray 	return errno;
105b528cefcSMark Murray     }
106b528cefcSMark Murray 
1075e9cd1aeSAssar Westerlund     ret = kadm5_log_get_version_fd (fd, &log_context->version);
108b528cefcSMark Murray     if (ret)
109b528cefcSMark Murray 	return ret;
110b528cefcSMark Murray 
111b528cefcSMark Murray     log_context->log_fd  = fd;
112b528cefcSMark Murray     return 0;
113b528cefcSMark Murray }
114b528cefcSMark Murray 
115b528cefcSMark Murray kadm5_ret_t
1165e9cd1aeSAssar Westerlund kadm5_log_reinit (kadm5_server_context *context)
1175e9cd1aeSAssar Westerlund {
1185e9cd1aeSAssar Westerlund     int fd;
1195e9cd1aeSAssar Westerlund     kadm5_log_context *log_context = &context->log_context;
1205e9cd1aeSAssar Westerlund 
1215e9cd1aeSAssar Westerlund     if (log_context->log_fd != -1) {
1225e9cd1aeSAssar Westerlund 	close (log_context->log_fd);
1235e9cd1aeSAssar Westerlund 	log_context->log_fd = -1;
1245e9cd1aeSAssar Westerlund     }
1255e9cd1aeSAssar Westerlund     fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
1265e9cd1aeSAssar Westerlund     if (fd < 0)
1275e9cd1aeSAssar Westerlund 	return errno;
1285e9cd1aeSAssar Westerlund     if (flock (fd, LOCK_EX) < 0) {
1295e9cd1aeSAssar Westerlund 	close (fd);
1305e9cd1aeSAssar Westerlund 	return errno;
1315e9cd1aeSAssar Westerlund     }
1325e9cd1aeSAssar Westerlund 
1335e9cd1aeSAssar Westerlund     log_context->version = 0;
1345e9cd1aeSAssar Westerlund     log_context->log_fd  = fd;
1355e9cd1aeSAssar Westerlund     return 0;
1365e9cd1aeSAssar Westerlund }
1375e9cd1aeSAssar Westerlund 
1385e9cd1aeSAssar Westerlund 
1395e9cd1aeSAssar Westerlund kadm5_ret_t
140b528cefcSMark Murray kadm5_log_end (kadm5_server_context *context)
141b528cefcSMark Murray {
142b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
143b528cefcSMark Murray     int fd = log_context->log_fd;
144b528cefcSMark Murray 
145b528cefcSMark Murray     flock (fd, LOCK_UN);
146b528cefcSMark Murray     close(fd);
147b528cefcSMark Murray     log_context->log_fd = -1;
148b528cefcSMark Murray     return 0;
149b528cefcSMark Murray }
150b528cefcSMark Murray 
151b528cefcSMark Murray static kadm5_ret_t
152b528cefcSMark Murray kadm5_log_preamble (kadm5_server_context *context,
153b528cefcSMark Murray 		    krb5_storage *sp,
154b528cefcSMark Murray 		    enum kadm_ops op)
155b528cefcSMark Murray {
156b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
157b528cefcSMark Murray     kadm5_ret_t kadm_ret;
158b528cefcSMark Murray 
159b528cefcSMark Murray     kadm_ret = kadm5_log_init (context);
160b528cefcSMark Murray     if (kadm_ret)
161b528cefcSMark Murray 	return kadm_ret;
162b528cefcSMark Murray 
163b528cefcSMark Murray     krb5_store_int32 (sp, ++log_context->version);
164b528cefcSMark Murray     krb5_store_int32 (sp, time(NULL));
165b528cefcSMark Murray     krb5_store_int32 (sp, op);
166b528cefcSMark Murray     return 0;
167b528cefcSMark Murray }
168b528cefcSMark Murray 
169b528cefcSMark Murray static kadm5_ret_t
170b528cefcSMark Murray kadm5_log_postamble (kadm5_log_context *context,
171b528cefcSMark Murray 		     krb5_storage *sp)
172b528cefcSMark Murray {
173b528cefcSMark Murray     krb5_store_int32 (sp, context->version);
174b528cefcSMark Murray     return 0;
175b528cefcSMark Murray }
176b528cefcSMark Murray 
177b528cefcSMark Murray /*
178b528cefcSMark Murray  * flush the log record in `sp'.
179b528cefcSMark Murray  */
180b528cefcSMark Murray 
181b528cefcSMark Murray static kadm5_ret_t
182b528cefcSMark Murray kadm5_log_flush (kadm5_log_context *log_context,
183b528cefcSMark Murray 		 krb5_storage *sp)
184b528cefcSMark Murray {
185b528cefcSMark Murray     krb5_data data;
186b528cefcSMark Murray     size_t len;
187b528cefcSMark Murray     int ret;
188b528cefcSMark Murray 
189b528cefcSMark Murray     krb5_storage_to_data(sp, &data);
190b528cefcSMark Murray     len = data.length;
191b528cefcSMark Murray     ret = write (log_context->log_fd, data.data, len);
192b528cefcSMark Murray     if (ret != len) {
193b528cefcSMark Murray 	krb5_data_free(&data);
194b528cefcSMark Murray 	return errno;
195b528cefcSMark Murray     }
196b528cefcSMark Murray     if (fsync (log_context->log_fd) < 0) {
197b528cefcSMark Murray 	krb5_data_free(&data);
198b528cefcSMark Murray 	return errno;
199b528cefcSMark Murray     }
200b528cefcSMark Murray     /*
201b528cefcSMark Murray      * Try to send a signal to any running `ipropd-master'
202b528cefcSMark Murray      */
203b528cefcSMark Murray     sendto (log_context->socket_fd,
204b528cefcSMark Murray 	    (void *)&log_context->version,
205b528cefcSMark Murray 	    sizeof(log_context->version),
206b528cefcSMark Murray 	    0,
207b528cefcSMark Murray 	    (struct sockaddr *)&log_context->socket_name,
208b528cefcSMark Murray 	    sizeof(log_context->socket_name));
209b528cefcSMark Murray 
210b528cefcSMark Murray     krb5_data_free(&data);
211b528cefcSMark Murray     return 0;
212b528cefcSMark Murray }
213b528cefcSMark Murray 
214b528cefcSMark Murray /*
215b528cefcSMark Murray  * Add a `create' operation to the log.
216b528cefcSMark Murray  */
217b528cefcSMark Murray 
218b528cefcSMark Murray kadm5_ret_t
219b528cefcSMark Murray kadm5_log_create (kadm5_server_context *context,
220b528cefcSMark Murray 		  hdb_entry *ent)
221b528cefcSMark Murray {
222b528cefcSMark Murray     krb5_storage *sp;
223b528cefcSMark Murray     kadm5_ret_t ret;
224b528cefcSMark Murray     krb5_data value;
225b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
226b528cefcSMark Murray 
227b528cefcSMark Murray     sp = krb5_storage_emem();
228b528cefcSMark Murray     ret = hdb_entry2value (context->context, ent, &value);
229b528cefcSMark Murray     if (ret) {
230b528cefcSMark Murray 	krb5_storage_free(sp);
231b528cefcSMark Murray 	return ret;
232b528cefcSMark Murray     }
233b528cefcSMark Murray     ret = kadm5_log_preamble (context, sp, kadm_create);
234b528cefcSMark Murray     if (ret) {
235b528cefcSMark Murray 	krb5_data_free (&value);
236b528cefcSMark Murray 	krb5_storage_free(sp);
237b528cefcSMark Murray 	return ret;
238b528cefcSMark Murray     }
239b528cefcSMark Murray     krb5_store_int32 (sp, value.length);
240*8373020dSJacques Vidrine     krb5_storage_write(sp, value.data, value.length);
241b528cefcSMark Murray     krb5_store_int32 (sp, value.length);
242b528cefcSMark Murray     krb5_data_free (&value);
243b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
244b528cefcSMark Murray     if (ret) {
245b528cefcSMark Murray 	krb5_storage_free (sp);
246b528cefcSMark Murray 	return ret;
247b528cefcSMark Murray     }
248b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
249b528cefcSMark Murray     krb5_storage_free (sp);
250b528cefcSMark Murray     if (ret)
251b528cefcSMark Murray 	return ret;
252b528cefcSMark Murray     ret = kadm5_log_end (context);
253b528cefcSMark Murray     return ret;
254b528cefcSMark Murray }
255b528cefcSMark Murray 
256b528cefcSMark Murray /*
257b528cefcSMark Murray  * Read the data of a create log record from `sp' and change the
258b528cefcSMark Murray  * database.
259b528cefcSMark Murray  */
260b528cefcSMark Murray 
261b528cefcSMark Murray kadm5_ret_t
262b528cefcSMark Murray kadm5_log_replay_create (kadm5_server_context *context,
263b528cefcSMark Murray 			 u_int32_t ver,
264b528cefcSMark Murray 			 u_int32_t len,
265b528cefcSMark Murray 			 krb5_storage *sp)
266b528cefcSMark Murray {
267b528cefcSMark Murray     krb5_error_code ret;
268b528cefcSMark Murray     krb5_data data;
269b528cefcSMark Murray     hdb_entry ent;
270b528cefcSMark Murray 
271b528cefcSMark Murray     krb5_data_alloc (&data, len);
272*8373020dSJacques Vidrine     krb5_storage_read (sp, data.data, len);
273b528cefcSMark Murray     ret = hdb_value2entry (context->context, &data, &ent);
274b528cefcSMark Murray     krb5_data_free(&data);
275b528cefcSMark Murray     if (ret)
276b528cefcSMark Murray 	return ret;
277b528cefcSMark Murray     ret = context->db->store(context->context, context->db, 0, &ent);
278b528cefcSMark Murray     hdb_free_entry (context->context, &ent);
279b528cefcSMark Murray     return ret;
280b528cefcSMark Murray }
281b528cefcSMark Murray 
282b528cefcSMark Murray /*
283b528cefcSMark Murray  * Add a `delete' operation to the log.
284b528cefcSMark Murray  */
285b528cefcSMark Murray 
286b528cefcSMark Murray kadm5_ret_t
287b528cefcSMark Murray kadm5_log_delete (kadm5_server_context *context,
288b528cefcSMark Murray 		  krb5_principal princ)
289b528cefcSMark Murray {
290b528cefcSMark Murray     krb5_storage *sp;
291b528cefcSMark Murray     kadm5_ret_t ret;
292b528cefcSMark Murray     off_t off;
293b528cefcSMark Murray     off_t len;
294b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
295b528cefcSMark Murray 
296b528cefcSMark Murray     sp = krb5_storage_emem();
297b528cefcSMark Murray     ret = kadm5_log_preamble (context, sp, kadm_delete);
298b528cefcSMark Murray     if (ret) {
299b528cefcSMark Murray 	krb5_storage_free(sp);
300b528cefcSMark Murray 	return ret;
301b528cefcSMark Murray     }
302b528cefcSMark Murray     krb5_store_int32 (sp, 0);
303*8373020dSJacques Vidrine     off = krb5_storage_seek (sp, 0, SEEK_CUR);
304b528cefcSMark Murray     krb5_store_principal (sp, princ);
305*8373020dSJacques Vidrine     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
306*8373020dSJacques Vidrine     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
307b528cefcSMark Murray     krb5_store_int32 (sp, len);
308*8373020dSJacques Vidrine     krb5_storage_seek(sp, len, SEEK_CUR);
309b528cefcSMark Murray     krb5_store_int32 (sp, len);
310b528cefcSMark Murray     if (ret) {
311b528cefcSMark Murray 	krb5_storage_free (sp);
312b528cefcSMark Murray 	return ret;
313b528cefcSMark Murray     }
314b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
315b528cefcSMark Murray     if (ret) {
316b528cefcSMark Murray 	krb5_storage_free (sp);
317b528cefcSMark Murray 	return ret;
318b528cefcSMark Murray     }
319b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
320b528cefcSMark Murray     krb5_storage_free (sp);
321b528cefcSMark Murray     if (ret)
322b528cefcSMark Murray 	return ret;
323b528cefcSMark Murray     ret = kadm5_log_end (context);
324b528cefcSMark Murray     return ret;
325b528cefcSMark Murray }
326b528cefcSMark Murray 
327b528cefcSMark Murray /*
328b528cefcSMark Murray  * Read a `delete' log operation from `sp' and apply it.
329b528cefcSMark Murray  */
330b528cefcSMark Murray 
331b528cefcSMark Murray kadm5_ret_t
332b528cefcSMark Murray kadm5_log_replay_delete (kadm5_server_context *context,
333b528cefcSMark Murray 			 u_int32_t ver,
334b528cefcSMark Murray 			 u_int32_t len,
335b528cefcSMark Murray 			 krb5_storage *sp)
336b528cefcSMark Murray {
337b528cefcSMark Murray     krb5_error_code ret;
338b528cefcSMark Murray     hdb_entry ent;
339b528cefcSMark Murray 
340b528cefcSMark Murray     krb5_ret_principal (sp, &ent.principal);
341b528cefcSMark Murray 
342b528cefcSMark Murray     ret = context->db->remove(context->context, context->db, &ent);
343b528cefcSMark Murray     krb5_free_principal (context->context, ent.principal);
344b528cefcSMark Murray     return ret;
345b528cefcSMark Murray }
346b528cefcSMark Murray 
347b528cefcSMark Murray /*
348b528cefcSMark Murray  * Add a `rename' operation to the log.
349b528cefcSMark Murray  */
350b528cefcSMark Murray 
351b528cefcSMark Murray kadm5_ret_t
352b528cefcSMark Murray kadm5_log_rename (kadm5_server_context *context,
353b528cefcSMark Murray 		  krb5_principal source,
354b528cefcSMark Murray 		  hdb_entry *ent)
355b528cefcSMark Murray {
356b528cefcSMark Murray     krb5_storage *sp;
357b528cefcSMark Murray     kadm5_ret_t ret;
358b528cefcSMark Murray     off_t off;
359b528cefcSMark Murray     off_t len;
360b528cefcSMark Murray     krb5_data value;
361b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
362b528cefcSMark Murray 
363b528cefcSMark Murray     sp = krb5_storage_emem();
364b528cefcSMark Murray     ret = hdb_entry2value (context->context, ent, &value);
365b528cefcSMark Murray     if (ret) {
366b528cefcSMark Murray 	krb5_storage_free(sp);
367b528cefcSMark Murray 	return ret;
368b528cefcSMark Murray     }
369b528cefcSMark Murray     ret = kadm5_log_preamble (context, sp, kadm_rename);
370b528cefcSMark Murray     if (ret) {
371b528cefcSMark Murray 	krb5_storage_free(sp);
372b528cefcSMark Murray 	krb5_data_free (&value);
373b528cefcSMark Murray 	return ret;
374b528cefcSMark Murray     }
375b528cefcSMark Murray     krb5_store_int32 (sp, 0);
376*8373020dSJacques Vidrine     off = krb5_storage_seek (sp, 0, SEEK_CUR);
377b528cefcSMark Murray     krb5_store_principal (sp, source);
378*8373020dSJacques Vidrine     krb5_storage_write(sp, value.data, value.length);
379b528cefcSMark Murray     krb5_data_free (&value);
380*8373020dSJacques Vidrine     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
381b528cefcSMark Murray 
382*8373020dSJacques Vidrine     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
383b528cefcSMark Murray     krb5_store_int32 (sp, len);
384*8373020dSJacques Vidrine     krb5_storage_seek(sp, len, SEEK_CUR);
385b528cefcSMark Murray     krb5_store_int32 (sp, len);
386b528cefcSMark Murray     if (ret) {
387b528cefcSMark Murray 	krb5_storage_free (sp);
388b528cefcSMark Murray 	return ret;
389b528cefcSMark Murray     }
390b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
391b528cefcSMark Murray     if (ret) {
392b528cefcSMark Murray 	krb5_storage_free (sp);
393b528cefcSMark Murray 	return ret;
394b528cefcSMark Murray     }
395b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
396b528cefcSMark Murray     krb5_storage_free (sp);
397b528cefcSMark Murray     if (ret)
398b528cefcSMark Murray 	return ret;
399b528cefcSMark Murray     ret = kadm5_log_end (context);
400b528cefcSMark Murray     return ret;
401b528cefcSMark Murray }
402b528cefcSMark Murray 
403b528cefcSMark Murray /*
404b528cefcSMark Murray  * Read a `rename' log operation from `sp' and apply it.
405b528cefcSMark Murray  */
406b528cefcSMark Murray 
407b528cefcSMark Murray kadm5_ret_t
408b528cefcSMark Murray kadm5_log_replay_rename (kadm5_server_context *context,
409b528cefcSMark Murray 			 u_int32_t ver,
410b528cefcSMark Murray 			 u_int32_t len,
411b528cefcSMark Murray 			 krb5_storage *sp)
412b528cefcSMark Murray {
413b528cefcSMark Murray     krb5_error_code ret;
414b528cefcSMark Murray     krb5_principal source;
415b528cefcSMark Murray     hdb_entry source_ent, target_ent;
416b528cefcSMark Murray     krb5_data value;
417b528cefcSMark Murray     off_t off;
418b528cefcSMark Murray     size_t princ_len, data_len;
419b528cefcSMark Murray 
420*8373020dSJacques Vidrine     off = krb5_storage_seek(sp, 0, SEEK_CUR);
421b528cefcSMark Murray     krb5_ret_principal (sp, &source);
422*8373020dSJacques Vidrine     princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
423b528cefcSMark Murray     data_len = len - princ_len;
424b528cefcSMark Murray     krb5_data_alloc (&value, data_len);
425*8373020dSJacques Vidrine     krb5_storage_read (sp, value.data, data_len);
426b528cefcSMark Murray     ret = hdb_value2entry (context->context, &value, &target_ent);
427b528cefcSMark Murray     krb5_data_free(&value);
428b528cefcSMark Murray     if (ret) {
429b528cefcSMark Murray 	krb5_free_principal (context->context, source);
430b528cefcSMark Murray 	return ret;
431b528cefcSMark Murray     }
432b528cefcSMark Murray     ret = context->db->store (context->context, context->db, 0, &target_ent);
433b528cefcSMark Murray     hdb_free_entry (context->context, &target_ent);
434b528cefcSMark Murray     if (ret) {
435b528cefcSMark Murray 	krb5_free_principal (context->context, source);
436b528cefcSMark Murray 	return ret;
437b528cefcSMark Murray     }
438b528cefcSMark Murray     source_ent.principal = source;
439b528cefcSMark Murray     ret = context->db->remove (context->context, context->db, &source_ent);
440b528cefcSMark Murray     krb5_free_principal (context->context, source);
441b528cefcSMark Murray     return ret;
442b528cefcSMark Murray }
443b528cefcSMark Murray 
444b528cefcSMark Murray 
445b528cefcSMark Murray /*
446b528cefcSMark Murray  * Add a `modify' operation to the log.
447b528cefcSMark Murray  */
448b528cefcSMark Murray 
449b528cefcSMark Murray kadm5_ret_t
450b528cefcSMark Murray kadm5_log_modify (kadm5_server_context *context,
451b528cefcSMark Murray 		  hdb_entry *ent,
452b528cefcSMark Murray 		  u_int32_t mask)
453b528cefcSMark Murray {
454b528cefcSMark Murray     krb5_storage *sp;
455b528cefcSMark Murray     kadm5_ret_t ret;
456b528cefcSMark Murray     krb5_data value;
457b528cefcSMark Murray     u_int32_t len;
458b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
459b528cefcSMark Murray 
460b528cefcSMark Murray     sp = krb5_storage_emem();
461b528cefcSMark Murray     ret = hdb_entry2value (context->context, ent, &value);
462b528cefcSMark Murray     if (ret) {
463b528cefcSMark Murray 	krb5_storage_free(sp);
464b528cefcSMark Murray 	return ret;
465b528cefcSMark Murray     }
466b528cefcSMark Murray     ret = kadm5_log_preamble (context, sp, kadm_modify);
467b528cefcSMark Murray     if (ret) {
468b528cefcSMark Murray 	krb5_data_free (&value);
469b528cefcSMark Murray 	krb5_storage_free(sp);
470b528cefcSMark Murray 	return ret;
471b528cefcSMark Murray     }
472b528cefcSMark Murray     len = value.length + 4;
473b528cefcSMark Murray     krb5_store_int32 (sp, len);
474b528cefcSMark Murray     krb5_store_int32 (sp, mask);
475*8373020dSJacques Vidrine     krb5_storage_write (sp, value.data, value.length);
476b528cefcSMark Murray     krb5_data_free (&value);
477b528cefcSMark Murray     krb5_store_int32 (sp, len);
478b528cefcSMark Murray     if (ret) {
479b528cefcSMark Murray 	krb5_storage_free (sp);
480b528cefcSMark Murray 	return ret;
481b528cefcSMark Murray     }
482b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
483b528cefcSMark Murray     if (ret) {
484b528cefcSMark Murray 	krb5_storage_free (sp);
485b528cefcSMark Murray 	return ret;
486b528cefcSMark Murray     }
487b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
488b528cefcSMark Murray     krb5_storage_free (sp);
489b528cefcSMark Murray     if (ret)
490b528cefcSMark Murray 	return ret;
491b528cefcSMark Murray     ret = kadm5_log_end (context);
492b528cefcSMark Murray     return ret;
493b528cefcSMark Murray }
494b528cefcSMark Murray 
495b528cefcSMark Murray /*
496b528cefcSMark Murray  * Read a `modify' log operation from `sp' and apply it.
497b528cefcSMark Murray  */
498b528cefcSMark Murray 
499b528cefcSMark Murray kadm5_ret_t
500b528cefcSMark Murray kadm5_log_replay_modify (kadm5_server_context *context,
501b528cefcSMark Murray 			 u_int32_t ver,
502b528cefcSMark Murray 			 u_int32_t len,
503b528cefcSMark Murray 			 krb5_storage *sp)
504b528cefcSMark Murray {
505b528cefcSMark Murray     krb5_error_code ret;
506b528cefcSMark Murray     int32_t mask;
507b528cefcSMark Murray     krb5_data value;
508b528cefcSMark Murray     hdb_entry ent, log_ent;
509b528cefcSMark Murray 
510b528cefcSMark Murray     krb5_ret_int32 (sp, &mask);
511b528cefcSMark Murray     len -= 4;
512b528cefcSMark Murray     krb5_data_alloc (&value, len);
513*8373020dSJacques Vidrine     krb5_storage_read (sp, value.data, len);
514b528cefcSMark Murray     ret = hdb_value2entry (context->context, &value, &log_ent);
515b528cefcSMark Murray     krb5_data_free(&value);
516b528cefcSMark Murray     if (ret)
517b528cefcSMark Murray 	return ret;
518b528cefcSMark Murray     ent.principal = log_ent.principal;
519b528cefcSMark Murray     log_ent.principal = NULL;
520b528cefcSMark Murray     ret = context->db->fetch(context->context, context->db,
521b528cefcSMark Murray 			     HDB_F_DECRYPT, &ent);
522b528cefcSMark Murray     if (ret)
523b528cefcSMark Murray 	return ret;
524b528cefcSMark Murray     if (mask & KADM5_PRINC_EXPIRE_TIME) {
5255e9cd1aeSAssar Westerlund 	if (log_ent.valid_end == NULL) {
5265e9cd1aeSAssar Westerlund 	    ent.valid_end = NULL;
5275e9cd1aeSAssar Westerlund 	} else {
528b528cefcSMark Murray 	    if (ent.valid_end == NULL)
529b528cefcSMark Murray 		ent.valid_end = malloc(sizeof(*ent.valid_end));
530b528cefcSMark Murray 	    *ent.valid_end = *log_ent.valid_end;
531b528cefcSMark Murray 	}
5325e9cd1aeSAssar Westerlund     }
533b528cefcSMark Murray     if (mask & KADM5_PW_EXPIRATION) {
5345e9cd1aeSAssar Westerlund 	if (log_ent.pw_end == NULL) {
5355e9cd1aeSAssar Westerlund 	    ent.pw_end = NULL;
5365e9cd1aeSAssar Westerlund 	} else {
537b528cefcSMark Murray 	    if (ent.pw_end == NULL)
538b528cefcSMark Murray 		ent.pw_end = malloc(sizeof(*ent.pw_end));
539b528cefcSMark Murray 	    *ent.pw_end = *log_ent.pw_end;
540b528cefcSMark Murray 	}
5415e9cd1aeSAssar Westerlund     }
542b528cefcSMark Murray     if (mask & KADM5_LAST_PWD_CHANGE) {
543b528cefcSMark Murray 	abort ();		/* XXX */
544b528cefcSMark Murray     }
545b528cefcSMark Murray     if (mask & KADM5_ATTRIBUTES) {
546b528cefcSMark Murray 	ent.flags = log_ent.flags;
547b528cefcSMark Murray     }
548b528cefcSMark Murray     if (mask & KADM5_MAX_LIFE) {
5495e9cd1aeSAssar Westerlund 	if (log_ent.max_life == NULL) {
5505e9cd1aeSAssar Westerlund 	    ent.max_life = NULL;
5515e9cd1aeSAssar Westerlund 	} else {
552b528cefcSMark Murray 	    if (ent.max_life == NULL)
553b528cefcSMark Murray 		ent.max_life = malloc (sizeof(*ent.max_life));
554b528cefcSMark Murray 	    *ent.max_life = *log_ent.max_life;
555b528cefcSMark Murray 	}
5565e9cd1aeSAssar Westerlund     }
557b528cefcSMark Murray     if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
558b528cefcSMark Murray 	if (ent.modified_by == NULL) {
559b528cefcSMark Murray 	    ent.modified_by = malloc(sizeof(*ent.modified_by));
560b528cefcSMark Murray 	} else
561b528cefcSMark Murray 	    free_Event(ent.modified_by);
562b528cefcSMark Murray 	copy_Event(log_ent.modified_by, ent.modified_by);
563b528cefcSMark Murray     }
564b528cefcSMark Murray     if (mask & KADM5_KVNO) {
565b528cefcSMark Murray 	ent.kvno = log_ent.kvno;
566b528cefcSMark Murray     }
567b528cefcSMark Murray     if (mask & KADM5_MKVNO) {
568b528cefcSMark Murray 	abort ();		/* XXX */
569b528cefcSMark Murray     }
570b528cefcSMark Murray     if (mask & KADM5_AUX_ATTRIBUTES) {
571b528cefcSMark Murray 	abort ();		/* XXX */
572b528cefcSMark Murray     }
573b528cefcSMark Murray     if (mask & KADM5_POLICY) {
574b528cefcSMark Murray 	abort ();		/* XXX */
575b528cefcSMark Murray     }
576b528cefcSMark Murray     if (mask & KADM5_POLICY_CLR) {
577b528cefcSMark Murray 	abort ();		/* XXX */
578b528cefcSMark Murray     }
579b528cefcSMark Murray     if (mask & KADM5_MAX_RLIFE) {
5805e9cd1aeSAssar Westerlund 	if (log_ent.max_renew == NULL) {
5815e9cd1aeSAssar Westerlund 	    ent.max_renew = NULL;
5825e9cd1aeSAssar Westerlund 	} else {
583b528cefcSMark Murray 	    if (ent.max_renew == NULL)
584b528cefcSMark Murray 		ent.max_renew = malloc (sizeof(*ent.max_renew));
585b528cefcSMark Murray 	    *ent.max_renew = *log_ent.max_renew;
586b528cefcSMark Murray 	}
5875e9cd1aeSAssar Westerlund     }
588b528cefcSMark Murray     if (mask & KADM5_LAST_SUCCESS) {
589b528cefcSMark Murray 	abort ();		/* XXX */
590b528cefcSMark Murray     }
591b528cefcSMark Murray     if (mask & KADM5_LAST_FAILED) {
592b528cefcSMark Murray 	abort ();		/* XXX */
593b528cefcSMark Murray     }
594b528cefcSMark Murray     if (mask & KADM5_FAIL_AUTH_COUNT) {
595b528cefcSMark Murray 	abort ();		/* XXX */
596b528cefcSMark Murray     }
597b528cefcSMark Murray     if (mask & KADM5_KEY_DATA) {
598b528cefcSMark Murray 	size_t len;
599b528cefcSMark Murray 	int i;
600b528cefcSMark Murray 
601b528cefcSMark Murray 	for (i = 0; i < ent.keys.len; ++i)
602b528cefcSMark Murray 	    free_Key(&ent.keys.val[i]);
603b528cefcSMark Murray 	free (ent.keys.val);
604b528cefcSMark Murray 
605b528cefcSMark Murray 	len = log_ent.keys.len;
606b528cefcSMark Murray 
607b528cefcSMark Murray 	ent.keys.len = len;
608b528cefcSMark Murray 	ent.keys.val = malloc(len * sizeof(*ent.keys.val));
609b528cefcSMark Murray 	for (i = 0; i < ent.keys.len; ++i)
610b528cefcSMark Murray 	    copy_Key(&log_ent.keys.val[i],
611b528cefcSMark Murray 		     &ent.keys.val[i]);
612b528cefcSMark Murray     }
613b528cefcSMark Murray     ret = context->db->store(context->context, context->db,
614b528cefcSMark Murray 			     HDB_F_REPLACE, &ent);
615b528cefcSMark Murray     hdb_free_entry (context->context, &ent);
616b528cefcSMark Murray     hdb_free_entry (context->context, &log_ent);
617b528cefcSMark Murray     return ret;
618b528cefcSMark Murray }
619b528cefcSMark Murray 
620b528cefcSMark Murray /*
6215e9cd1aeSAssar Westerlund  * Add a `nop' operation to the log.
6225e9cd1aeSAssar Westerlund  */
6235e9cd1aeSAssar Westerlund 
6245e9cd1aeSAssar Westerlund kadm5_ret_t
6255e9cd1aeSAssar Westerlund kadm5_log_nop (kadm5_server_context *context)
6265e9cd1aeSAssar Westerlund {
6275e9cd1aeSAssar Westerlund     krb5_storage *sp;
6285e9cd1aeSAssar Westerlund     kadm5_ret_t ret;
6295e9cd1aeSAssar Westerlund     kadm5_log_context *log_context = &context->log_context;
6305e9cd1aeSAssar Westerlund 
6315e9cd1aeSAssar Westerlund     sp = krb5_storage_emem();
6325e9cd1aeSAssar Westerlund     ret = kadm5_log_preamble (context, sp, kadm_nop);
6335e9cd1aeSAssar Westerlund     if (ret) {
6345e9cd1aeSAssar Westerlund 	krb5_storage_free (sp);
6355e9cd1aeSAssar Westerlund 	return ret;
6365e9cd1aeSAssar Westerlund     }
6375e9cd1aeSAssar Westerlund     krb5_store_int32 (sp, 0);
6385e9cd1aeSAssar Westerlund     krb5_store_int32 (sp, 0);
6395e9cd1aeSAssar Westerlund     ret = kadm5_log_postamble (log_context, sp);
6405e9cd1aeSAssar Westerlund     if (ret) {
6415e9cd1aeSAssar Westerlund 	krb5_storage_free (sp);
6425e9cd1aeSAssar Westerlund 	return ret;
6435e9cd1aeSAssar Westerlund     }
6445e9cd1aeSAssar Westerlund     ret = kadm5_log_flush (log_context, sp);
6455e9cd1aeSAssar Westerlund     krb5_storage_free (sp);
6465e9cd1aeSAssar Westerlund     if (ret)
6475e9cd1aeSAssar Westerlund 	return ret;
6485e9cd1aeSAssar Westerlund     ret = kadm5_log_end (context);
6495e9cd1aeSAssar Westerlund     return ret;
6505e9cd1aeSAssar Westerlund }
6515e9cd1aeSAssar Westerlund 
6525e9cd1aeSAssar Westerlund /*
6535e9cd1aeSAssar Westerlund  * Read a `nop' log operation from `sp' and apply it.
6545e9cd1aeSAssar Westerlund  */
6555e9cd1aeSAssar Westerlund 
6565e9cd1aeSAssar Westerlund kadm5_ret_t
6575e9cd1aeSAssar Westerlund kadm5_log_replay_nop (kadm5_server_context *context,
6585e9cd1aeSAssar Westerlund 		      u_int32_t ver,
6595e9cd1aeSAssar Westerlund 		      u_int32_t len,
6605e9cd1aeSAssar Westerlund 		      krb5_storage *sp)
6615e9cd1aeSAssar Westerlund {
6625e9cd1aeSAssar Westerlund     return 0;
6635e9cd1aeSAssar Westerlund }
6645e9cd1aeSAssar Westerlund 
6655e9cd1aeSAssar Westerlund /*
666b528cefcSMark Murray  * Call `func' for each log record in the log in `context'
667b528cefcSMark Murray  */
668b528cefcSMark Murray 
669b528cefcSMark Murray kadm5_ret_t
670b528cefcSMark Murray kadm5_log_foreach (kadm5_server_context *context,
671b528cefcSMark Murray 		   void (*func)(kadm5_server_context *server_context,
672b528cefcSMark Murray 				u_int32_t ver,
673b528cefcSMark Murray 				time_t timestamp,
674b528cefcSMark Murray 				enum kadm_ops op,
675b528cefcSMark Murray 				u_int32_t len,
676b528cefcSMark Murray 				krb5_storage *sp))
677b528cefcSMark Murray {
678b528cefcSMark Murray     int fd = context->log_context.log_fd;
679b528cefcSMark Murray     krb5_storage *sp;
680b528cefcSMark Murray 
681b528cefcSMark Murray     lseek (fd, 0, SEEK_SET);
682b528cefcSMark Murray     sp = krb5_storage_from_fd (fd);
683b528cefcSMark Murray     for (;;) {
684b528cefcSMark Murray 	int32_t ver, timestamp, op, len;
685b528cefcSMark Murray 
686b528cefcSMark Murray 	if(krb5_ret_int32 (sp, &ver) != 0)
687b528cefcSMark Murray 	    break;
688b528cefcSMark Murray 	krb5_ret_int32 (sp, &timestamp);
689b528cefcSMark Murray 	krb5_ret_int32 (sp, &op);
690b528cefcSMark Murray 	krb5_ret_int32 (sp, &len);
691b528cefcSMark Murray 	(*func)(context, ver, timestamp, op, len, sp);
692*8373020dSJacques Vidrine 	krb5_storage_seek(sp, 8, SEEK_CUR);
693b528cefcSMark Murray     }
694b528cefcSMark Murray     return 0;
695b528cefcSMark Murray }
696b528cefcSMark Murray 
697b528cefcSMark Murray /*
698b528cefcSMark Murray  * Go to end of log.
699b528cefcSMark Murray  */
700b528cefcSMark Murray 
701b528cefcSMark Murray krb5_storage *
702b528cefcSMark Murray kadm5_log_goto_end (int fd)
703b528cefcSMark Murray {
704b528cefcSMark Murray     krb5_storage *sp;
705b528cefcSMark Murray 
706b528cefcSMark Murray     sp = krb5_storage_from_fd (fd);
707*8373020dSJacques Vidrine     krb5_storage_seek(sp, 0, SEEK_END);
708b528cefcSMark Murray     return sp;
709b528cefcSMark Murray }
710b528cefcSMark Murray 
711b528cefcSMark Murray /*
712b528cefcSMark Murray  * Return previous log entry.
713b528cefcSMark Murray  */
714b528cefcSMark Murray 
715b528cefcSMark Murray kadm5_ret_t
716b528cefcSMark Murray kadm5_log_previous (krb5_storage *sp,
717b528cefcSMark Murray 		    u_int32_t *ver,
718b528cefcSMark Murray 		    time_t *timestamp,
719b528cefcSMark Murray 		    enum kadm_ops *op,
720b528cefcSMark Murray 		    u_int32_t *len)
721b528cefcSMark Murray {
722b528cefcSMark Murray     off_t off;
723b528cefcSMark Murray     int32_t tmp;
724b528cefcSMark Murray 
725*8373020dSJacques Vidrine     krb5_storage_seek(sp, -8, SEEK_CUR);
726b528cefcSMark Murray     krb5_ret_int32 (sp, &tmp);
727b528cefcSMark Murray     *len = tmp;
728b528cefcSMark Murray     krb5_ret_int32 (sp, &tmp);
729b528cefcSMark Murray     *ver = tmp;
730b528cefcSMark Murray     off = 24 + *len;
731*8373020dSJacques Vidrine     krb5_storage_seek(sp, -off, SEEK_CUR);
732b528cefcSMark Murray     krb5_ret_int32 (sp, &tmp);
733b528cefcSMark Murray     assert(tmp == *ver);
734b528cefcSMark Murray     krb5_ret_int32 (sp, &tmp);
735b528cefcSMark Murray     *timestamp = tmp;
736b528cefcSMark Murray     krb5_ret_int32 (sp, &tmp);
737b528cefcSMark Murray     *op = tmp;
738b528cefcSMark Murray     krb5_ret_int32 (sp, &tmp);
739b528cefcSMark Murray     assert(tmp == *len);
740b528cefcSMark Murray     return 0;
741b528cefcSMark Murray }
742b528cefcSMark Murray 
743b528cefcSMark Murray /*
744b528cefcSMark Murray  * Replay a record from the log
745b528cefcSMark Murray  */
746b528cefcSMark Murray 
747b528cefcSMark Murray kadm5_ret_t
748b528cefcSMark Murray kadm5_log_replay (kadm5_server_context *context,
749b528cefcSMark Murray 		  enum kadm_ops op,
750b528cefcSMark Murray 		  u_int32_t ver,
751b528cefcSMark Murray 		  u_int32_t len,
752b528cefcSMark Murray 		  krb5_storage *sp)
753b528cefcSMark Murray {
754b528cefcSMark Murray     switch (op) {
755b528cefcSMark Murray     case kadm_create :
756b528cefcSMark Murray 	return kadm5_log_replay_create (context, ver, len, sp);
757b528cefcSMark Murray     case kadm_delete :
758b528cefcSMark Murray 	return kadm5_log_replay_delete (context, ver, len, sp);
759b528cefcSMark Murray     case kadm_rename :
760b528cefcSMark Murray 	return kadm5_log_replay_rename (context, ver, len, sp);
761b528cefcSMark Murray     case kadm_modify :
762b528cefcSMark Murray 	return kadm5_log_replay_modify (context, ver, len, sp);
7635e9cd1aeSAssar Westerlund     case kadm_nop :
7645e9cd1aeSAssar Westerlund 	return kadm5_log_replay_nop (context, ver, len, sp);
765b528cefcSMark Murray     default :
766b528cefcSMark Murray 	return KADM5_FAILURE;
767b528cefcSMark Murray     }
768b528cefcSMark Murray }
7695e9cd1aeSAssar Westerlund 
7705e9cd1aeSAssar Westerlund /*
7715e9cd1aeSAssar Westerlund  * truncate the log - i.e. create an empty file with just (nop vno + 2)
7725e9cd1aeSAssar Westerlund  */
7735e9cd1aeSAssar Westerlund 
7745e9cd1aeSAssar Westerlund kadm5_ret_t
7755e9cd1aeSAssar Westerlund kadm5_log_truncate (kadm5_server_context *server_context)
7765e9cd1aeSAssar Westerlund {
7775e9cd1aeSAssar Westerlund     kadm5_ret_t ret;
7785e9cd1aeSAssar Westerlund     u_int32_t vno;
7795e9cd1aeSAssar Westerlund 
7805e9cd1aeSAssar Westerlund     ret = kadm5_log_init (server_context);
7815e9cd1aeSAssar Westerlund     if (ret)
7825e9cd1aeSAssar Westerlund 	return ret;
7835e9cd1aeSAssar Westerlund 
7845e9cd1aeSAssar Westerlund     ret = kadm5_log_get_version (server_context, &vno);
7855e9cd1aeSAssar Westerlund     if (ret)
7865e9cd1aeSAssar Westerlund 	return ret;
7875e9cd1aeSAssar Westerlund 
7885e9cd1aeSAssar Westerlund     ret = kadm5_log_reinit (server_context);
7895e9cd1aeSAssar Westerlund     if (ret)
7905e9cd1aeSAssar Westerlund 	return ret;
7915e9cd1aeSAssar Westerlund 
7925e9cd1aeSAssar Westerlund     ret = kadm5_log_set_version (server_context, vno + 1);
7935e9cd1aeSAssar Westerlund     if (ret)
7945e9cd1aeSAssar Westerlund 	return ret;
7955e9cd1aeSAssar Westerlund 
7965e9cd1aeSAssar Westerlund     ret = kadm5_log_nop (server_context);
7975e9cd1aeSAssar Westerlund     if (ret)
7985e9cd1aeSAssar Westerlund 	return ret;
7995e9cd1aeSAssar Westerlund 
8005e9cd1aeSAssar Westerlund     ret = kadm5_log_end (server_context);
8015e9cd1aeSAssar Westerlund     if (ret)
8025e9cd1aeSAssar Westerlund 	return ret;
8035e9cd1aeSAssar Westerlund     return 0;
8045e9cd1aeSAssar Westerlund 
8055e9cd1aeSAssar Westerlund }
806