~lefteris-nikoltsios/+junk/samba-lp1016895

« back to all changes in this revision

Viewing changes to source3/lib/addrchange.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Samba Unix/Linux SMB client library
 
3
 * Copyright (C) Volker Lendecke 2011
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 3 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include "includes.h"
 
20
#include "lib/addrchange.h"
 
21
#include "../lib/util/tevent_ntstatus.h"
 
22
 
 
23
#if HAVE_LINUX_RTNETLINK_H
 
24
 
 
25
#include "asm/types.h"
 
26
#include "linux/netlink.h"
 
27
#include "linux/rtnetlink.h"
 
28
#include "lib/async_req/async_sock.h"
 
29
 
 
30
struct addrchange_context {
 
31
        int sock;
 
32
};
 
33
 
 
34
static int addrchange_context_destructor(struct addrchange_context *c);
 
35
 
 
36
NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
 
37
                                   struct addrchange_context **pctx)
 
38
{
 
39
        struct addrchange_context *ctx;
 
40
        struct sockaddr_nl addr;
 
41
        NTSTATUS status;
 
42
        int res;
 
43
 
 
44
        ctx = talloc(mem_ctx, struct addrchange_context);
 
45
        if (ctx == NULL) {
 
46
                return NT_STATUS_NO_MEMORY;
 
47
        }
 
48
 
 
49
        ctx->sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 
50
        if (ctx->sock == -1) {
 
51
                status = map_nt_error_from_unix(errno);
 
52
                goto fail;
 
53
        }
 
54
        talloc_set_destructor(ctx, addrchange_context_destructor);
 
55
 
 
56
        /*
 
57
         * We're interested in address changes
 
58
         */
 
59
        ZERO_STRUCT(addr);
 
60
        addr.nl_family = AF_NETLINK;
 
61
        addr.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR;
 
62
 
 
63
        res = bind(ctx->sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
 
64
        if (res == -1) {
 
65
                status = map_nt_error_from_unix(errno);
 
66
                goto fail;
 
67
        }
 
68
 
 
69
        *pctx = ctx;
 
70
        return NT_STATUS_OK;
 
71
fail:
 
72
        TALLOC_FREE(ctx);
 
73
        return status;
 
74
}
 
75
 
 
76
static int addrchange_context_destructor(struct addrchange_context *c)
 
77
{
 
78
        if (c->sock != -1) {
 
79
                close(c->sock);
 
80
                c->sock = -1;
 
81
        }
 
82
        return 0;
 
83
}
 
84
 
 
85
struct addrchange_state {
 
86
        struct tevent_context *ev;
 
87
        struct addrchange_context *ctx;
 
88
        uint8_t buf[8192];
 
89
        struct sockaddr_storage fromaddr;
 
90
        socklen_t fromaddr_len;
 
91
 
 
92
        enum addrchange_type type;
 
93
        struct sockaddr_storage addr;
 
94
};
 
95
 
 
96
static void addrchange_done(struct tevent_req *subreq);
 
97
 
 
98
struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
 
99
                                   struct tevent_context *ev,
 
100
                                   struct addrchange_context *ctx)
 
101
{
 
102
        struct tevent_req *req, *subreq;
 
103
        struct addrchange_state *state;
 
104
 
 
105
        req = tevent_req_create(mem_ctx, &state, struct addrchange_state);
 
106
        if (req == NULL) {
 
107
                return NULL;
 
108
        }
 
109
        state->ev = ev;
 
110
        state->ctx = ctx;
 
111
 
 
112
        state->fromaddr_len = sizeof(state->fromaddr);
 
113
        subreq = recvfrom_send(state, state->ev, state->ctx->sock,
 
114
                               state->buf, sizeof(state->buf), 0,
 
115
                               &state->fromaddr, &state->fromaddr_len);
 
116
        if (tevent_req_nomem(subreq, req)) {
 
117
                return tevent_req_post(req, state->ev);
 
118
        }
 
119
        tevent_req_set_callback(subreq, addrchange_done, req);
 
120
        return req;
 
121
}
 
122
 
 
123
static void addrchange_done(struct tevent_req *subreq)
 
124
{
 
125
        struct tevent_req *req = tevent_req_callback_data(
 
126
                subreq, struct tevent_req);
 
127
        struct addrchange_state *state = tevent_req_data(
 
128
                req, struct addrchange_state);
 
129
        struct sockaddr_nl *addr;
 
130
        struct nlmsghdr *h;
 
131
        struct ifaddrmsg *ifa;
 
132
        struct rtattr *rta;
 
133
        ssize_t received;
 
134
        int len;
 
135
        int err;
 
136
        bool found;
 
137
 
 
138
        received = recvfrom_recv(subreq, &err);
 
139
        TALLOC_FREE(subreq);
 
140
        if (received == -1) {
 
141
                DEBUG(10, ("recvfrom returned %s\n", strerror(errno)));
 
142
                tevent_req_nterror(req, map_nt_error_from_unix(err));
 
143
                return;
 
144
        }
 
145
        if ((state->fromaddr_len != sizeof(struct sockaddr_nl))
 
146
            || (state->fromaddr.ss_family != AF_NETLINK)) {
 
147
                DEBUG(10, ("Got message from wrong addr\n"));
 
148
                goto retry;
 
149
        }
 
150
 
 
151
        addr = (struct sockaddr_nl *)(void *)&state->addr;
 
152
        if (addr->nl_pid != 0) {
 
153
                DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
 
154
                           (int)addr->nl_pid));
 
155
                goto retry;
 
156
        }
 
157
 
 
158
        if (received < sizeof(struct nlmsghdr)) {
 
159
                DEBUG(10, ("received %d, expected at least %d\n",
 
160
                           (int)received, (int)sizeof(struct nlmsghdr)));
 
161
                goto retry;
 
162
        }
 
163
 
 
164
        h = (struct nlmsghdr *)state->buf;
 
165
        if (h->nlmsg_len < sizeof(struct nlmsghdr)) {
 
166
                DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
 
167
                           (int)h->nlmsg_len, (int)sizeof(struct nlmsghdr)));
 
168
                goto retry;
 
169
        }
 
170
        if (h->nlmsg_len > received) {
 
171
                DEBUG(10, ("nlmsg_len=%d, expected at most %d\n",
 
172
                           (int)h->nlmsg_len, (int)received));
 
173
                goto retry;
 
174
        }
 
175
        switch (h->nlmsg_type) {
 
176
        case RTM_NEWADDR:
 
177
                state->type = ADDRCHANGE_ADD;
 
178
                break;
 
179
        case RTM_DELADDR:
 
180
                state->type = ADDRCHANGE_DEL;
 
181
                break;
 
182
        default:
 
183
                DEBUG(10, ("Got unexpected type %d - ignoring\n", h->nlmsg_type));
 
184
                goto retry;
 
185
        }
 
186
 
 
187
        if (h->nlmsg_len < sizeof(struct nlmsghdr)+sizeof(struct ifaddrmsg)) {
 
188
                DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
 
189
                           (int)h->nlmsg_len,
 
190
                           (int)(sizeof(struct nlmsghdr)
 
191
                                 +sizeof(struct ifaddrmsg))));
 
192
                tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
 
193
                return;
 
194
        }
 
195
 
 
196
        ifa = (struct ifaddrmsg *)NLMSG_DATA(h);
 
197
 
 
198
        state->addr.ss_family = ifa->ifa_family;
 
199
 
 
200
        rta = IFA_RTA(ifa);
 
201
        len = h->nlmsg_len - sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg);
 
202
 
 
203
        found = false;
 
204
 
 
205
        for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
 
206
 
 
207
                if ((rta->rta_type != IFA_LOCAL)
 
208
                    && (rta->rta_type != IFA_ADDRESS)) {
 
209
                        continue;
 
210
                }
 
211
 
 
212
                switch (ifa->ifa_family) {
 
213
                case AF_INET: {
 
214
                        struct sockaddr_in *v4_addr;
 
215
                        v4_addr = (struct sockaddr_in *)(void *)&state->addr;
 
216
 
 
217
                        if (RTA_PAYLOAD(rta) != sizeof(uint32_t)) {
 
218
                                continue;
 
219
                        }
 
220
                        v4_addr->sin_addr.s_addr = *(uint32_t *)RTA_DATA(rta);
 
221
                        found = true;
 
222
                        break;
 
223
                }
 
224
                case AF_INET6: {
 
225
                        struct sockaddr_in6 *v6_addr;
 
226
                        v6_addr = (struct sockaddr_in6 *)(void *)&state->addr;
 
227
 
 
228
                        if (RTA_PAYLOAD(rta) !=
 
229
                            sizeof(v6_addr->sin6_addr.s6_addr)) {
 
230
                                continue;
 
231
                        }
 
232
                        memcpy(v6_addr->sin6_addr.s6_addr, RTA_DATA(rta),
 
233
                               sizeof(v6_addr->sin6_addr.s6_addr));
 
234
                        found = true;
 
235
                        break;
 
236
                }
 
237
                }
 
238
        }
 
239
 
 
240
        if (!found) {
 
241
                tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
 
242
                return;
 
243
        }
 
244
 
 
245
        tevent_req_done(req);
 
246
        return;
 
247
 
 
248
retry:
 
249
        state->fromaddr_len = sizeof(state->fromaddr);
 
250
        subreq = recvfrom_send(state, state->ev, state->ctx->sock,
 
251
                               state->buf, sizeof(state->buf), 0,
 
252
                               &state->fromaddr, &state->fromaddr_len);
 
253
        if (tevent_req_nomem(subreq, req)) {
 
254
                return;
 
255
        }
 
256
        tevent_req_set_callback(subreq, addrchange_done, req);
 
257
}
 
258
 
 
259
NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
 
260
                         struct sockaddr_storage *addr)
 
261
{
 
262
        struct addrchange_state *state = tevent_req_data(
 
263
                req, struct addrchange_state);
 
264
        NTSTATUS status;
 
265
 
 
266
        if (tevent_req_is_nterror(req, &status)) {
 
267
                return status;
 
268
        }
 
269
 
 
270
        *type = state->type;
 
271
        *addr = state->addr;
 
272
        return NT_STATUS_OK;
 
273
}
 
274
 
 
275
#else
 
276
 
 
277
NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
 
278
                                   struct addrchange_context **pctx)
 
279
{
 
280
        return NT_STATUS_NOT_SUPPORTED;
 
281
}
 
282
 
 
283
struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
 
284
                                   struct tevent_context *ev,
 
285
                                   struct addrchange_context *ctx)
 
286
{
 
287
        return NULL;
 
288
}
 
289
 
 
290
NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
 
291
                         struct sockaddr_storage *addr)
 
292
{
 
293
        return NT_STATUS_NOT_IMPLEMENTED;
 
294
}
 
295
 
 
296
#endif