~ubuntu-branches/ubuntu/jaunty/wpasupplicant/jaunty

« back to all changes in this revision

Viewing changes to src/l2_packet/l2_packet_privsep.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-12-02 20:52:16 UTC
  • mfrom: (2.1.30 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081202205216-72fqozu84sdt89a8
Tags: 0.6.4-3
Bugfix: "Missing -d in testing for a directory in init script". 
Thanks to Braun Gábor <braung@renyi.hu> for reporting and the patch.
(Closes: #506328)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant - Layer2 packet handling with privilege separation
 
3
 * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
 
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 version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
#include <sys/un.h>
 
17
 
 
18
#include "common.h"
 
19
#include "eloop.h"
 
20
#include "l2_packet.h"
 
21
#include "privsep_commands.h"
 
22
 
 
23
 
 
24
struct l2_packet_data {
 
25
        int fd; /* UNIX domain socket for privsep access */
 
26
        void (*rx_callback)(void *ctx, const u8 *src_addr,
 
27
                            const u8 *buf, size_t len);
 
28
        void *rx_callback_ctx;
 
29
        u8 own_addr[ETH_ALEN];
 
30
        char *own_socket_path;
 
31
        struct sockaddr_un priv_addr;
 
32
};
 
33
 
 
34
 
 
35
static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
 
36
                        const void *data, size_t data_len)
 
37
{
 
38
        struct msghdr msg;
 
39
        struct iovec io[2];
 
40
 
 
41
        io[0].iov_base = &cmd;
 
42
        io[0].iov_len = sizeof(cmd);
 
43
        io[1].iov_base = (u8 *) data;
 
44
        io[1].iov_len = data_len;
 
45
 
 
46
        os_memset(&msg, 0, sizeof(msg));
 
47
        msg.msg_iov = io;
 
48
        msg.msg_iovlen = data ? 2 : 1;
 
49
        msg.msg_name = &l2->priv_addr;
 
50
        msg.msg_namelen = sizeof(l2->priv_addr);
 
51
 
 
52
        if (sendmsg(l2->fd, &msg, 0) < 0) {
 
53
                perror("L2: sendmsg(cmd)");
 
54
                return -1;
 
55
        }
 
56
 
 
57
        return 0;
 
58
}
 
59
 
 
60
                             
 
61
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
 
62
{
 
63
        os_memcpy(addr, l2->own_addr, ETH_ALEN);
 
64
        return 0;
 
65
}
 
66
 
 
67
 
 
68
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
 
69
                   const u8 *buf, size_t len)
 
70
{
 
71
        struct msghdr msg;
 
72
        struct iovec io[4];
 
73
        int cmd = PRIVSEP_CMD_L2_SEND;
 
74
 
 
75
        io[0].iov_base = &cmd;
 
76
        io[0].iov_len = sizeof(cmd);
 
77
        io[1].iov_base = &dst_addr;
 
78
        io[1].iov_len = ETH_ALEN;
 
79
        io[2].iov_base = &proto;
 
80
        io[2].iov_len = 2;
 
81
        io[3].iov_base = (u8 *) buf;
 
82
        io[3].iov_len = len;
 
83
 
 
84
        os_memset(&msg, 0, sizeof(msg));
 
85
        msg.msg_iov = io;
 
86
        msg.msg_iovlen = 4;
 
87
        msg.msg_name = &l2->priv_addr;
 
88
        msg.msg_namelen = sizeof(l2->priv_addr);
 
89
 
 
90
        if (sendmsg(l2->fd, &msg, 0) < 0) {
 
91
                perror("L2: sendmsg(packet_send)");
 
92
                return -1;
 
93
        }
 
94
 
 
95
        return 0;
 
96
}
 
97
 
 
98
 
 
99
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
 
100
{
 
101
        struct l2_packet_data *l2 = eloop_ctx;
 
102
        u8 buf[2300];
 
103
        int res;
 
104
        struct sockaddr_un from;
 
105
        socklen_t fromlen = sizeof(from);
 
106
 
 
107
        os_memset(&from, 0, sizeof(from));
 
108
        res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
 
109
                       &fromlen);
 
110
        if (res < 0) {
 
111
                perror("l2_packet_receive - recvfrom");
 
112
                return;
 
113
        }
 
114
        if (res < ETH_ALEN) {
 
115
                wpa_printf(MSG_DEBUG, "L2: Too show packet received");
 
116
                return;
 
117
        }
 
118
 
 
119
        if (from.sun_family != AF_UNIX ||
 
120
            os_strncmp(from.sun_path, l2->priv_addr.sun_path,
 
121
                       sizeof(from.sun_path)) != 0) {
 
122
                wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
 
123
                           "source");
 
124
                return;
 
125
        }
 
126
 
 
127
        l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
 
128
                        res - ETH_ALEN);
 
129
}
 
130
 
 
131
 
 
132
struct l2_packet_data * l2_packet_init(
 
133
        const char *ifname, const u8 *own_addr, unsigned short protocol,
 
134
        void (*rx_callback)(void *ctx, const u8 *src_addr,
 
135
                            const u8 *buf, size_t len),
 
136
        void *rx_callback_ctx, int l2_hdr)
 
137
{
 
138
        struct l2_packet_data *l2;
 
139
        char *own_dir = "/tmp";
 
140
        char *priv_dir = "/var/run/wpa_priv";
 
141
        size_t len;
 
142
        static unsigned int counter = 0;
 
143
        struct sockaddr_un addr;
 
144
        fd_set rfds;
 
145
        struct timeval tv;
 
146
        int res;
 
147
        u8 reply[ETH_ALEN + 1];
 
148
        int reg_cmd[2];
 
149
 
 
150
        l2 = os_zalloc(sizeof(struct l2_packet_data));
 
151
        if (l2 == NULL)
 
152
                return NULL;
 
153
        l2->rx_callback = rx_callback;
 
154
        l2->rx_callback_ctx = rx_callback_ctx;
 
155
 
 
156
        len = os_strlen(own_dir) + 50;
 
157
        l2->own_socket_path = os_malloc(len);
 
158
        if (l2->own_socket_path == NULL) {
 
159
                os_free(l2);
 
160
                return NULL;
 
161
        }
 
162
        os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
 
163
                    own_dir, getpid(), counter++);
 
164
 
 
165
        l2->priv_addr.sun_family = AF_UNIX;
 
166
        os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
 
167
                    "%s/%s", priv_dir, ifname);
 
168
 
 
169
        l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
 
170
        if (l2->fd < 0) {
 
171
                perror("socket(PF_UNIX)");
 
172
                os_free(l2->own_socket_path);
 
173
                l2->own_socket_path = NULL;
 
174
                os_free(l2);
 
175
                return NULL;
 
176
        }
 
177
 
 
178
        os_memset(&addr, 0, sizeof(addr));
 
179
        addr.sun_family = AF_UNIX;
 
180
        os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
 
181
        if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 
182
                perror("bind(PF_UNIX)");
 
183
                goto fail;
 
184
        }
 
185
 
 
186
        reg_cmd[0] = protocol;
 
187
        reg_cmd[1] = l2_hdr;
 
188
        if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
 
189
            < 0) {
 
190
                wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
 
191
                goto fail;
 
192
        }
 
193
 
 
194
        FD_ZERO(&rfds);
 
195
        FD_SET(l2->fd, &rfds);
 
196
        tv.tv_sec = 5;
 
197
        tv.tv_usec = 0;
 
198
        res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
 
199
        if (res < 0 && errno != EINTR) {
 
200
                perror("select");
 
201
                goto fail;
 
202
        }
 
203
 
 
204
        if (FD_ISSET(l2->fd, &rfds)) {
 
205
                res = recv(l2->fd, reply, sizeof(reply), 0);
 
206
                if (res < 0) {
 
207
                        perror("recv");
 
208
                        goto fail;
 
209
                }
 
210
        } else {
 
211
                wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
 
212
                           "registration reply");
 
213
                goto fail;
 
214
        }
 
215
 
 
216
        if (res != ETH_ALEN) {
 
217
                wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
 
218
                           "(len=%d)", res);
 
219
        }
 
220
        os_memcpy(l2->own_addr, reply, ETH_ALEN);
 
221
 
 
222
        eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
 
223
 
 
224
        return l2;
 
225
 
 
226
fail:
 
227
        close(l2->fd);
 
228
        l2->fd = -1;
 
229
        unlink(l2->own_socket_path);
 
230
        os_free(l2->own_socket_path);
 
231
        l2->own_socket_path = NULL;
 
232
        os_free(l2);
 
233
        return NULL;
 
234
}
 
235
 
 
236
 
 
237
void l2_packet_deinit(struct l2_packet_data *l2)
 
238
{
 
239
        if (l2 == NULL)
 
240
                return;
 
241
 
 
242
        if (l2->fd >= 0) {
 
243
                wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
 
244
                eloop_unregister_read_sock(l2->fd);
 
245
                close(l2->fd);
 
246
        }
 
247
 
 
248
        if (l2->own_socket_path) {
 
249
                unlink(l2->own_socket_path);
 
250
                os_free(l2->own_socket_path);
 
251
        }
 
252
                
 
253
        os_free(l2);
 
254
}
 
255
 
 
256
 
 
257
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
 
258
{
 
259
        /* TODO */
 
260
        return -1;
 
261
}
 
262
 
 
263
 
 
264
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
 
265
{
 
266
        wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
 
267
}