xref: /freebsd/crypto/heimdal/lib/kadm5/log.c (revision c19800e8)
1b528cefcSMark Murray /*
2c19800e8SDoug Rabson  * Copyright (c) 1997 - 2007 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"
35c19800e8SDoug Rabson #include "heim_threads.h"
36b528cefcSMark Murray 
37c19800e8SDoug Rabson RCSID("$Id$");
38b528cefcSMark Murray 
39b528cefcSMark Murray /*
40b528cefcSMark Murray  * A log record consists of:
41b528cefcSMark Murray  *
42b528cefcSMark Murray  * version number		4 bytes
43b528cefcSMark Murray  * time in seconds		4 bytes
44b528cefcSMark Murray  * operation (enum kadm_ops)	4 bytes
45b528cefcSMark Murray  * length of record		4 bytes
46b528cefcSMark Murray  * data...			n bytes
47b528cefcSMark Murray  * length of record		4 bytes
48b528cefcSMark Murray  * version number		4 bytes
49b528cefcSMark Murray  *
50b528cefcSMark Murray  */
51b528cefcSMark Murray 
52b528cefcSMark Murray kadm5_ret_t
kadm5_log_get_version_fd(int fd,uint32_t * ver)535e9cd1aeSAssar Westerlund kadm5_log_get_version_fd (int fd,
54c19800e8SDoug Rabson 			  uint32_t *ver)
55b528cefcSMark Murray {
56b528cefcSMark Murray     int ret;
57b528cefcSMark Murray     krb5_storage *sp;
58b528cefcSMark Murray     int32_t old_version;
59b528cefcSMark Murray 
60b528cefcSMark Murray     ret = lseek (fd, 0, SEEK_END);
61b528cefcSMark Murray     if(ret < 0)
62b528cefcSMark Murray 	return errno;
63b528cefcSMark Murray     if(ret == 0) {
64b528cefcSMark Murray 	*ver = 0;
65b528cefcSMark Murray 	return 0;
66b528cefcSMark Murray     }
67b528cefcSMark Murray     sp = krb5_storage_from_fd (fd);
688373020dSJacques Vidrine     krb5_storage_seek(sp, -4, SEEK_CUR);
69b528cefcSMark Murray     krb5_ret_int32 (sp, &old_version);
70b528cefcSMark Murray     *ver = old_version;
71b528cefcSMark Murray     krb5_storage_free(sp);
72b528cefcSMark Murray     lseek (fd, 0, SEEK_END);
73b528cefcSMark Murray     return 0;
74b528cefcSMark Murray }
75b528cefcSMark Murray 
76b528cefcSMark Murray kadm5_ret_t
kadm5_log_get_version(kadm5_server_context * context,uint32_t * ver)77c19800e8SDoug Rabson kadm5_log_get_version (kadm5_server_context *context, uint32_t *ver)
785e9cd1aeSAssar Westerlund {
795e9cd1aeSAssar Westerlund     return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
805e9cd1aeSAssar Westerlund }
815e9cd1aeSAssar Westerlund 
825e9cd1aeSAssar Westerlund kadm5_ret_t
kadm5_log_set_version(kadm5_server_context * context,uint32_t vno)83c19800e8SDoug Rabson kadm5_log_set_version (kadm5_server_context *context, uint32_t vno)
845e9cd1aeSAssar Westerlund {
855e9cd1aeSAssar Westerlund     kadm5_log_context *log_context = &context->log_context;
865e9cd1aeSAssar Westerlund 
875e9cd1aeSAssar Westerlund     log_context->version = vno;
885e9cd1aeSAssar Westerlund     return 0;
895e9cd1aeSAssar Westerlund }
905e9cd1aeSAssar Westerlund 
915e9cd1aeSAssar Westerlund kadm5_ret_t
kadm5_log_init(kadm5_server_context * context)92b528cefcSMark Murray kadm5_log_init (kadm5_server_context *context)
93b528cefcSMark Murray {
94b528cefcSMark Murray     int fd;
95b528cefcSMark Murray     kadm5_ret_t ret;
96b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
97b528cefcSMark Murray 
98b528cefcSMark Murray     if (log_context->log_fd != -1)
99b528cefcSMark Murray 	return 0;
100b528cefcSMark Murray     fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
101c19800e8SDoug Rabson     if (fd < 0) {
102c19800e8SDoug Rabson 	ret = errno;
103c19800e8SDoug Rabson 	krb5_set_error_message(context->context, ret, "kadm5_log_init: open %s",
104b528cefcSMark Murray 			      log_context->log_file);
105c19800e8SDoug Rabson 	return ret;
106b528cefcSMark Murray     }
107c19800e8SDoug Rabson     if (flock (fd, LOCK_EX) < 0) {
108c19800e8SDoug Rabson 	ret = errno;
109b528cefcSMark Murray 	krb5_set_error_message(context->context, ret, "kadm5_log_init: flock %s",
110b528cefcSMark Murray 			       log_context->log_file);
111b528cefcSMark Murray 	close (fd);
112b528cefcSMark Murray 	return errno;
1135e9cd1aeSAssar Westerlund     }
114b528cefcSMark Murray 
115b528cefcSMark Murray     ret = kadm5_log_get_version_fd (fd, &log_context->version);
116b528cefcSMark Murray     if (ret)
117b528cefcSMark Murray 	return ret;
118b528cefcSMark Murray 
119b528cefcSMark Murray     log_context->log_fd  = fd;
120b528cefcSMark Murray     return 0;
121b528cefcSMark Murray }
1225e9cd1aeSAssar Westerlund 
1235e9cd1aeSAssar Westerlund kadm5_ret_t
kadm5_log_reinit(kadm5_server_context * context)1245e9cd1aeSAssar Westerlund kadm5_log_reinit (kadm5_server_context *context)
1255e9cd1aeSAssar Westerlund {
1265e9cd1aeSAssar Westerlund     int fd;
1275e9cd1aeSAssar Westerlund     kadm5_log_context *log_context = &context->log_context;
128c19800e8SDoug Rabson 
1295e9cd1aeSAssar Westerlund     if (log_context->log_fd != -1) {
1305e9cd1aeSAssar Westerlund 	flock (log_context->log_fd, LOCK_UN);
1315e9cd1aeSAssar Westerlund 	close (log_context->log_fd);
1325e9cd1aeSAssar Westerlund 	log_context->log_fd = -1;
1335e9cd1aeSAssar Westerlund     }
1345e9cd1aeSAssar Westerlund     fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
1355e9cd1aeSAssar Westerlund     if (fd < 0)
1365e9cd1aeSAssar Westerlund 	return errno;
1375e9cd1aeSAssar Westerlund     if (flock (fd, LOCK_EX) < 0) {
1385e9cd1aeSAssar Westerlund 	close (fd);
1395e9cd1aeSAssar Westerlund 	return errno;
1405e9cd1aeSAssar Westerlund     }
1415e9cd1aeSAssar Westerlund 
1425e9cd1aeSAssar Westerlund     log_context->version = 0;
1435e9cd1aeSAssar Westerlund     log_context->log_fd  = fd;
1445e9cd1aeSAssar Westerlund     return 0;
1455e9cd1aeSAssar Westerlund }
1465e9cd1aeSAssar Westerlund 
147b528cefcSMark Murray 
148b528cefcSMark Murray kadm5_ret_t
kadm5_log_end(kadm5_server_context * context)149b528cefcSMark Murray kadm5_log_end (kadm5_server_context *context)
150b528cefcSMark Murray {
151b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
152b528cefcSMark Murray     int fd = log_context->log_fd;
153b528cefcSMark Murray 
154b528cefcSMark Murray     flock (fd, LOCK_UN);
155b528cefcSMark Murray     close(fd);
156b528cefcSMark Murray     log_context->log_fd = -1;
157b528cefcSMark Murray     return 0;
158b528cefcSMark Murray }
159b528cefcSMark Murray 
160b528cefcSMark Murray static kadm5_ret_t
kadm5_log_preamble(kadm5_server_context * context,krb5_storage * sp,enum kadm_ops op)161b528cefcSMark Murray kadm5_log_preamble (kadm5_server_context *context,
162b528cefcSMark Murray 		    krb5_storage *sp,
163b528cefcSMark Murray 		    enum kadm_ops op)
164b528cefcSMark Murray {
165b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
166b528cefcSMark Murray     kadm5_ret_t kadm_ret;
167b528cefcSMark Murray 
168b528cefcSMark Murray     kadm_ret = kadm5_log_init (context);
169b528cefcSMark Murray     if (kadm_ret)
170b528cefcSMark Murray 	return kadm_ret;
171b528cefcSMark Murray 
172b528cefcSMark Murray     krb5_store_int32 (sp, ++log_context->version);
173b528cefcSMark Murray     krb5_store_int32 (sp, time(NULL));
174b528cefcSMark Murray     krb5_store_int32 (sp, op);
175b528cefcSMark Murray     return 0;
176b528cefcSMark Murray }
177b528cefcSMark Murray 
178b528cefcSMark Murray static kadm5_ret_t
kadm5_log_postamble(kadm5_log_context * context,krb5_storage * sp)179b528cefcSMark Murray kadm5_log_postamble (kadm5_log_context *context,
180b528cefcSMark Murray 		     krb5_storage *sp)
181b528cefcSMark Murray {
182b528cefcSMark Murray     krb5_store_int32 (sp, context->version);
183b528cefcSMark Murray     return 0;
184b528cefcSMark Murray }
185b528cefcSMark Murray 
186b528cefcSMark Murray /*
187b528cefcSMark Murray  * flush the log record in `sp'.
188b528cefcSMark Murray  */
189b528cefcSMark Murray 
190b528cefcSMark Murray static kadm5_ret_t
kadm5_log_flush(kadm5_log_context * log_context,krb5_storage * sp)191b528cefcSMark Murray kadm5_log_flush (kadm5_log_context *log_context,
192b528cefcSMark Murray 		 krb5_storage *sp)
193b528cefcSMark Murray {
194b528cefcSMark Murray     krb5_data data;
195b528cefcSMark Murray     size_t len;
196b528cefcSMark Murray     ssize_t ret;
197b528cefcSMark Murray 
198b528cefcSMark Murray     krb5_storage_to_data(sp, &data);
199b528cefcSMark Murray     len = data.length;
200b528cefcSMark Murray     ret = write (log_context->log_fd, data.data, len);
201b528cefcSMark Murray     if (ret < 0 || (size_t)ret != len) {
202b528cefcSMark Murray 	krb5_data_free(&data);
203b528cefcSMark Murray 	return errno;
204b528cefcSMark Murray     }
205b528cefcSMark Murray     if (fsync (log_context->log_fd) < 0) {
206b528cefcSMark Murray 	krb5_data_free(&data);
207b528cefcSMark Murray 	return errno;
208b528cefcSMark Murray     }
209b528cefcSMark Murray 
210b528cefcSMark Murray     /*
211b528cefcSMark Murray      * Try to send a signal to any running `ipropd-master'
212b528cefcSMark Murray      */
213b528cefcSMark Murray #ifndef NO_UNIX_SOCKETS
214b528cefcSMark Murray     sendto (log_context->socket_fd,
215b528cefcSMark Murray 	    (void *)&log_context->version,
216b528cefcSMark Murray 	    sizeof(log_context->version),
217b528cefcSMark Murray 	    0,
218b528cefcSMark Murray 	    (struct sockaddr *)&log_context->socket_name,
219b528cefcSMark Murray 	    sizeof(log_context->socket_name));
220b528cefcSMark Murray #else
221b528cefcSMark Murray     sendto (log_context->socket_fd,
222b528cefcSMark Murray 	    (void *)&log_context->version,
223b528cefcSMark Murray 	    sizeof(log_context->version),
224b528cefcSMark Murray 	    0,
225b528cefcSMark Murray 	    log_context->socket_info->ai_addr,
226b528cefcSMark Murray 	    log_context->socket_info->ai_addrlen);
227b528cefcSMark Murray #endif
228b528cefcSMark Murray 
229b528cefcSMark Murray     krb5_data_free(&data);
230b528cefcSMark Murray     return 0;
231b528cefcSMark Murray }
232b528cefcSMark Murray 
233b528cefcSMark Murray /*
234b528cefcSMark Murray  * Add a `create' operation to the log.
235b528cefcSMark Murray  */
236b528cefcSMark Murray 
237b528cefcSMark Murray kadm5_ret_t
kadm5_log_create(kadm5_server_context * context,hdb_entry * ent)238b528cefcSMark Murray kadm5_log_create (kadm5_server_context *context,
239b528cefcSMark Murray 		  hdb_entry *ent)
240b528cefcSMark Murray {
241b528cefcSMark Murray     krb5_storage *sp;
242b528cefcSMark Murray     kadm5_ret_t ret;
243b528cefcSMark Murray     krb5_data value;
244b528cefcSMark Murray     kadm5_log_context *log_context = &context->log_context;
245b528cefcSMark Murray 
246b528cefcSMark Murray     sp = krb5_storage_emem();
2478373020dSJacques Vidrine     ret = hdb_entry2value (context->context, ent, &value);
248b528cefcSMark Murray     if (ret) {
249b528cefcSMark Murray 	krb5_storage_free(sp);
250b528cefcSMark Murray 	return ret;
251b528cefcSMark Murray     }
252b528cefcSMark Murray     ret = kadm5_log_preamble (context, sp, kadm_create);
253b528cefcSMark Murray     if (ret) {
254b528cefcSMark Murray 	krb5_data_free (&value);
255b528cefcSMark Murray 	krb5_storage_free(sp);
256b528cefcSMark Murray 	return ret;
257b528cefcSMark Murray     }
258b528cefcSMark Murray     krb5_store_int32 (sp, value.length);
259b528cefcSMark Murray     krb5_storage_write(sp, value.data, value.length);
260b528cefcSMark Murray     krb5_store_int32 (sp, value.length);
261b528cefcSMark Murray     krb5_data_free (&value);
262b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
263b528cefcSMark Murray     if (ret) {
264b528cefcSMark Murray 	krb5_storage_free (sp);
265b528cefcSMark Murray 	return ret;
266b528cefcSMark Murray     }
267b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
268c19800e8SDoug Rabson     krb5_storage_free (sp);
269b528cefcSMark Murray     if (ret)
270c19800e8SDoug Rabson 	return ret;
271c19800e8SDoug Rabson     ret = kadm5_log_end (context);
272b528cefcSMark Murray     return ret;
273b528cefcSMark Murray }
274b528cefcSMark Murray 
275b528cefcSMark Murray /*
276c19800e8SDoug Rabson  * Read the data of a create log record from `sp' and change the
277c19800e8SDoug Rabson  * database.
278c19800e8SDoug Rabson  */
279b528cefcSMark Murray 
280bbd80c28SJacques Vidrine static kadm5_ret_t
kadm5_log_replay_create(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)281c19800e8SDoug Rabson kadm5_log_replay_create (kadm5_server_context *context,
282c19800e8SDoug Rabson 			 uint32_t ver,
283bbd80c28SJacques Vidrine 			 uint32_t len,
284c19800e8SDoug Rabson 			 krb5_storage *sp)
2858373020dSJacques Vidrine {
286c19800e8SDoug Rabson     krb5_error_code ret;
287b528cefcSMark Murray     krb5_data data;
288c19800e8SDoug Rabson     hdb_entry_ex ent;
289c19800e8SDoug Rabson 
290c19800e8SDoug Rabson     memset(&ent, 0, sizeof(ent));
291b528cefcSMark Murray 
292c19800e8SDoug Rabson     ret = krb5_data_alloc (&data, len);
293c19800e8SDoug Rabson     if (ret) {
294b528cefcSMark Murray 	krb5_set_error_message(context->context, ret, "out of memory");
295b528cefcSMark Murray 	return ret;
296b528cefcSMark Murray     }
297b528cefcSMark Murray     krb5_storage_read (sp, data.data, len);
298b528cefcSMark Murray     ret = hdb_value2entry (context->context, &data, &ent.entry);
299b528cefcSMark Murray     krb5_data_free(&data);
300b528cefcSMark Murray     if (ret) {
301b528cefcSMark Murray 	krb5_set_error_message(context->context, ret,
302b528cefcSMark Murray 			       "Unmarshaling hdb entry failed");
303b528cefcSMark Murray 	return ret;
304b528cefcSMark Murray     }
305b528cefcSMark Murray     ret = context->db->hdb_store(context->context, context->db, 0, &ent);
306b528cefcSMark Murray     hdb_free_entry (context->context, &ent);
307b528cefcSMark Murray     return ret;
308b528cefcSMark Murray }
309b528cefcSMark Murray 
310b528cefcSMark Murray /*
311b528cefcSMark Murray  * Add a `delete' operation to the log.
312b528cefcSMark Murray  */
313c19800e8SDoug Rabson 
314c19800e8SDoug Rabson kadm5_ret_t
kadm5_log_delete(kadm5_server_context * context,krb5_principal princ)315b528cefcSMark Murray kadm5_log_delete (kadm5_server_context *context,
316c19800e8SDoug Rabson 		  krb5_principal princ)
317c19800e8SDoug Rabson {
318c19800e8SDoug Rabson     krb5_storage *sp;
319c19800e8SDoug Rabson     kadm5_ret_t ret;
320c19800e8SDoug Rabson     off_t off;
3218373020dSJacques Vidrine     off_t len;
322c19800e8SDoug Rabson     kadm5_log_context *log_context = &context->log_context;
323c19800e8SDoug Rabson 
324c19800e8SDoug Rabson     sp = krb5_storage_emem();
3258373020dSJacques Vidrine     if (sp == NULL)
3268373020dSJacques Vidrine 	return ENOMEM;
327c19800e8SDoug Rabson     ret = kadm5_log_preamble (context, sp, kadm_delete);
328b528cefcSMark Murray     if (ret)
329c19800e8SDoug Rabson 	goto out;
330c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, 0);
331c19800e8SDoug Rabson     if (ret)
332c19800e8SDoug Rabson 	goto out;
333c19800e8SDoug Rabson     off = krb5_storage_seek (sp, 0, SEEK_CUR);
334c19800e8SDoug Rabson     ret = krb5_store_principal (sp, princ);
335c19800e8SDoug Rabson     if (ret)
336c19800e8SDoug Rabson 	goto out;
337c19800e8SDoug Rabson     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
338c19800e8SDoug Rabson     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
339c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, len);
340b528cefcSMark Murray     if (ret)
341c19800e8SDoug Rabson 	goto out;
342c19800e8SDoug Rabson     krb5_storage_seek(sp, len, SEEK_CUR);
343b528cefcSMark Murray     ret = krb5_store_int32 (sp, len);
344b528cefcSMark Murray     if (ret)
345b528cefcSMark Murray 	goto out;
346b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
347b528cefcSMark Murray     if (ret)
348b528cefcSMark Murray 	goto out;
349b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
350c19800e8SDoug Rabson     if (ret)
351b528cefcSMark Murray 	goto out;
352c19800e8SDoug Rabson     ret = kadm5_log_end (context);
353c19800e8SDoug Rabson out:
354b528cefcSMark Murray     krb5_storage_free (sp);
355b528cefcSMark Murray     return ret;
356b528cefcSMark Murray }
357c19800e8SDoug Rabson 
358b528cefcSMark Murray /*
359c19800e8SDoug Rabson  * Read a `delete' log operation from `sp' and apply it.
360c19800e8SDoug Rabson  */
361c19800e8SDoug Rabson 
362c19800e8SDoug Rabson static kadm5_ret_t
kadm5_log_replay_delete(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)363c19800e8SDoug Rabson kadm5_log_replay_delete (kadm5_server_context *context,
364c19800e8SDoug Rabson 			 uint32_t ver,
365b528cefcSMark Murray 			 uint32_t len,
366c19800e8SDoug Rabson 			 krb5_storage *sp)
367c19800e8SDoug Rabson {
368b528cefcSMark Murray     krb5_error_code ret;
369b528cefcSMark Murray     krb5_principal principal;
370b528cefcSMark Murray 
371b528cefcSMark Murray     ret = krb5_ret_principal (sp, &principal);
372b528cefcSMark Murray     if (ret) {
373b528cefcSMark Murray 	krb5_set_error_message(context->context,  ret, "Failed to read deleted "
374b528cefcSMark Murray 			       "principal from log version: %ld",  (long)ver);
375b528cefcSMark Murray 	return ret;
376b528cefcSMark Murray     }
377b528cefcSMark Murray 
378b528cefcSMark Murray     ret = context->db->hdb_remove(context->context, context->db, principal);
379b528cefcSMark Murray     krb5_free_principal (context->context, principal);
380b528cefcSMark Murray     return ret;
381b528cefcSMark Murray }
382b528cefcSMark Murray 
383b528cefcSMark Murray /*
384b528cefcSMark Murray  * Add a `rename' operation to the log.
385b528cefcSMark Murray  */
386b528cefcSMark Murray 
387c19800e8SDoug Rabson kadm5_ret_t
kadm5_log_rename(kadm5_server_context * context,krb5_principal source,hdb_entry * ent)388c19800e8SDoug Rabson kadm5_log_rename (kadm5_server_context *context,
389b528cefcSMark Murray 		  krb5_principal source,
390b528cefcSMark Murray 		  hdb_entry *ent)
391c19800e8SDoug Rabson {
392c19800e8SDoug Rabson     krb5_storage *sp;
393c19800e8SDoug Rabson     kadm5_ret_t ret;
394b528cefcSMark Murray     off_t off;
395c19800e8SDoug Rabson     off_t len;
396c19800e8SDoug Rabson     krb5_data value;
397c19800e8SDoug Rabson     kadm5_log_context *log_context = &context->log_context;
398c19800e8SDoug Rabson 
399c19800e8SDoug Rabson     krb5_data_zero(&value);
400c19800e8SDoug Rabson 
4018373020dSJacques Vidrine     sp = krb5_storage_emem();
402c19800e8SDoug Rabson     ret = hdb_entry2value (context->context, ent, &value);
403c19800e8SDoug Rabson     if (ret)
404c19800e8SDoug Rabson 	goto failed;
405c19800e8SDoug Rabson 
4068373020dSJacques Vidrine     ret = kadm5_log_preamble (context, sp, kadm_rename);
4078373020dSJacques Vidrine     if (ret)
408b528cefcSMark Murray 	goto failed;
4098373020dSJacques Vidrine 
410c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, 0);
411b528cefcSMark Murray     if (ret)
412c19800e8SDoug Rabson 	goto failed;
413c19800e8SDoug Rabson     off = krb5_storage_seek (sp, 0, SEEK_CUR);
414c19800e8SDoug Rabson     ret = krb5_store_principal (sp, source);
415c19800e8SDoug Rabson     if (ret)
416c19800e8SDoug Rabson 	goto failed;
417c19800e8SDoug Rabson 
418c19800e8SDoug Rabson     krb5_storage_write(sp, value.data, value.length);
419c19800e8SDoug Rabson     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
420c19800e8SDoug Rabson 
421c19800e8SDoug Rabson     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
422c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, len);
423c19800e8SDoug Rabson     if (ret)
424c19800e8SDoug Rabson 	goto failed;
425c19800e8SDoug Rabson 
426c19800e8SDoug Rabson     krb5_storage_seek(sp, len, SEEK_CUR);
427c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, len);
428c19800e8SDoug Rabson     if (ret)
429c19800e8SDoug Rabson 	goto failed;
430c19800e8SDoug Rabson 
431c19800e8SDoug Rabson     ret = kadm5_log_postamble (log_context, sp);
432c19800e8SDoug Rabson     if (ret)
433c19800e8SDoug Rabson 	goto failed;
434b528cefcSMark Murray 
435b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
436b528cefcSMark Murray     if (ret)
437b528cefcSMark Murray 	goto failed;
438b528cefcSMark Murray     krb5_storage_free (sp);
439b528cefcSMark Murray     krb5_data_free (&value);
440b528cefcSMark Murray 
441c19800e8SDoug Rabson     return kadm5_log_end (context);
442b528cefcSMark Murray 
443c19800e8SDoug Rabson failed:
444c19800e8SDoug Rabson     krb5_data_free(&value);
445b528cefcSMark Murray     krb5_storage_free(sp);
446b528cefcSMark Murray     return ret;
447b528cefcSMark Murray }
448b528cefcSMark Murray 
449c19800e8SDoug Rabson /*
450b528cefcSMark Murray  * Read a `rename' log operation from `sp' and apply it.
451b528cefcSMark Murray  */
452b528cefcSMark Murray 
453b528cefcSMark Murray static kadm5_ret_t
kadm5_log_replay_rename(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)454c19800e8SDoug Rabson kadm5_log_replay_rename (kadm5_server_context *context,
455c19800e8SDoug Rabson 			 uint32_t ver,
4568373020dSJacques Vidrine 			 uint32_t len,
457c19800e8SDoug Rabson 			 krb5_storage *sp)
458c19800e8SDoug Rabson {
459c19800e8SDoug Rabson     krb5_error_code ret;
460c19800e8SDoug Rabson     krb5_principal source;
461c19800e8SDoug Rabson     hdb_entry_ex target_ent;
462c19800e8SDoug Rabson     krb5_data value;
4638373020dSJacques Vidrine     off_t off;
464b528cefcSMark Murray     size_t princ_len, data_len;
465bbd80c28SJacques Vidrine 
466bbd80c28SJacques Vidrine     memset(&target_ent, 0, sizeof(target_ent));
467bbd80c28SJacques Vidrine 
468bbd80c28SJacques Vidrine     off = krb5_storage_seek(sp, 0, SEEK_CUR);
469bbd80c28SJacques Vidrine     ret = krb5_ret_principal (sp, &source);
4708373020dSJacques Vidrine     if (ret) {
471c19800e8SDoug Rabson 	krb5_set_error_message(context->context, ret, "Failed to read renamed "
472b528cefcSMark Murray 			       "principal in log, version: %ld", (long)ver);
473b528cefcSMark Murray 	return ret;
474b528cefcSMark Murray     }
475b528cefcSMark Murray     princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
476b528cefcSMark Murray     data_len = len - princ_len;
477c19800e8SDoug Rabson     ret = krb5_data_alloc (&value, data_len);
478c19800e8SDoug Rabson     if (ret) {
479b528cefcSMark Murray 	krb5_free_principal (context->context, source);
480b528cefcSMark Murray 	return ret;
481b528cefcSMark Murray     }
482b528cefcSMark Murray     krb5_storage_read (sp, value.data, data_len);
483b528cefcSMark Murray     ret = hdb_value2entry (context->context, &value, &target_ent.entry);
484c19800e8SDoug Rabson     krb5_data_free(&value);
485b528cefcSMark Murray     if (ret) {
486b528cefcSMark Murray 	krb5_free_principal (context->context, source);
487b528cefcSMark Murray 	return ret;
488b528cefcSMark Murray     }
489b528cefcSMark Murray     ret = context->db->hdb_store (context->context, context->db,
490b528cefcSMark Murray 				  0, &target_ent);
491b528cefcSMark Murray     hdb_free_entry (context->context, &target_ent);
492b528cefcSMark Murray     if (ret) {
493b528cefcSMark Murray 	krb5_free_principal (context->context, source);
494b528cefcSMark Murray 	return ret;
495b528cefcSMark Murray     }
496b528cefcSMark Murray     ret = context->db->hdb_remove (context->context, context->db, source);
497c19800e8SDoug Rabson     krb5_free_principal (context->context, source);
498b528cefcSMark Murray     return ret;
499b528cefcSMark Murray }
500b528cefcSMark Murray 
501b528cefcSMark Murray 
502c19800e8SDoug Rabson /*
503b528cefcSMark Murray  * Add a `modify' operation to the log.
504b528cefcSMark Murray  */
505c19800e8SDoug Rabson 
506c19800e8SDoug Rabson kadm5_ret_t
kadm5_log_modify(kadm5_server_context * context,hdb_entry * ent,uint32_t mask)507b528cefcSMark Murray kadm5_log_modify (kadm5_server_context *context,
508b528cefcSMark Murray 		  hdb_entry *ent,
509b528cefcSMark Murray 		  uint32_t mask)
510c19800e8SDoug Rabson {
511c19800e8SDoug Rabson     krb5_storage *sp;
512c19800e8SDoug Rabson     kadm5_ret_t ret;
513c19800e8SDoug Rabson     krb5_data value;
514c19800e8SDoug Rabson     uint32_t len;
515c19800e8SDoug Rabson     kadm5_log_context *log_context = &context->log_context;
516c19800e8SDoug Rabson 
517c19800e8SDoug Rabson     krb5_data_zero(&value);
518c19800e8SDoug Rabson 
519c19800e8SDoug Rabson     sp = krb5_storage_emem();
520c19800e8SDoug Rabson     ret = hdb_entry2value (context->context, ent, &value);
521c19800e8SDoug Rabson     if (ret)
522c19800e8SDoug Rabson 	goto failed;
523c19800e8SDoug Rabson 
524c19800e8SDoug Rabson     ret = kadm5_log_preamble (context, sp, kadm_modify);
525c19800e8SDoug Rabson     if (ret)
526c19800e8SDoug Rabson 	goto failed;
527c19800e8SDoug Rabson 
528c19800e8SDoug Rabson     len = value.length + 4;
529c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, len);
530c19800e8SDoug Rabson     if (ret)
531c19800e8SDoug Rabson 	goto failed;
532c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, mask);
533c19800e8SDoug Rabson     if (ret)
534c19800e8SDoug Rabson 	goto failed;
535c19800e8SDoug Rabson     krb5_storage_write (sp, value.data, value.length);
536c19800e8SDoug Rabson 
537c19800e8SDoug Rabson     ret = krb5_store_int32 (sp, len);
538c19800e8SDoug Rabson     if (ret)
539c19800e8SDoug Rabson 	goto failed;
540b528cefcSMark Murray     ret = kadm5_log_postamble (log_context, sp);
541b528cefcSMark Murray     if (ret)
542b528cefcSMark Murray 	goto failed;
543b528cefcSMark Murray     ret = kadm5_log_flush (log_context, sp);
544b528cefcSMark Murray     if (ret)
545b528cefcSMark Murray 	goto failed;
546b528cefcSMark Murray     krb5_data_free(&value);
547c19800e8SDoug Rabson     krb5_storage_free (sp);
548b528cefcSMark Murray     return kadm5_log_end (context);
549c19800e8SDoug Rabson failed:
550c19800e8SDoug Rabson     krb5_data_free(&value);
551b528cefcSMark Murray     krb5_storage_free(sp);
552b528cefcSMark Murray     return ret;
553b528cefcSMark Murray }
554b528cefcSMark Murray 
555b528cefcSMark Murray /*
556c19800e8SDoug Rabson  * Read a `modify' log operation from `sp' and apply it.
557c19800e8SDoug Rabson  */
558c19800e8SDoug Rabson 
559b528cefcSMark Murray static kadm5_ret_t
kadm5_log_replay_modify(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)560b528cefcSMark Murray kadm5_log_replay_modify (kadm5_server_context *context,
561b528cefcSMark Murray 			 uint32_t ver,
562bbd80c28SJacques Vidrine 			 uint32_t len,
563c19800e8SDoug Rabson 			 krb5_storage *sp)
564c19800e8SDoug Rabson {
565bbd80c28SJacques Vidrine     krb5_error_code ret;
566c19800e8SDoug Rabson     int32_t mask;
5678373020dSJacques Vidrine     krb5_data value;
568c19800e8SDoug Rabson     hdb_entry_ex ent, log_ent;
569b528cefcSMark Murray 
570b528cefcSMark Murray     memset(&log_ent, 0, sizeof(log_ent));
571b528cefcSMark Murray 
572c19800e8SDoug Rabson     krb5_ret_int32 (sp, &mask);
573c19800e8SDoug Rabson     len -= 4;
574c19800e8SDoug Rabson     ret = krb5_data_alloc (&value, len);
575c19800e8SDoug Rabson     if (ret) {
576c19800e8SDoug Rabson 	krb5_set_error_message(context->context, ret, "out of memory");
577b528cefcSMark Murray 	return ret;
578c19800e8SDoug Rabson     }
579b528cefcSMark Murray     krb5_storage_read (sp, value.data, len);
580c19800e8SDoug Rabson     ret = hdb_value2entry (context->context, &value, &log_ent.entry);
581c19800e8SDoug Rabson     krb5_data_free(&value);
5825e9cd1aeSAssar Westerlund     if (ret)
583c19800e8SDoug Rabson 	return ret;
584c19800e8SDoug Rabson 
585c19800e8SDoug Rabson     memset(&ent, 0, sizeof(ent));
586c19800e8SDoug Rabson     ret = context->db->hdb_fetch_kvno(context->context, context->db,
587c19800e8SDoug Rabson 				      log_ent.entry.principal,
588c19800e8SDoug Rabson 				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
589c19800e8SDoug Rabson     if (ret)
590c19800e8SDoug Rabson 	goto out;
591c19800e8SDoug Rabson     if (mask & KADM5_PRINC_EXPIRE_TIME) {
592b528cefcSMark Murray 	if (log_ent.entry.valid_end == NULL) {
5935e9cd1aeSAssar Westerlund 	    ent.entry.valid_end = NULL;
594b528cefcSMark Murray 	} else {
595c19800e8SDoug Rabson 	    if (ent.entry.valid_end == NULL) {
596c19800e8SDoug Rabson 		ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
5975e9cd1aeSAssar Westerlund 		if (ent.entry.valid_end == NULL) {
598c19800e8SDoug Rabson 		    ret = ENOMEM;
599c19800e8SDoug Rabson 		    krb5_set_error_message(context->context, ret, "out of memory");
600c19800e8SDoug Rabson 		    goto out;
601c19800e8SDoug Rabson 		}
602c19800e8SDoug Rabson 	    }
603c19800e8SDoug Rabson 	    *ent.entry.valid_end = *log_ent.entry.valid_end;
604c19800e8SDoug Rabson 	}
605c19800e8SDoug Rabson     }
606c19800e8SDoug Rabson     if (mask & KADM5_PW_EXPIRATION) {
607b528cefcSMark Murray 	if (log_ent.entry.pw_end == NULL) {
6085e9cd1aeSAssar Westerlund 	    ent.entry.pw_end = NULL;
609b528cefcSMark Murray 	} else {
610b528cefcSMark Murray 	    if (ent.entry.pw_end == NULL) {
611b528cefcSMark Murray 		ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
612b528cefcSMark Murray 		if (ent.entry.pw_end == NULL) {
613c19800e8SDoug Rabson 		    ret = ENOMEM;
614b528cefcSMark Murray 		    krb5_set_error_message(context->context, ret, "out of memory");
615b528cefcSMark Murray 		    goto out;
616c19800e8SDoug Rabson 		}
617c19800e8SDoug Rabson 	    }
6185e9cd1aeSAssar Westerlund 	    *ent.entry.pw_end = *log_ent.entry.pw_end;
619c19800e8SDoug Rabson 	}
620c19800e8SDoug Rabson     }
621c19800e8SDoug Rabson     if (mask & KADM5_LAST_PWD_CHANGE) {
622c19800e8SDoug Rabson 	abort ();		/* XXX */
623c19800e8SDoug Rabson     }
624c19800e8SDoug Rabson     if (mask & KADM5_ATTRIBUTES) {
625c19800e8SDoug Rabson 	ent.entry.flags = log_ent.entry.flags;
626c19800e8SDoug Rabson     }
627c19800e8SDoug Rabson     if (mask & KADM5_MAX_LIFE) {
628b528cefcSMark Murray 	if (log_ent.entry.max_life == NULL) {
6295e9cd1aeSAssar Westerlund 	    ent.entry.max_life = NULL;
630b528cefcSMark Murray 	} else {
631c19800e8SDoug Rabson 	    if (ent.entry.max_life == NULL) {
632c19800e8SDoug Rabson 		ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
633c19800e8SDoug Rabson 		if (ent.entry.max_life == NULL) {
634c19800e8SDoug Rabson 		    ret = ENOMEM;
635c19800e8SDoug Rabson 		    krb5_set_error_message(context->context, ret, "out of memory");
636c19800e8SDoug Rabson 		    goto out;
637c19800e8SDoug Rabson 		}
638b528cefcSMark Murray 	    }
639c19800e8SDoug Rabson 	    *ent.entry.max_life = *log_ent.entry.max_life;
640c19800e8SDoug Rabson 	}
641c19800e8SDoug Rabson     }
642c19800e8SDoug Rabson     if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
643c19800e8SDoug Rabson 	if (ent.entry.modified_by == NULL) {
644c19800e8SDoug Rabson 	    ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
645b528cefcSMark Murray 	    if (ent.entry.modified_by == NULL) {
646b528cefcSMark Murray 		ret = ENOMEM;
647c19800e8SDoug Rabson 		krb5_set_error_message(context->context, ret, "out of memory");
648b528cefcSMark Murray 		goto out;
649b528cefcSMark Murray 	    }
650b528cefcSMark Murray 	} else
651b528cefcSMark Murray 	    free_Event(ent.entry.modified_by);
652b528cefcSMark Murray 	ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
653b528cefcSMark Murray 	if (ret) {
654b528cefcSMark Murray 	    krb5_set_error_message(context->context, ret, "out of memory");
655b528cefcSMark Murray 	    goto out;
656b528cefcSMark Murray 	}
657b528cefcSMark Murray     }
658b528cefcSMark Murray     if (mask & KADM5_KVNO) {
659b528cefcSMark Murray 	ent.entry.kvno = log_ent.entry.kvno;
660b528cefcSMark Murray     }
661b528cefcSMark Murray     if (mask & KADM5_MKVNO) {
662c19800e8SDoug Rabson 	abort ();		/* XXX */
663c19800e8SDoug Rabson     }
6645e9cd1aeSAssar Westerlund     if (mask & KADM5_AUX_ATTRIBUTES) {
665c19800e8SDoug Rabson 	abort ();		/* XXX */
666c19800e8SDoug Rabson     }
667c19800e8SDoug Rabson     if (mask & KADM5_POLICY) {
668c19800e8SDoug Rabson 	abort ();		/* XXX */
669c19800e8SDoug Rabson     }
670c19800e8SDoug Rabson     if (mask & KADM5_POLICY_CLR) {
671c19800e8SDoug Rabson 	abort ();		/* XXX */
672c19800e8SDoug Rabson     }
673c19800e8SDoug Rabson     if (mask & KADM5_MAX_RLIFE) {
674b528cefcSMark Murray 	if (log_ent.entry.max_renew == NULL) {
6755e9cd1aeSAssar Westerlund 	    ent.entry.max_renew = NULL;
676b528cefcSMark Murray 	} else {
677b528cefcSMark Murray 	    if (ent.entry.max_renew == NULL) {
678b528cefcSMark Murray 		ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
679b528cefcSMark Murray 		if (ent.entry.max_renew == NULL) {
680b528cefcSMark Murray 		    ret = ENOMEM;
681b528cefcSMark Murray 		    krb5_set_error_message(context->context, ret, "out of memory");
682b528cefcSMark Murray 		    goto out;
683b528cefcSMark Murray 		}
684b528cefcSMark Murray 	    }
685b528cefcSMark Murray 	    *ent.entry.max_renew = *log_ent.entry.max_renew;
686c19800e8SDoug Rabson 	}
687b528cefcSMark Murray     }
688b528cefcSMark Murray     if (mask & KADM5_LAST_SUCCESS) {
689c19800e8SDoug Rabson 	abort ();		/* XXX */
690c19800e8SDoug Rabson     }
691c19800e8SDoug Rabson     if (mask & KADM5_LAST_FAILED) {
692b528cefcSMark Murray 	abort ();		/* XXX */
693c19800e8SDoug Rabson     }
694b528cefcSMark Murray     if (mask & KADM5_FAIL_AUTH_COUNT) {
695c19800e8SDoug Rabson 	abort ();		/* XXX */
696c19800e8SDoug Rabson     }
697c19800e8SDoug Rabson     if (mask & KADM5_KEY_DATA) {
698c19800e8SDoug Rabson 	size_t num;
699c19800e8SDoug Rabson 	size_t i;
700b528cefcSMark Murray 
701c19800e8SDoug Rabson 	for (i = 0; i < ent.entry.keys.len; ++i)
702c19800e8SDoug Rabson 	    free_Key(&ent.entry.keys.val[i]);
703c19800e8SDoug Rabson 	free (ent.entry.keys.val);
704c19800e8SDoug Rabson 
705c19800e8SDoug Rabson 	num = log_ent.entry.keys.len;
706c19800e8SDoug Rabson 
707c19800e8SDoug Rabson 	ent.entry.keys.len = num;
708c19800e8SDoug Rabson 	ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
709c19800e8SDoug Rabson 	if (ent.entry.keys.val == NULL) {
710c19800e8SDoug Rabson 	    krb5_set_error_message(context->context, ENOMEM, "out of memory");
711c19800e8SDoug Rabson 	    return ENOMEM;
712c19800e8SDoug Rabson 	}
713c19800e8SDoug Rabson 	for (i = 0; i < ent.entry.keys.len; ++i) {
714c19800e8SDoug Rabson 	    ret = copy_Key(&log_ent.entry.keys.val[i],
715c19800e8SDoug Rabson 			   &ent.entry.keys.val[i]);
716c19800e8SDoug Rabson 	    if (ret) {
717c19800e8SDoug Rabson 		krb5_set_error_message(context->context, ret, "out of memory");
718c19800e8SDoug Rabson 		goto out;
719c19800e8SDoug Rabson 	    }
720c19800e8SDoug Rabson 	}
721c19800e8SDoug Rabson     }
722c19800e8SDoug Rabson     if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
723c19800e8SDoug Rabson 	HDB_extensions *es = ent.entry.extensions;
724c19800e8SDoug Rabson 
725c19800e8SDoug Rabson 	ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
726c19800e8SDoug Rabson 	if (ent.entry.extensions == NULL)
727c19800e8SDoug Rabson 	    goto out;
728c19800e8SDoug Rabson 
729c19800e8SDoug Rabson 	ret = copy_HDB_extensions(log_ent.entry.extensions,
730c19800e8SDoug Rabson 				  ent.entry.extensions);
731b528cefcSMark Murray 	if (ret) {
732c19800e8SDoug Rabson 	    krb5_set_error_message(context->context, ret, "out of memory");
733b528cefcSMark Murray 	    free(ent.entry.extensions);
734b528cefcSMark Murray 	    ent.entry.extensions = es;
735b528cefcSMark Murray 	    goto out;
736b528cefcSMark Murray 	}
737b528cefcSMark Murray 	if (es) {
738b528cefcSMark Murray 	    free_HDB_extensions(es);
739c19800e8SDoug Rabson 	    free(es);
7405e9cd1aeSAssar Westerlund 	}
7415e9cd1aeSAssar Westerlund     }
7425e9cd1aeSAssar Westerlund     ret = context->db->hdb_store(context->context, context->db,
7435e9cd1aeSAssar Westerlund 				 HDB_F_REPLACE, &ent);
7445e9cd1aeSAssar Westerlund  out:
7455e9cd1aeSAssar Westerlund     hdb_free_entry (context->context, &ent);
7465e9cd1aeSAssar Westerlund     hdb_free_entry (context->context, &log_ent);
7475e9cd1aeSAssar Westerlund     return ret;
7485e9cd1aeSAssar Westerlund }
7495e9cd1aeSAssar Westerlund 
7505e9cd1aeSAssar Westerlund /*
7515e9cd1aeSAssar Westerlund  * Add a `nop' operation to the log. Does not close the log.
7525e9cd1aeSAssar Westerlund  */
7535e9cd1aeSAssar Westerlund 
7545e9cd1aeSAssar Westerlund kadm5_ret_t
kadm5_log_nop(kadm5_server_context * context)7555e9cd1aeSAssar Westerlund kadm5_log_nop (kadm5_server_context *context)
7565e9cd1aeSAssar Westerlund {
7575e9cd1aeSAssar Westerlund     krb5_storage *sp;
7585e9cd1aeSAssar Westerlund     kadm5_ret_t ret;
7595e9cd1aeSAssar Westerlund     kadm5_log_context *log_context = &context->log_context;
7605e9cd1aeSAssar Westerlund 
7615e9cd1aeSAssar Westerlund     sp = krb5_storage_emem();
7625e9cd1aeSAssar Westerlund     ret = kadm5_log_preamble (context, sp, kadm_nop);
7635e9cd1aeSAssar Westerlund     if (ret) {
764c19800e8SDoug Rabson 	krb5_storage_free (sp);
7655e9cd1aeSAssar Westerlund 	return ret;
7665e9cd1aeSAssar Westerlund     }
7675e9cd1aeSAssar Westerlund     krb5_store_int32 (sp, 0);
7685e9cd1aeSAssar Westerlund     krb5_store_int32 (sp, 0);
7695e9cd1aeSAssar Westerlund     ret = kadm5_log_postamble (log_context, sp);
7705e9cd1aeSAssar Westerlund     if (ret) {
7715e9cd1aeSAssar Westerlund 	krb5_storage_free (sp);
772c19800e8SDoug Rabson 	return ret;
7735e9cd1aeSAssar Westerlund     }
774c19800e8SDoug Rabson     ret = kadm5_log_flush (log_context, sp);
775c19800e8SDoug Rabson     krb5_storage_free (sp);
7765e9cd1aeSAssar Westerlund 
7775e9cd1aeSAssar Westerlund     return ret;
7785e9cd1aeSAssar Westerlund }
7795e9cd1aeSAssar Westerlund 
7805e9cd1aeSAssar Westerlund /*
7815e9cd1aeSAssar Westerlund  * Read a `nop' log operation from `sp' and apply it.
782b528cefcSMark Murray  */
783b528cefcSMark Murray 
784b528cefcSMark Murray static kadm5_ret_t
kadm5_log_replay_nop(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)785b528cefcSMark Murray kadm5_log_replay_nop (kadm5_server_context *context,
786b528cefcSMark Murray 		      uint32_t ver,
787b528cefcSMark Murray 		      uint32_t len,
788c19800e8SDoug Rabson 		      krb5_storage *sp)
789b528cefcSMark Murray {
790b528cefcSMark Murray     return 0;
791c19800e8SDoug Rabson }
792c19800e8SDoug Rabson 
793c19800e8SDoug Rabson /*
794c19800e8SDoug Rabson  * Call `func' for each log record in the log in `context'
795b528cefcSMark Murray  */
796b528cefcSMark Murray 
797b528cefcSMark Murray kadm5_ret_t
kadm5_log_foreach(kadm5_server_context * context,void (* func)(kadm5_server_context * server_context,uint32_t ver,time_t timestamp,enum kadm_ops op,uint32_t len,krb5_storage *,void *),void * ctx)798b528cefcSMark Murray kadm5_log_foreach (kadm5_server_context *context,
799b528cefcSMark Murray 		   void (*func)(kadm5_server_context *server_context,
800b528cefcSMark Murray 				uint32_t ver,
801b528cefcSMark Murray 				time_t timestamp,
802c19800e8SDoug Rabson 				enum kadm_ops op,
803b528cefcSMark Murray 				uint32_t len,
804b528cefcSMark Murray 				krb5_storage *,
805b528cefcSMark Murray 				void *),
806b528cefcSMark Murray 		   void *ctx)
807b528cefcSMark Murray {
808b528cefcSMark Murray     int fd = context->log_context.log_fd;
809c19800e8SDoug Rabson     krb5_storage *sp;
810c19800e8SDoug Rabson 
811c19800e8SDoug Rabson     lseek (fd, 0, SEEK_SET);
812c19800e8SDoug Rabson     sp = krb5_storage_from_fd (fd);
813c19800e8SDoug Rabson     for (;;) {
814c19800e8SDoug Rabson 	int32_t ver, timestamp, op, len, len2, ver2;
815c19800e8SDoug Rabson 
816b528cefcSMark Murray 	if(krb5_ret_int32 (sp, &ver) != 0)
817c19800e8SDoug Rabson 	    break;
818b528cefcSMark Murray 	krb5_ret_int32 (sp, &timestamp);
819b528cefcSMark Murray 	krb5_ret_int32 (sp, &op);
820b528cefcSMark Murray 	krb5_ret_int32 (sp, &len);
821b528cefcSMark Murray 	(*func)(context, ver, timestamp, op, len, sp, ctx);
822b528cefcSMark Murray 	krb5_ret_int32 (sp, &len2);
823b528cefcSMark Murray 	krb5_ret_int32 (sp, &ver2);
824b528cefcSMark Murray 	if (len != len2)
825b528cefcSMark Murray 	    abort();
826b528cefcSMark Murray 	if (ver != ver2)
827b528cefcSMark Murray 	    abort();
828b528cefcSMark Murray     }
829b528cefcSMark Murray     krb5_storage_free(sp);
830b528cefcSMark Murray     return 0;
8318373020dSJacques Vidrine }
832b528cefcSMark Murray 
833b528cefcSMark Murray /*
834b528cefcSMark Murray  * Go to end of log.
835b528cefcSMark Murray  */
836b528cefcSMark Murray 
837c19800e8SDoug Rabson krb5_storage *
kadm5_log_goto_end(int fd)838c19800e8SDoug Rabson kadm5_log_goto_end (int fd)
839c19800e8SDoug Rabson {
840c19800e8SDoug Rabson     krb5_storage *sp;
841b528cefcSMark Murray 
842b528cefcSMark Murray     sp = krb5_storage_from_fd (fd);
843b528cefcSMark Murray     krb5_storage_seek(sp, 0, SEEK_END);
844c19800e8SDoug Rabson     return sp;
845c19800e8SDoug Rabson }
846c19800e8SDoug Rabson 
847b528cefcSMark Murray /*
848b528cefcSMark Murray  * Return previous log entry.
849c19800e8SDoug Rabson  *
850b528cefcSMark Murray  * The pointer in `sp´ is assumed to be at the top of the entry before
851c19800e8SDoug Rabson  * previous entry. On success, the `sp´ pointer is set to data portion
852c19800e8SDoug Rabson  * of previous entry. In case of error, it's not changed at all.
853b528cefcSMark Murray  */
854b528cefcSMark Murray 
855c19800e8SDoug Rabson kadm5_ret_t
kadm5_log_previous(krb5_context context,krb5_storage * sp,uint32_t * ver,time_t * timestamp,enum kadm_ops * op,uint32_t * len)856c19800e8SDoug Rabson kadm5_log_previous (krb5_context context,
8578373020dSJacques Vidrine 		    krb5_storage *sp,
858c19800e8SDoug Rabson 		    uint32_t *ver,
859c19800e8SDoug Rabson 		    time_t *timestamp,
860c19800e8SDoug Rabson 		    enum kadm_ops *op,
861b528cefcSMark Murray 		    uint32_t *len)
862c19800e8SDoug Rabson {
863b528cefcSMark Murray     krb5_error_code ret;
864b528cefcSMark Murray     off_t off, oldoff;
8658373020dSJacques Vidrine     int32_t tmp;
866c19800e8SDoug Rabson 
867c19800e8SDoug Rabson     oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
868c19800e8SDoug Rabson 
869c19800e8SDoug Rabson     krb5_storage_seek(sp, -8, SEEK_CUR);
870c19800e8SDoug Rabson     ret = krb5_ret_int32 (sp, &tmp);
871c19800e8SDoug Rabson     if (ret)
872c19800e8SDoug Rabson 	goto end_of_storage;
873c19800e8SDoug Rabson     *len = tmp;
874c19800e8SDoug Rabson     ret = krb5_ret_int32 (sp, &tmp);
875c19800e8SDoug Rabson     if (ret)
876c19800e8SDoug Rabson 	goto end_of_storage;
877c19800e8SDoug Rabson     *ver = tmp;
878b528cefcSMark Murray     off = 24 + *len;
879c19800e8SDoug Rabson     krb5_storage_seek(sp, -off, SEEK_CUR);
880b528cefcSMark Murray     ret = krb5_ret_int32 (sp, &tmp);
881c19800e8SDoug Rabson     if (ret)
882c19800e8SDoug Rabson 	goto end_of_storage;
883c19800e8SDoug Rabson     if ((uint32_t)tmp != *ver) {
884c19800e8SDoug Rabson 	krb5_storage_seek(sp, oldoff, SEEK_SET);
885c19800e8SDoug Rabson 	krb5_set_error_message(context, KADM5_BAD_DB,
886c19800e8SDoug Rabson 			       "kadm5_log_previous: log entry "
887c19800e8SDoug Rabson 			       "have consistency failure, version number wrong "
888c19800e8SDoug Rabson 			       "(tmp %lu ver %lu)",
889c19800e8SDoug Rabson 			       (unsigned long)tmp,
890b528cefcSMark Murray 			       (unsigned long)*ver);
891c19800e8SDoug Rabson 	return KADM5_BAD_DB;
892c19800e8SDoug Rabson     }
893c19800e8SDoug Rabson     ret = krb5_ret_int32 (sp, &tmp);
894c19800e8SDoug Rabson     if (ret)
895c19800e8SDoug Rabson 	goto end_of_storage;
896c19800e8SDoug Rabson     *timestamp = tmp;
897b528cefcSMark Murray     ret = krb5_ret_int32 (sp, &tmp);
898b528cefcSMark Murray     if (ret)
899b528cefcSMark Murray 	goto end_of_storage;
900b528cefcSMark Murray     *op = tmp;
901b528cefcSMark Murray     ret = krb5_ret_int32 (sp, &tmp);
902b528cefcSMark Murray     if (ret)
903b528cefcSMark Murray 	goto end_of_storage;
904b528cefcSMark Murray     if ((uint32_t)tmp != *len) {
905b528cefcSMark Murray 	krb5_storage_seek(sp, oldoff, SEEK_SET);
906c19800e8SDoug Rabson 	krb5_set_error_message(context, KADM5_BAD_DB,
907c19800e8SDoug Rabson 			       "kadm5_log_previous: log entry "
908b528cefcSMark Murray 			       "have consistency failure, length wrong");
909b528cefcSMark Murray 	return KADM5_BAD_DB;
910b528cefcSMark Murray     }
911b528cefcSMark Murray     return 0;
912b528cefcSMark Murray 
913b528cefcSMark Murray  end_of_storage:
914b528cefcSMark Murray     krb5_storage_seek(sp, oldoff, SEEK_SET);
915b528cefcSMark Murray     krb5_set_error_message(context, ret, "kadm5_log_previous: end of storage "
916b528cefcSMark Murray 			   "reached before end");
917b528cefcSMark Murray     return ret;
918b528cefcSMark Murray }
9195e9cd1aeSAssar Westerlund 
9205e9cd1aeSAssar Westerlund /*
921b528cefcSMark Murray  * Replay a record from the log
922c19800e8SDoug Rabson  */
923c19800e8SDoug Rabson 
924b528cefcSMark Murray kadm5_ret_t
kadm5_log_replay(kadm5_server_context * context,enum kadm_ops op,uint32_t ver,uint32_t len,krb5_storage * sp)925b528cefcSMark Murray kadm5_log_replay (kadm5_server_context *context,
926b528cefcSMark Murray 		  enum kadm_ops op,
9275e9cd1aeSAssar Westerlund 		  uint32_t ver,
9285e9cd1aeSAssar Westerlund 		  uint32_t len,
9295e9cd1aeSAssar Westerlund 		  krb5_storage *sp)
9305e9cd1aeSAssar Westerlund {
9315e9cd1aeSAssar Westerlund     switch (op) {
9325e9cd1aeSAssar Westerlund     case kadm_create :
9335e9cd1aeSAssar Westerlund 	return kadm5_log_replay_create (context, ver, len, sp);
9345e9cd1aeSAssar Westerlund     case kadm_delete :
9355e9cd1aeSAssar Westerlund 	return kadm5_log_replay_delete (context, ver, len, sp);
936c19800e8SDoug Rabson     case kadm_rename :
9375e9cd1aeSAssar Westerlund 	return kadm5_log_replay_rename (context, ver, len, sp);
9385e9cd1aeSAssar Westerlund     case kadm_modify :
9395e9cd1aeSAssar Westerlund 	return kadm5_log_replay_modify (context, ver, len, sp);
9405e9cd1aeSAssar Westerlund     case kadm_nop :
9415e9cd1aeSAssar Westerlund 	return kadm5_log_replay_nop (context, ver, len, sp);
9425e9cd1aeSAssar Westerlund     default :
9435e9cd1aeSAssar Westerlund 	krb5_set_error_message(context->context, KADM5_FAILURE,
9445e9cd1aeSAssar Westerlund 			       "Unsupported replay op %d", (int)op);
9455e9cd1aeSAssar Westerlund 	return KADM5_FAILURE;
9465e9cd1aeSAssar Westerlund     }
9475e9cd1aeSAssar Westerlund }
9485e9cd1aeSAssar Westerlund 
9495e9cd1aeSAssar Westerlund /*
950c19800e8SDoug Rabson  * truncate the log - i.e. create an empty file with just (nop vno + 2)
9515e9cd1aeSAssar Westerlund  */
9525e9cd1aeSAssar Westerlund 
9535e9cd1aeSAssar Westerlund kadm5_ret_t
kadm5_log_truncate(kadm5_server_context * server_context)9545e9cd1aeSAssar Westerlund kadm5_log_truncate (kadm5_server_context *server_context)
9555e9cd1aeSAssar Westerlund {
9565e9cd1aeSAssar Westerlund     kadm5_ret_t ret;
9575e9cd1aeSAssar Westerlund     uint32_t vno;
9585e9cd1aeSAssar Westerlund 
9595e9cd1aeSAssar Westerlund     ret = kadm5_log_init (server_context);
9605e9cd1aeSAssar Westerlund     if (ret)
9615e9cd1aeSAssar Westerlund 	return ret;
9625e9cd1aeSAssar Westerlund 
9635e9cd1aeSAssar Westerlund     ret = kadm5_log_get_version (server_context, &vno);
964c19800e8SDoug Rabson     if (ret)
965c19800e8SDoug Rabson 	return ret;
966c19800e8SDoug Rabson 
967c19800e8SDoug Rabson     ret = kadm5_log_reinit (server_context);
968c19800e8SDoug Rabson     if (ret)
969c19800e8SDoug Rabson 	return ret;
970c19800e8SDoug Rabson 
971c19800e8SDoug Rabson     ret = kadm5_log_set_version (server_context, vno);
972c19800e8SDoug Rabson     if (ret)
973c19800e8SDoug Rabson 	return ret;
974c19800e8SDoug Rabson 
975c19800e8SDoug Rabson     ret = kadm5_log_nop (server_context);
976c19800e8SDoug Rabson     if (ret)
977c19800e8SDoug Rabson 	return ret;
978c19800e8SDoug Rabson 
979c19800e8SDoug Rabson     ret = kadm5_log_end (server_context);
980c19800e8SDoug Rabson     if (ret)
981c19800e8SDoug Rabson 	return ret;
982c19800e8SDoug Rabson     return 0;
983 
984 }
985 
986 #ifndef NO_UNIX_SOCKETS
987 
988 static char *default_signal = NULL;
989 static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
990 
991 const char *
kadm5_log_signal_socket(krb5_context context)992 kadm5_log_signal_socket(krb5_context context)
993 {
994     HEIMDAL_MUTEX_lock(&signal_mutex);
995     if (!default_signal)
996 	asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
997     HEIMDAL_MUTEX_unlock(&signal_mutex);
998 
999     return krb5_config_get_string_default(context,
1000 					  NULL,
1001 					  default_signal,
1002 					  "kdc",
1003 					  "signal_socket",
1004 					  NULL);
1005 }
1006 
1007 #else  /* NO_UNIX_SOCKETS */
1008 
1009 #define SIGNAL_SOCKET_HOST "127.0.0.1"
1010 #define SIGNAL_SOCKET_PORT "12701"
1011 
1012 kadm5_ret_t
kadm5_log_signal_socket_info(krb5_context context,int server_end,struct addrinfo ** ret_addrs)1013 kadm5_log_signal_socket_info(krb5_context context,
1014 			     int server_end,
1015 			     struct addrinfo **ret_addrs)
1016 {
1017     struct addrinfo hints;
1018     struct addrinfo *addrs = NULL;
1019     kadm5_ret_t ret = KADM5_FAILURE;
1020     int wsret;
1021 
1022     memset(&hints, 0, sizeof(hints));
1023 
1024     hints.ai_flags = AI_NUMERICHOST;
1025     if (server_end)
1026 	hints.ai_flags |= AI_PASSIVE;
1027     hints.ai_family = AF_INET;
1028     hints.ai_socktype = SOCK_STREAM;
1029     hints.ai_protocol = IPPROTO_TCP;
1030 
1031     wsret = getaddrinfo(SIGNAL_SOCKET_HOST,
1032 			SIGNAL_SOCKET_PORT,
1033 			&hints, &addrs);
1034 
1035     if (wsret != 0) {
1036 	krb5_set_error_message(context, KADM5_FAILURE,
1037 			       "%s", gai_strerror(wsret));
1038 	goto done;
1039     }
1040 
1041     if (addrs == NULL) {
1042 	krb5_set_error_message(context, KADM5_FAILURE,
1043 			       "getaddrinfo() failed to return address list");
1044 	goto done;
1045     }
1046 
1047     *ret_addrs = addrs;
1048     addrs = NULL;
1049     ret = 0;
1050 
1051  done:
1052     if (addrs)
1053 	freeaddrinfo(addrs);
1054     return ret;
1055 }
1056 
1057 #endif
1058