s3-libsmb: finally remove cli_read_old()
[samba.git] / source3 / lib / serverid.c
1 /*
2    Unix SMB/CIFS implementation.
3    Implementation of a reliable server_exists()
4    Copyright (C) Volker Lendecke 2010
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 "includes.h"
21 #include "system/filesys.h"
22 #include "serverid.h"
23 #include "util_tdb.h"
24 #include "dbwrap.h"
25 #include "lib/util/tdb_wrap.h"
26
27 struct serverid_key {
28         pid_t pid;
29         uint32_t task_id;
30         uint32_t vnn;
31 };
32
33 struct serverid_data {
34         uint64_t unique_id;
35         uint32_t msg_flags;
36 };
37
38 bool serverid_parent_init(TALLOC_CTX *mem_ctx)
39 {
40         struct tdb_wrap *db;
41
42         /*
43          * Open the tdb in the parent process (smbd) so that our
44          * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
45          * work.
46          */
47
48         db = tdb_wrap_open(mem_ctx, lock_path("serverid.tdb"),
49                            0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT,
50                            0644);
51         if (db == NULL) {
52                 DEBUG(1, ("could not open serverid.tdb: %s\n",
53                           strerror(errno)));
54                 return false;
55         }
56         return true;
57 }
58
59 static struct db_context *serverid_db(void)
60 {
61         static struct db_context *db;
62
63         if (db != NULL) {
64                 return db;
65         }
66         db = db_open(NULL, lock_path("serverid.tdb"), 0,
67                      TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT, 0644);
68         return db;
69 }
70
71 static void serverid_fill_key(const struct server_id *id,
72                               struct serverid_key *key)
73 {
74         ZERO_STRUCTP(key);
75         key->pid = id->pid;
76         key->task_id = id->task_id;
77         key->vnn = id->vnn;
78 }
79
80 bool serverid_register(const struct server_id id, uint32_t msg_flags)
81 {
82         struct db_context *db;
83         struct serverid_key key;
84         struct serverid_data data;
85         struct db_record *rec;
86         TDB_DATA tdbkey, tdbdata;
87         NTSTATUS status;
88         bool ret = false;
89
90         db = serverid_db();
91         if (db == NULL) {
92                 return false;
93         }
94
95         serverid_fill_key(&id, &key);
96         tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
97
98         rec = db->fetch_locked(db, talloc_tos(), tdbkey);
99         if (rec == NULL) {
100                 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
101                 return false;
102         }
103
104         ZERO_STRUCT(data);
105         data.unique_id = id.unique_id;
106         data.msg_flags = msg_flags;
107
108         tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
109         status = rec->store(rec, tdbdata, 0);
110         if (!NT_STATUS_IS_OK(status)) {
111                 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
112                           nt_errstr(status)));
113                 goto done;
114         }
115         ret = true;
116 done:
117         TALLOC_FREE(rec);
118         return ret;
119 }
120
121 bool serverid_register_msg_flags(const struct server_id id, bool do_reg,
122                                  uint32_t msg_flags)
123 {
124         struct db_context *db;
125         struct serverid_key key;
126         struct serverid_data *data;
127         struct db_record *rec;
128         TDB_DATA tdbkey;
129         NTSTATUS status;
130         bool ret = false;
131
132         db = serverid_db();
133         if (db == NULL) {
134                 return false;
135         }
136
137         serverid_fill_key(&id, &key);
138         tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
139
140         rec = db->fetch_locked(db, talloc_tos(), tdbkey);
141         if (rec == NULL) {
142                 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
143                 return false;
144         }
145
146         if (rec->value.dsize != sizeof(struct serverid_data)) {
147                 DEBUG(1, ("serverid record has unexpected size %d "
148                           "(wanted %d)\n", (int)rec->value.dsize,
149                           (int)sizeof(struct serverid_data)));
150                 goto done;
151         }
152
153         data = (struct serverid_data *)rec->value.dptr;
154
155         if (do_reg) {
156                 data->msg_flags |= msg_flags;
157         } else {
158                 data->msg_flags &= ~msg_flags;
159         }
160
161         status = rec->store(rec, rec->value, 0);
162         if (!NT_STATUS_IS_OK(status)) {
163                 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
164                           nt_errstr(status)));
165                 goto done;
166         }
167         ret = true;
168 done:
169         TALLOC_FREE(rec);
170         return ret;
171 }
172
173 bool serverid_deregister(struct server_id id)
174 {
175         struct db_context *db;
176         struct serverid_key key;
177         struct db_record *rec;
178         TDB_DATA tdbkey;
179         NTSTATUS status;
180         bool ret = false;
181
182         db = serverid_db();
183         if (db == NULL) {
184                 return false;
185         }
186
187         serverid_fill_key(&id, &key);
188         tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
189
190         rec = db->fetch_locked(db, talloc_tos(), tdbkey);
191         if (rec == NULL) {
192                 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
193                 return false;
194         }
195
196         status = rec->delete_rec(rec);
197         if (!NT_STATUS_IS_OK(status)) {
198                 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
199                           nt_errstr(status)));
200                 goto done;
201         }
202         ret = true;
203 done:
204         TALLOC_FREE(rec);
205         return ret;
206 }
207
208 struct serverid_exists_state {
209         const struct server_id *id;
210         bool exists;
211 };
212
213 static int server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
214 {
215         struct serverid_exists_state *state =
216                 (struct serverid_exists_state *)priv;
217
218         if (data.dsize != sizeof(struct serverid_data)) {
219                 return -1;
220         }
221
222         /*
223          * Use memcmp, not direct compare. data.dptr might not be
224          * aligned.
225          */
226         state->exists = (memcmp(&state->id->unique_id, data.dptr,
227                                 sizeof(state->id->unique_id)) == 0);
228         return 0;
229 }
230
231 bool serverid_exists(const struct server_id *id)
232 {
233         struct db_context *db;
234         struct serverid_exists_state state;
235         struct serverid_key key;
236         TDB_DATA tdbkey;
237
238         if (lp_clustering() && !process_exists(*id)) {
239                 return false;
240         }
241
242         db = serverid_db();
243         if (db == NULL) {
244                 return false;
245         }
246
247         serverid_fill_key(id, &key);
248         tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
249
250         state.id = id;
251         state.exists = false;
252
253         if (db->parse_record(db, tdbkey, server_exists_parse, &state) != 0) {
254                 return false;
255         }
256         return state.exists;
257 }
258
259 static bool serverid_rec_parse(const struct db_record *rec,
260                                struct server_id *id, uint32_t *msg_flags)
261 {
262         struct serverid_key key;
263         struct serverid_data data;
264
265         if (rec->key.dsize != sizeof(key)) {
266                 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
267                           (int)rec->key.dsize));
268                 return false;
269         }
270         if (rec->value.dsize != sizeof(data)) {
271                 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
272                           (int)rec->value.dsize));
273                 return false;
274         }
275
276         memcpy(&key, rec->key.dptr, sizeof(key));
277         memcpy(&data, rec->value.dptr, sizeof(data));
278
279         id->pid = key.pid;
280         id->task_id = key.task_id;
281         id->vnn = key.vnn;
282         id->unique_id = data.unique_id;
283         *msg_flags = data.msg_flags;
284         return true;
285 }
286
287 struct serverid_traverse_read_state {
288         int (*fn)(const struct server_id *id, uint32_t msg_flags,
289                   void *private_data);
290         void *private_data;
291 };
292
293 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
294 {
295         struct serverid_traverse_read_state *state =
296                 (struct serverid_traverse_read_state *)private_data;
297         struct server_id id;
298         uint32_t msg_flags;
299
300         if (!serverid_rec_parse(rec, &id, &msg_flags)) {
301                 return 0;
302         }
303         return state->fn(&id, msg_flags,state->private_data);
304 }
305
306 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
307                                       uint32_t msg_flags, void *private_data),
308                             void *private_data)
309 {
310         struct db_context *db;
311         struct serverid_traverse_read_state state;
312
313         db = serverid_db();
314         if (db == NULL) {
315                 return false;
316         }
317         state.fn = fn;
318         state.private_data = private_data;
319         return db->traverse_read(db, serverid_traverse_read_fn, &state);
320 }
321
322 struct serverid_traverse_state {
323         int (*fn)(struct db_record *rec, const struct server_id *id,
324                   uint32_t msg_flags, void *private_data);
325         void *private_data;
326 };
327
328 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
329 {
330         struct serverid_traverse_state *state =
331                 (struct serverid_traverse_state *)private_data;
332         struct server_id id;
333         uint32_t msg_flags;
334
335         if (!serverid_rec_parse(rec, &id, &msg_flags)) {
336                 return 0;
337         }
338         return state->fn(rec, &id, msg_flags, state->private_data);
339 }
340
341 bool serverid_traverse(int (*fn)(struct db_record *rec,
342                                  const struct server_id *id,
343                                  uint32_t msg_flags, void *private_data),
344                             void *private_data)
345 {
346         struct db_context *db;
347         struct serverid_traverse_state state;
348
349         db = serverid_db();
350         if (db == NULL) {
351                 return false;
352         }
353         state.fn = fn;
354         state.private_data = private_data;
355         return db->traverse(db, serverid_traverse_fn, &state);
356 }