Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/notify_msg.c
Line
Count
Source
1
/*
2
 * Unix SMB/CIFS implementation.
3
 *
4
 * Copyright (C) Volker Lendecke 2014
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 "librpc/gen_ndr/notify.h"
22
#include "librpc/gen_ndr/messaging.h"
23
#include "lib/dbwrap/dbwrap.h"
24
#include "lib/dbwrap/dbwrap_rbt.h"
25
#include "lib/util/server_id.h"
26
#include "messages.h"
27
#include "proto.h"
28
#include "globals.h"
29
#include "tdb.h"
30
#include "util_tdb.h"
31
#include "lib/util/server_id_db.h"
32
#include "smbd/notifyd/notifyd.h"
33
34
struct notify_context {
35
  struct server_id notifyd;
36
  struct messaging_context *msg_ctx;
37
38
  struct smbd_server_connection *sconn;
39
  void (*callback)(struct smbd_server_connection *sconn,
40
       void *private_data, struct timespec when,
41
       const struct notify_event *ctx);
42
};
43
44
static void notify_handler(struct messaging_context *msg, void *private_data,
45
         uint32_t msg_type, struct server_id src,
46
         DATA_BLOB *data);
47
static int notify_context_destructor(struct notify_context *ctx);
48
49
struct notify_context *notify_init(
50
  TALLOC_CTX *mem_ctx, struct messaging_context *msg,
51
  struct smbd_server_connection *sconn,
52
  void (*callback)(struct smbd_server_connection *sconn,
53
       void *, struct timespec,
54
       const struct notify_event *))
55
0
{
56
0
  struct server_id_db *names_db;
57
0
  struct notify_context *ctx;
58
0
  NTSTATUS status;
59
60
0
  ctx = talloc(mem_ctx, struct notify_context);
61
0
  if (ctx == NULL) {
62
0
    return NULL;
63
0
  }
64
0
  ctx->msg_ctx = msg;
65
66
0
  ctx->sconn = sconn;
67
0
  ctx->callback = callback;
68
69
0
  names_db = messaging_names_db(msg);
70
0
  if (!server_id_db_lookup_one(names_db, "notify-daemon",
71
0
             &ctx->notifyd)) {
72
0
    DBG_WARNING("No notify daemon around\n");
73
0
    TALLOC_FREE(ctx);
74
0
    return NULL;
75
0
  }
76
77
0
  {
78
0
    struct server_id_buf tmp;
79
0
    DBG_DEBUG("notifyd=%s\n",
80
0
        server_id_str_buf(ctx->notifyd, &tmp));
81
0
  }
82
83
0
  if (callback != NULL) {
84
0
    status = messaging_register(msg, ctx, MSG_PVFS_NOTIFY,
85
0
              notify_handler);
86
0
    if (!NT_STATUS_IS_OK(status)) {
87
0
      DBG_WARNING("messaging_register failed: %s\n",
88
0
            nt_errstr(status));
89
0
      TALLOC_FREE(ctx);
90
0
      return NULL;
91
0
    }
92
0
  }
93
94
0
  talloc_set_destructor(ctx, notify_context_destructor);
95
96
0
  return ctx;
97
0
}
98
99
static int notify_context_destructor(struct notify_context *ctx)
100
0
{
101
0
  if (ctx->callback != NULL) {
102
0
    messaging_deregister(ctx->msg_ctx, MSG_PVFS_NOTIFY, ctx);
103
0
  }
104
105
0
  return 0;
106
0
}
107
108
static void notify_handler(struct messaging_context *msg, void *private_data,
109
         uint32_t msg_type, struct server_id src,
110
         DATA_BLOB *data)
111
0
{
112
0
  struct notify_context *ctx = talloc_get_type_abort(
113
0
    private_data, struct notify_context);
114
0
  struct notify_event_msg *event_msg;
115
0
  struct notify_event event;
116
117
0
  if (data->length < offsetof(struct notify_event_msg, path) + 1) {
118
0
    DBG_WARNING("message too short: %zu\n", data->length);
119
0
    return;
120
0
  }
121
0
  if (data->data[data->length-1] != 0) {
122
0
    DBG_WARNING("path not 0-terminated\n");
123
0
    return;
124
0
  }
125
126
0
  event_msg = (struct notify_event_msg *)data->data;
127
128
0
  event.action = event_msg->action;
129
0
  event.path = event_msg->path;
130
0
  event.private_data = event_msg->private_data;
131
132
0
  DBG_DEBUG("Got notify_event action=%"PRIu32", private_data=%p, "
133
0
       "path=%s\n",
134
0
      event.action,
135
0
      event.private_data,
136
0
      event.path);
137
138
0
  ctx->callback(ctx->sconn, event.private_data, event_msg->when, &event);
139
0
}
140
141
NTSTATUS notify_add(struct notify_context *ctx,
142
        const char *path, uint32_t filter, uint32_t subdir_filter,
143
        void *private_data)
144
0
{
145
0
  struct notify_rec_change_msg msg = {};
146
0
  struct iovec iov[2];
147
0
  size_t pathlen;
148
0
  NTSTATUS status;
149
150
0
  if (ctx == NULL) {
151
0
    return NT_STATUS_NOT_IMPLEMENTED;
152
0
  }
153
154
0
  DBG_DEBUG("path=[%s], filter=%"PRIu32", subdir_filter=%"PRIu32", "
155
0
      "private_data=%p\n",
156
0
      path,
157
0
      filter,
158
0
      subdir_filter,
159
0
      private_data);
160
161
0
  pathlen = strlen(path)+1;
162
163
0
  clock_gettime_mono(&msg.instance.creation_time);
164
0
  msg.instance.filter = filter;
165
0
  msg.instance.subdir_filter = subdir_filter;
166
0
  msg.instance.private_data = private_data;
167
168
0
  iov[0].iov_base = &msg;
169
0
  iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
170
0
  iov[1].iov_base = discard_const_p(char, path);
171
0
  iov[1].iov_len = pathlen;
172
173
0
  status =  messaging_send_iov(
174
0
    ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
175
0
    iov, ARRAY_SIZE(iov), NULL, 0);
176
177
0
  if (!NT_STATUS_IS_OK(status)) {
178
0
    DBG_DEBUG("messaging_send_iov returned %s\n",
179
0
        nt_errstr(status));
180
0
    return status;
181
0
  }
182
183
0
  return NT_STATUS_OK;
184
0
}
185
186
NTSTATUS notify_remove(struct notify_context *ctx, void *private_data,
187
           char *path)
188
0
{
189
0
  struct notify_rec_change_msg msg = {};
190
0
  struct iovec iov[2];
191
0
  NTSTATUS status;
192
193
  /* see if change notify is enabled at all */
194
0
  if (ctx == NULL) {
195
0
    return NT_STATUS_NOT_IMPLEMENTED;
196
0
  }
197
198
0
  msg.instance.private_data = private_data;
199
200
0
  iov[0].iov_base = &msg;
201
0
  iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
202
0
  iov[1].iov_base = path;
203
0
  iov[1].iov_len = strlen(path)+1;
204
205
0
  status = messaging_send_iov(
206
0
    ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
207
0
    iov, ARRAY_SIZE(iov), NULL, 0);
208
209
0
  return status;
210
0
}
211
212
void notify_trigger(struct notify_context *ctx,
213
        uint32_t action, uint32_t filter,
214
        const char *dir, const char *name)
215
0
{
216
0
  struct notify_trigger_msg msg;
217
0
  struct iovec iov[4];
218
0
  char slash = '/';
219
220
0
  DBG_DEBUG("notify_trigger called action=0x%"PRIx32", "
221
0
      "filter=0x%"PRIx32", dir=%s, name=%s\n",
222
0
      action,
223
0
      filter,
224
0
      dir,
225
0
      name);
226
227
0
  if (ctx == NULL) {
228
0
    return;
229
0
  }
230
231
0
  msg.when = timespec_current();
232
0
  msg.action = action;
233
0
  msg.filter = filter;
234
235
0
  iov[0].iov_base = &msg;
236
0
  iov[0].iov_len = offsetof(struct notify_trigger_msg, path);
237
0
  iov[1].iov_base = discard_const_p(char, dir);
238
0
  iov[1].iov_len = strlen(dir);
239
0
  iov[2].iov_base = &slash;
240
0
  iov[2].iov_len = 1;
241
0
  iov[3].iov_base = discard_const_p(char, name);
242
0
  iov[3].iov_len = strlen(name)+1;
243
244
0
  messaging_send_iov(
245
0
    ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_TRIGGER,
246
0
    iov, ARRAY_SIZE(iov), NULL, 0);
247
0
}