~ecryptfs/ecryptfs/trunk

« back to all changes in this revision

Viewing changes to src/libecryptfs/netlink.c

  • Committer: mhalcrow@us.ibm.com
  • Date: 2007-11-06 22:56:01 UTC
  • Revision ID: git-v1:f8357de9d554b274497b5cce9db4347254b7e7eb
Initial import of eCryptfs filesystem userspace utilities (mount helper, daemon component,
etc.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Userspace side of netlink communications with eCryptfs kernel
 
3
 * module.
 
4
 *
 
5
 * Copyright (C) 2004-2007 International Business Machines Corp.
 
6
 *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
 
7
 *              Tyler Hicks <tyhicks@ou.edu>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public License as
 
11
 * published by the Free Software Foundation; either version 2 of the
 
12
 * License, or (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful, but
 
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
22
 * 02111-1307, USA.
 
23
 */
 
24
 
 
25
#include <errno.h>
 
26
#include <fcntl.h>
 
27
#include <signal.h>
 
28
#ifndef S_SPLINT_S
 
29
#include <stdio.h>
 
30
#include <syslog.h>
 
31
#endif
 
32
#include <stdlib.h>
 
33
#include <string.h>
 
34
#include <sys/socket.h>
 
35
#include "config.h"
 
36
#include "../include/ecryptfs.h"
 
37
 
 
38
int ecryptfs_send_netlink(int sk_fd, struct ecryptfs_netlink_message *emsg,
 
39
                          uint16_t msg_type, uint16_t msg_flags,
 
40
                          uint32_t msg_seq)
 
41
{
 
42
        struct nlmsghdr *nlh = NULL;
 
43
        struct sockaddr_nl dst_addr;
 
44
        int payload_len;
 
45
        int rc;
 
46
 
 
47
        payload_len = emsg ? sizeof(*emsg) + emsg->data_len : 0;
 
48
        nlh = malloc(NLMSG_SPACE(payload_len));
 
49
        if (!nlh) {
 
50
                ecryptfs_syslog(LOG_ERR, "Failed to allocate memory for "
 
51
                                "netlink header: %s\n", strerror(errno));
 
52
                rc = -ENOMEM;
 
53
                goto out;
 
54
        }
 
55
        memset(&dst_addr, 0, sizeof(dst_addr));
 
56
        dst_addr.nl_family = AF_NETLINK;
 
57
        dst_addr.nl_pid = 0;
 
58
        dst_addr.nl_groups = 0;
 
59
        nlh->nlmsg_len = NLMSG_LENGTH(payload_len);
 
60
        nlh->nlmsg_seq = msg_seq;
 
61
        nlh->nlmsg_pid = 0;
 
62
        nlh->nlmsg_type = msg_type;
 
63
        nlh->nlmsg_flags = msg_flags;
 
64
        if (payload_len)
 
65
                memcpy(NLMSG_DATA(nlh), emsg, payload_len);
 
66
        rc = sendto(sk_fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dst_addr,
 
67
                    sizeof(dst_addr));
 
68
        if (rc < 0) {
 
69
                rc = -errno;
 
70
                syslog(LOG_ERR, "Failed to send eCryptfs netlink "
 
71
                       "message: %s\n", strerror(errno));
 
72
                goto out;
 
73
        }
 
74
out:
 
75
        free(nlh);
 
76
        return rc;
 
77
}
 
78
 
 
79
int ecryptfs_recv_netlink(int sk_fd, struct ecryptfs_netlink_message **emsg,
 
80
                          int *msg_seq, int *msg_type)
 
81
{
 
82
        struct nlmsghdr *nlh = NULL;
 
83
        struct sockaddr_nl nladdr;
 
84
        socklen_t nladdr_len = sizeof(nladdr);
 
85
        int flags = MSG_PEEK;
 
86
        int buf_len = sizeof(*nlh);
 
87
        int pl_len;
 
88
        int rc;
 
89
 
 
90
receive:
 
91
        nlh = (struct nlmsghdr *)realloc(nlh, buf_len);
 
92
        if (!nlh) {
 
93
                rc = -errno;
 
94
                syslog(LOG_ERR, "Failed to allocate memory for "
 
95
                       "netlink message: %s\n", strerror(errno));
 
96
                goto out;
 
97
        }
 
98
        rc = recvfrom(sk_fd, nlh, buf_len, flags, (struct sockaddr*)&nladdr,
 
99
                      &nladdr_len);
 
100
        if (rc < 0) {
 
101
                rc = -errno;
 
102
                syslog(LOG_ERR, "Failed to receive netlink header; errno = "
 
103
                       "[%d]; errno msg = [%s]\n", errno, strerror(errno));
 
104
                goto free_out;
 
105
        }
 
106
        if (flags & MSG_PEEK) {
 
107
                buf_len = nlh->nlmsg_len;
 
108
                flags &= ~MSG_PEEK;
 
109
                goto receive;
 
110
        }
 
111
        if (nladdr_len != sizeof(nladdr)) {
 
112
                rc = -EPROTO;
 
113
                syslog(LOG_ERR, "Received invalid netlink message\n");
 
114
                goto free_out;
 
115
        }
 
116
        if (nladdr.nl_pid) {
 
117
                rc = -ENOMSG;
 
118
                syslog(LOG_WARNING, "Received netlink packet from a "
 
119
                                "userspace application; pid [%d] may be trying "
 
120
                                "to spoof eCryptfs netlink packets\n",
 
121
                                nladdr.nl_pid);
 
122
                goto out;
 
123
        }
 
124
        pl_len = NLMSG_PAYLOAD(nlh, 0);
 
125
        if (pl_len) {
 
126
                *emsg = malloc(pl_len);
 
127
                if (!*emsg) {
 
128
                        rc = -errno;
 
129
                        syslog(LOG_ERR, "Failed to allocate memory "
 
130
                                        "for eCryptfs netlink message: %s\n",
 
131
                                        strerror(errno));
 
132
                        goto free_out;
 
133
                }
 
134
                memcpy(*emsg, NLMSG_DATA(nlh), pl_len);
 
135
        }
 
136
        *msg_seq = nlh->nlmsg_seq;
 
137
        *msg_type = nlh->nlmsg_type;
 
138
free_out:
 
139
        free(nlh);
 
140
out:
 
141
        return rc;
 
142
}
 
143
 
 
144
int ecryptfs_init_netlink(int *sk_fd)
 
145
{
 
146
        struct sockaddr_nl src_addr;
 
147
        int rc;
 
148
 
 
149
        (*sk_fd) = socket(PF_NETLINK, SOCK_RAW, NETLINK_ECRYPTFS);
 
150
        if (!(*sk_fd)) {
 
151
                rc = -errno;
 
152
                syslog(LOG_ERR, "Failed to create the eCryptfs "
 
153
                       "netlink socket: %s\n", strerror(errno));
 
154
                goto out;
 
155
        }
 
156
        memset(&src_addr, 0, sizeof(src_addr));
 
157
        src_addr.nl_family = AF_NETLINK;
 
158
        src_addr.nl_pid = getpid();
 
159
        src_addr.nl_groups = 0;
 
160
        rc = bind(*sk_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
 
161
        if (rc) {
 
162
                rc = -errno;
 
163
                syslog(LOG_ERR, "Failed to bind the eCryptfs netlink "
 
164
                       "socket: %s\n", strerror(errno));
 
165
                goto out;
 
166
        }
 
167
        syslog(LOG_DEBUG, "eCryptfs netlink socket was successfully "
 
168
               "initialized\n");
 
169
out:
 
170
        return rc;
 
171
}
 
172
 
 
173
void ecryptfs_release_netlink(int sk_fd)
 
174
{
 
175
        close(sk_fd);
 
176
        syslog(LOG_DEBUG, "eCryptfs netlink socket was successfully "
 
177
               "released\n");
 
178
}
 
179
 
 
180
int init_netlink_daemon(void)
 
181
{
 
182
        int null_fd;
 
183
        int rc;
 
184
 
 
185
        syslog(LOG_INFO, "Starting eCryptfs userspace netlink daemon "
 
186
               "[%u]\n", getpid());
 
187
        rc = 0;
 
188
out:
 
189
        return rc;
 
190
}
 
191
 
 
192
int ecryptfs_run_netlink_daemon(int sk_fd)
 
193
{
 
194
        struct ecryptfs_netlink_message *emsg = NULL;
 
195
        struct ecryptfs_ctx ctx;
 
196
        int msg_seq, msg_type;
 
197
        int error_count = 0;
 
198
        int rc;
 
199
 
 
200
        memset(&ctx, 0, sizeof(struct ecryptfs_ctx));
 
201
 
 
202
        if ((rc = ecryptfs_register_key_modules(&ctx))) {
 
203
                syslog(LOG_ERR, "Failed to register key modules; rc = [%d]\n",
 
204
                       rc);
 
205
                goto out;
 
206
        }
 
207
receive:
 
208
        rc = ecryptfs_recv_netlink(sk_fd, &emsg, &msg_seq, &msg_type);
 
209
        if (rc < 0) {
 
210
                syslog(LOG_ERR, "Error while receiving eCryptfs netlink "
 
211
                       "message; errno = [%d]; errno msg = [%s]\n", errno,
 
212
                       strerror(errno));
 
213
                error_count++;
 
214
                if (error_count > ECRYPTFS_NETLINK_ERROR_COUNT_THRESHOLD) {
 
215
                        syslog(LOG_ERR, "Netlink error threshold exceeded "
 
216
                               "maximum of [%d]; terminating daemon\n",
 
217
                               ECRYPTFS_NETLINK_ERROR_COUNT_THRESHOLD);
 
218
                        rc = -EIO;
 
219
                        goto out;
 
220
                }
 
221
        } else if (msg_type == ECRYPTFS_NLMSG_HELO) {
 
222
                syslog(LOG_DEBUG, "Received eCryptfs netlink HELO "
 
223
                       "message from the kernel\n");
 
224
                error_count = 0;
 
225
        } else if (msg_type == ECRYPTFS_NLMSG_QUIT) {
 
226
                syslog(LOG_DEBUG, "Received eCryptfs netlink QUIT "
 
227
                       "message from the kernel\n");
 
228
                free(emsg);
 
229
                rc = 0;
 
230
                goto out;
 
231
        } else if (msg_type == ECRYPTFS_NLMSG_REQUEST) {
 
232
                struct ecryptfs_netlink_message *reply = NULL;
 
233
 
 
234
                rc = parse_packet(&ctx, emsg, &reply);
 
235
                if (rc) {
 
236
                        syslog(LOG_ERR, "Failed to process "
 
237
                               "netlink packet\n");
 
238
                        free(reply);
 
239
                        goto free_emsg;
 
240
                }
 
241
                reply->index = emsg->index;
 
242
                rc = ecryptfs_send_netlink(sk_fd, reply,
 
243
                                           ECRYPTFS_NLMSG_RESPONSE, 0,
 
244
                                           msg_seq);
 
245
                if (rc < 0) {
 
246
                        syslog(LOG_ERR, "Failed to send netlink "
 
247
                               "message in response to kernel "
 
248
                               "request\n");
 
249
                }
 
250
                free(reply);
 
251
                error_count = 0;
 
252
        } else
 
253
                syslog(LOG_DEBUG, "Received unrecognized netlink "
 
254
                       "message type [%d]\n", msg_type);
 
255
free_emsg:
 
256
        free(emsg);
 
257
        goto receive;
 
258
out:
 
259
        ecryptfs_free_key_mod_list(&ctx);
 
260
        return rc;
 
261
}