cleanupdb: Fix a memory read error
[ambi/samba-autobuild/.git] / source3 / lib / cleanupdb.c
1 /*
2    Unix SMB/CIFS implementation.
3    Implementation of reliable cleanup events
4    Copyright (C) Ralph Boehme 2016
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "cleanupdb.h"
21
22 struct cleanup_key {
23         pid_t pid;
24 };
25
26 struct cleanup_rec {
27         /* Storing the pid here as well saves a few lines of code */
28         pid_t pid;
29         bool unclean;
30 };
31
32 static struct tdb_wrap *cleanup_db(void)
33 {
34         static struct tdb_wrap *db;
35         char *db_path = NULL;
36         int tdbflags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST |
37                 TDB_MUTEX_LOCKING;
38
39         if (db != NULL) {
40                 return db;
41         }
42
43         db_path = lock_path("smbd_cleanupd.tdb");
44         if (db_path == NULL) {
45                 return NULL;
46         }
47
48         db = tdb_wrap_open(NULL, db_path, 0, tdbflags,
49                            O_CREAT | O_RDWR, 0644);
50         if (db == NULL) {
51                 DBG_ERR("Failed to open smbd_cleanupd.tdb\n");
52         }
53
54         TALLOC_FREE(db_path);
55         return db;
56 }
57
58 bool cleanupdb_store_child(const pid_t pid, const bool unclean)
59 {
60         struct tdb_wrap *db;
61         struct cleanup_key key = { .pid = pid };
62         struct cleanup_rec rec = { .pid = pid, .unclean = unclean };
63         TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) };
64         TDB_DATA tdbdata = { .dptr = (uint8_t *)&rec, .dsize = sizeof(rec) };
65         int result;
66
67         db = cleanup_db();
68         if (db == NULL) {
69                 return false;
70         }
71
72         result = tdb_store(db->tdb, tdbkey, tdbdata, TDB_REPLACE);
73         if (result != 0) {
74                 DBG_ERR("tdb_store failed for pid %d\n", (int)pid);
75                 return false;
76         }
77
78         return true;
79 }
80
81 bool cleanupdb_delete_child(const pid_t pid)
82 {
83         struct tdb_wrap *db;
84         struct cleanup_key key = { .pid = pid };
85         TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) };
86         int result;
87
88         db = cleanup_db();
89         if (db == NULL) {
90                 return false;
91         }
92
93         result = tdb_delete(db->tdb, tdbkey);
94         if (result != 0) {
95                 DBG_ERR("tdb_delete failed for pid %d\n", (int)pid);
96                 return false;
97         }
98
99         return true;
100 }
101
102 static bool cleanup_rec_parse(TDB_DATA tdbdata,
103                               struct cleanup_rec *cleanup_rec)
104 {
105         if (tdbdata.dsize != sizeof(struct cleanup_rec)) {
106                 DBG_ERR("Found invalid value length %d in cleanup.tdb\n",
107                         (int)tdbdata.dsize);
108                 return false;
109         }
110
111         memcpy(cleanup_rec, tdbdata.dptr, sizeof(struct cleanup_rec));
112
113         return true;
114 }
115
116 struct cleanup_read_state {
117         int (*fn)(const pid_t pid, const bool cleanup, void *private_data);
118         void *private_data;
119 };
120
121 static int cleanup_traverse_fn(struct tdb_context *tdb,
122                                TDB_DATA key, TDB_DATA value,
123                                void *private_data)
124 {
125         struct cleanup_read_state *state =
126                 (struct cleanup_read_state *)private_data;
127         struct cleanup_rec rec;
128         bool ok;
129         int result;
130
131         ok = cleanup_rec_parse(value, &rec);
132         if (!ok) {
133                 return -1;
134         }
135
136         result = state->fn(rec.pid, rec.unclean, state->private_data);
137         if (result != 0) {
138                 return -1;
139         }
140
141         return 0;
142 }
143
144 int cleanupdb_traverse_read(int (*fn)(const pid_t pid,
145                                       const bool cleanup,
146                                       void *private_data),
147                             void *private_data)
148 {
149         struct tdb_wrap *db;
150         struct cleanup_read_state state;
151         int result;
152
153         db = cleanup_db();
154         if (db == NULL) {
155                 return -1;
156         }
157
158         state = (struct cleanup_read_state) {
159                 .fn = fn,
160                 .private_data = private_data
161         };
162
163         result = tdb_traverse_read(db->tdb, cleanup_traverse_fn, &state);
164         if (result < 0) {
165                 DBG_ERR("tdb_traverse_read failed\n");
166                 return -1;
167         }
168
169         return result;
170 }