73004489befaa212f40a6642de36551fb046d582
[nivanova/samba-autobuild/.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 "lib/util/server_id.h"
23 #include "serverid.h"
24 #include "util_tdb.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "lib/tdb_wrap/tdb_wrap.h"
28 #include "lib/param/param.h"
29 #include "ctdbd_conn.h"
30 #include "messages.h"
31 #include "lib/messages_ctdb.h"
32 #include "lib/messages_dgm.h"
33
34 struct serverid_key {
35         pid_t pid;
36         uint32_t task_id;
37         uint32_t vnn;
38 };
39
40 struct serverid_data {
41         uint64_t unique_id;
42         uint32_t msg_flags;
43 };
44
45 static struct db_context *serverid_db(void)
46 {
47         static struct db_context *db;
48         char *db_path;
49
50         if (db != NULL) {
51                 return db;
52         }
53
54         db_path = lock_path("serverid.tdb");
55         if (db_path == NULL) {
56                 return NULL;
57         }
58
59         db = db_open(NULL, db_path, 0,
60                      TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
61                      O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2,
62                      DBWRAP_FLAG_NONE);
63         TALLOC_FREE(db_path);
64         return db;
65 }
66
67 bool serverid_parent_init(TALLOC_CTX *mem_ctx)
68 {
69         struct db_context *db;
70
71         db = serverid_db();
72         if (db == NULL) {
73                 DEBUG(1, ("could not open serverid.tdb: %s\n",
74                           strerror(errno)));
75                 return false;
76         }
77
78         return true;
79 }
80
81 static void serverid_fill_key(const struct server_id *id,
82                               struct serverid_key *key)
83 {
84         ZERO_STRUCTP(key);
85         key->pid = id->pid;
86         key->task_id = id->task_id;
87         key->vnn = id->vnn;
88 }
89
90 bool serverid_register(const struct server_id id, uint32_t msg_flags)
91 {
92         struct db_context *db;
93         struct serverid_key key;
94         struct serverid_data data;
95         struct db_record *rec;
96         TDB_DATA tdbkey, tdbdata;
97         NTSTATUS status;
98         bool ret = false;
99
100         db = serverid_db();
101         if (db == NULL) {
102                 return false;
103         }
104
105         serverid_fill_key(&id, &key);
106         tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
107
108         rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
109         if (rec == NULL) {
110                 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
111                 return false;
112         }
113
114         ZERO_STRUCT(data);
115         data.unique_id = id.unique_id;
116         data.msg_flags = msg_flags;
117
118         tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
119         status = dbwrap_record_store(rec, tdbdata, 0);
120         if (!NT_STATUS_IS_OK(status)) {
121                 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
122                           nt_errstr(status)));
123                 goto done;
124         }
125
126         if (lp_clustering()) {
127                 register_with_ctdbd(messaging_ctdb_connection(), id.unique_id,
128                                     NULL, NULL);
129         }
130
131         ret = true;
132 done:
133         TALLOC_FREE(rec);
134         return ret;
135 }
136
137 bool serverid_deregister(struct server_id id)
138 {
139         struct db_context *db;
140         struct serverid_key key;
141         struct db_record *rec;
142         TDB_DATA tdbkey;
143         NTSTATUS status;
144         bool ret = false;
145
146         db = serverid_db();
147         if (db == NULL) {
148                 return false;
149         }
150
151         serverid_fill_key(&id, &key);
152         tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
153
154         rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
155         if (rec == NULL) {
156                 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
157                 return false;
158         }
159
160         status = dbwrap_record_delete(rec);
161         if (!NT_STATUS_IS_OK(status)) {
162                 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
163                           nt_errstr(status)));
164                 goto done;
165         }
166         ret = true;
167 done:
168         TALLOC_FREE(rec);
169         return ret;
170 }
171
172 static bool serverid_exists_local(const struct server_id *id)
173 {
174         bool exists = process_exists_by_pid(id->pid);
175         uint64_t unique;
176         int ret;
177
178         if (!exists) {
179                 return false;
180         }
181
182         if (id->unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
183                 return true;
184         }
185
186         ret = messaging_dgm_get_unique(id->pid, &unique);
187         if (ret != 0) {
188                 return false;
189         }
190
191         return (unique == id->unique_id);
192 }
193
194 bool serverid_exists(const struct server_id *id)
195 {
196         if (procid_is_local(id)) {
197                 return serverid_exists_local(id);
198         }
199
200         if (lp_clustering()) {
201                 return ctdbd_process_exists(messaging_ctdb_connection(),
202                                             id->vnn, id->pid, id->unique_id);
203         }
204
205         return false;
206 }
207
208 static bool serverid_rec_parse(const struct db_record *rec,
209                                struct server_id *id, uint32_t *msg_flags)
210 {
211         struct serverid_key key;
212         struct serverid_data data;
213         TDB_DATA tdbkey;
214         TDB_DATA tdbdata;
215
216         tdbkey = dbwrap_record_get_key(rec);
217         tdbdata = dbwrap_record_get_value(rec);
218
219         if (tdbkey.dsize != sizeof(key)) {
220                 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
221                           (int)tdbkey.dsize));
222                 return false;
223         }
224         if (tdbdata.dsize != sizeof(data)) {
225                 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
226                           (int)tdbdata.dsize));
227                 return false;
228         }
229
230         memcpy(&key, tdbkey.dptr, sizeof(key));
231         memcpy(&data, tdbdata.dptr, sizeof(data));
232
233         id->pid = key.pid;
234         id->task_id = key.task_id;
235         id->vnn = key.vnn;
236         id->unique_id = data.unique_id;
237         *msg_flags = data.msg_flags;
238         return true;
239 }
240
241 struct serverid_traverse_read_state {
242         int (*fn)(const struct server_id *id, uint32_t msg_flags,
243                   void *private_data);
244         void *private_data;
245 };
246
247 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
248 {
249         struct serverid_traverse_read_state *state =
250                 (struct serverid_traverse_read_state *)private_data;
251         struct server_id id;
252         uint32_t msg_flags;
253
254         if (!serverid_rec_parse(rec, &id, &msg_flags)) {
255                 return 0;
256         }
257         return state->fn(&id, msg_flags,state->private_data);
258 }
259
260 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
261                                       uint32_t msg_flags, void *private_data),
262                             void *private_data)
263 {
264         struct db_context *db;
265         struct serverid_traverse_read_state state;
266         NTSTATUS status;
267
268         db = serverid_db();
269         if (db == NULL) {
270                 return false;
271         }
272         state.fn = fn;
273         state.private_data = private_data;
274
275         status = dbwrap_traverse_read(db, serverid_traverse_read_fn, &state,
276                                       NULL);
277         return NT_STATUS_IS_OK(status);
278 }
279
280 struct serverid_traverse_state {
281         int (*fn)(struct db_record *rec, const struct server_id *id,
282                   uint32_t msg_flags, void *private_data);
283         void *private_data;
284 };
285
286 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
287 {
288         struct serverid_traverse_state *state =
289                 (struct serverid_traverse_state *)private_data;
290         struct server_id id;
291         uint32_t msg_flags;
292
293         if (!serverid_rec_parse(rec, &id, &msg_flags)) {
294                 return 0;
295         }
296         return state->fn(rec, &id, msg_flags, state->private_data);
297 }
298
299 bool serverid_traverse(int (*fn)(struct db_record *rec,
300                                  const struct server_id *id,
301                                  uint32_t msg_flags, void *private_data),
302                             void *private_data)
303 {
304         struct db_context *db;
305         struct serverid_traverse_state state;
306         NTSTATUS status;
307
308         db = serverid_db();
309         if (db == NULL) {
310                 return false;
311         }
312         state.fn = fn;
313         state.private_data = private_data;
314
315         status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
316         return NT_STATUS_IS_OK(status);
317 }
318
319 struct msg_all {
320         struct messaging_context *msg_ctx;
321         int msg_type;
322         uint32_t msg_flag;
323         const void *buf;
324         size_t len;
325         int n_sent;
326 };
327
328 /****************************************************************************
329  Send one of the messages for the broadcast.
330 ****************************************************************************/
331
332 static int traverse_fn(struct db_record *rec, const struct server_id *id,
333                        uint32_t msg_flags, void *state)
334 {
335         struct msg_all *msg_all = (struct msg_all *)state;
336         NTSTATUS status;
337
338         /* Don't send if the receiver hasn't registered an interest. */
339
340         if((msg_flags & msg_all->msg_flag) == 0) {
341                 return 0;
342         }
343
344         /* If the msg send fails because the pid was not found (i.e. smbd died),
345          * the msg has already been deleted from the messages.tdb.*/
346
347         status = messaging_send_buf(msg_all->msg_ctx, *id, msg_all->msg_type,
348                                     (const uint8_t *)msg_all->buf, msg_all->len);
349
350         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
351                 struct server_id_buf idbuf;
352
353                 /*
354                  * If the pid was not found delete the entry from
355                  * serverid.tdb
356                  */
357
358                 DEBUG(2, ("pid %s doesn't exist\n",
359                           server_id_str_buf(*id, &idbuf)));
360
361                 dbwrap_record_delete(rec);
362         }
363         msg_all->n_sent++;
364         return 0;
365 }
366
367 /**
368  * Send a message to all smbd processes.
369  *
370  * It isn't very efficient, but should be OK for the sorts of
371  * applications that use it. When we need efficient broadcast we can add
372  * it.
373  *
374  * @param n_sent Set to the number of messages sent.  This should be
375  * equal to the number of processes, but be careful for races.
376  *
377  * @retval True for success.
378  **/
379 bool message_send_all(struct messaging_context *msg_ctx,
380                       int msg_type,
381                       const void *buf, size_t len,
382                       int *n_sent)
383 {
384         struct msg_all msg_all;
385
386         msg_all.msg_type = msg_type;
387         if (msg_type < 0x100) {
388                 msg_all.msg_flag = FLAG_MSG_GENERAL;
389         } else if (msg_type > 0x100 && msg_type < 0x200) {
390                 msg_all.msg_flag = FLAG_MSG_NMBD;
391         } else if (msg_type > 0x200 && msg_type < 0x300) {
392                 msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
393         } else if (msg_type > 0x300 && msg_type < 0x400) {
394                 msg_all.msg_flag = FLAG_MSG_SMBD;
395         } else if (msg_type > 0x400 && msg_type < 0x600) {
396                 msg_all.msg_flag = FLAG_MSG_WINBIND;
397         } else if (msg_type > 4000 && msg_type < 5000) {
398                 msg_all.msg_flag = FLAG_MSG_DBWRAP;
399         } else {
400                 return false;
401         }
402
403         msg_all.buf = buf;
404         msg_all.len = len;
405         msg_all.n_sent = 0;
406         msg_all.msg_ctx = msg_ctx;
407
408         serverid_traverse(traverse_fn, &msg_all);
409         if (n_sent)
410                 *n_sent = msg_all.n_sent;
411         return true;
412 }