~ecryptfs/ecryptfs/trunk

« back to all changes in this revision

Viewing changes to src/daemon/main.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 daemon which responds to the eCryptfs kernel module's requests
 
3
 *
 
4
 * Copyright (C) 2004-2006 International Business Machines Corp.
 
5
 *   Author(s): Tyler Hicks <tyhicks@ou.edu>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License as
 
9
 * published by the Free Software Foundation; either version 2 of the
 
10
 * License, or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
20
 * 02111-1307, USA.
 
21
 */
 
22
 
 
23
#include <errno.h>
 
24
#include <signal.h>
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <syslog.h>
 
28
#include <string.h>
 
29
#include <unistd.h>
 
30
#include <fcntl.h>
 
31
#include <getopt.h>
 
32
#include <sys/resource.h>
 
33
#include "config.h"
 
34
#include "../include/ecryptfs.h"
 
35
 
 
36
static int ecryptfs_socket = 0;
 
37
static char *pidfile = NULL;
 
38
static char *prompt_prog = NULL;
 
39
 
 
40
static
 
41
int
 
42
prompt_callback(char *prompt_type, char *prompt, char *input, int input_size) {
 
43
        int status;
 
44
        pid_t pid = -1;
 
45
        int fds[2] = {-1, -1};
 
46
        int r = 0;
 
47
        int rc;
 
48
 
 
49
        /*
 
50
         * Make sure we don't reuse input
 
51
         */
 
52
        if (input) {
 
53
                memset (input, 0, input_size);
 
54
        }
 
55
 
 
56
        if (prompt_prog == NULL) {
 
57
                rc = -EINVAL;
 
58
                goto out;
 
59
        }
 
60
 
 
61
        if (pipe (fds) == -1) {
 
62
                rc = -errno;
 
63
                goto out;
 
64
        }
 
65
 
 
66
        if ((pid = fork ()) == -1) {
 
67
                rc = -errno;
 
68
                goto out;
 
69
        }
 
70
 
 
71
        if (pid == 0) {
 
72
                close (fds[0]);
 
73
                fds[0] = -1;
 
74
 
 
75
                if (dup2 (fds[1], 1) == -1) {
 
76
                        exit (1);
 
77
                }
 
78
 
 
79
                close (fds[1]);
 
80
                fds[1] = -1;
 
81
 
 
82
                execl (
 
83
                        prompt_prog,
 
84
                        prompt_prog,
 
85
                        "-t",
 
86
                        prompt_type,
 
87
                        prompt,
 
88
                        NULL
 
89
                );
 
90
 
 
91
                exit (1);
 
92
        }
 
93
 
 
94
        close (fds[1]);
 
95
        fds[1] = -1;
 
96
 
 
97
        while (
 
98
                (r=waitpid (pid, &status, __WNOTHREAD)) == 0 ||
 
99
                (r == -1 && errno == EINTR)
 
100
        );
 
101
 
 
102
        if (r == -1) {
 
103
                rc = -errno;
 
104
                goto out;
 
105
        }
 
106
 
 
107
        if (!WIFEXITED (status)) {
 
108
                rc = -EFAULT;
 
109
                goto out;
 
110
        }
 
111
 
 
112
        if (WEXITSTATUS (status) != 0) {
 
113
                rc = -EIO;
 
114
                goto out;
 
115
        }
 
116
        
 
117
        if (!strcmp (prompt_type, "password")) {
 
118
                if ((r = read (fds[0], input, input_size)) == -1) {
 
119
                        rc = -errno;
 
120
                        goto out;
 
121
                }
 
122
        
 
123
                input[r] = '\0';
 
124
 
 
125
                if (strlen (input) > 0 && input[strlen (input)-1] == '\n') {
 
126
                        input[strlen (input)-1] = '\0';
 
127
                }
 
128
        }
 
129
 
 
130
        rc = 0;
 
131
 
 
132
out:
 
133
        if (rc != 0) {
 
134
                if (input) {
 
135
                        memset (input, 0, input_size);
 
136
                }
 
137
        }
 
138
 
 
139
        if (fds[0] != -1) {
 
140
                close (fds[0]);
 
141
                fds[0] = -1;
 
142
        }
 
143
 
 
144
        if (fds[1] != -1) {
 
145
                close (fds[1]);
 
146
                fds[1] = -1;
 
147
        }
 
148
 
 
149
        return rc;
 
150
}
 
151
 
 
152
 
 
153
static void ecryptfsd_exit(int retval)
 
154
{
 
155
        if (pidfile != NULL) {
 
156
                unlink(pidfile);
 
157
                free(pidfile);
 
158
                pidfile = NULL;
 
159
        }
 
160
        if (!ecryptfs_socket)
 
161
                goto out;
 
162
        if (ecryptfs_send_netlink(ecryptfs_socket, NULL,
 
163
                                  ECRYPTFS_NLMSG_QUIT, 0, 0) < 0) {
 
164
                ecryptfs_syslog(LOG_ERR, "Failed to unregister netlink "
 
165
                                "daemon with the eCryptfs kernel module\n");
 
166
        }
 
167
        ecryptfs_release_netlink(ecryptfs_socket);
 
168
out:
 
169
        ecryptfs_syslog(LOG_INFO, "Closing eCryptfs userspace netlink "
 
170
                        "daemon [%u]\n", getpid());
 
171
        exit(retval);
 
172
}
 
173
 
 
174
void daemonize(void)
 
175
{
 
176
        pid_t pid;
 
177
        int fd;
 
178
        int null;
 
179
 
 
180
        if(getppid() == 1)
 
181
                return; /* Already a daemon */
 
182
        if ((pid=fork()) == -1) {
 
183
                fprintf(stderr, "Failed to create daemon process: %s\n",
 
184
                        strerror(errno));
 
185
                exit(1);
 
186
        }
 
187
        if (pid != 0)
 
188
                exit(0);
 
189
        setsid();
 
190
        umask(027);
 
191
        chdir("/");
 
192
        if ((pid=fork()) == -1) { /* Fork in new session */
 
193
                syslog(LOG_ERR, "Failed to create daemon process: %s",
 
194
                       strerror(errno));
 
195
                exit(1);
 
196
        }
 
197
        if (pid != 0)
 
198
                exit(0);
 
199
        /* Make std handles write to null; close all others. */
 
200
        if ((null = open("/dev/null", O_RDWR)) == -1) {
 
201
                syslog(LOG_ERR, "Cannot open /dev/null");
 
202
                exit(1);
 
203
        }
 
204
        for (fd=0; fd < 3; fd++) {
 
205
                if (dup2(null, 0) == -1) {
 
206
                        syslog(LOG_ERR, "Failed to dup null: %s",
 
207
                               strerror(errno));
 
208
                        exit(1);
 
209
                }
 
210
        }
 
211
        for (fd = (getdtablesize() - 1); fd > 2; fd--)
 
212
                close(fd);
 
213
        /* Ignore major signals */
 
214
        if (signal(SIGHUP, SIG_IGN) == SIG_ERR
 
215
            || signal(SIGTERM, SIG_IGN) == SIG_ERR
 
216
            || signal(SIGINT, SIG_IGN) == SIG_ERR) {
 
217
                syslog(LOG_ERR, "Failed to setup initial signals");
 
218
                exit(1);
 
219
        }
 
220
}
 
221
 
 
222
void sigterm_handler(int sig)
 
223
{
 
224
        ecryptfsd_exit(0);
 
225
}
 
226
 
 
227
void usage(const char * const me, const struct option * const options,
 
228
           const char * const short_options)
 
229
{
 
230
        const struct option *opt;
 
231
 
 
232
        printf("Usage: %s [options]", me);
 
233
        for (opt = options; opt->name; opt++) {
 
234
                const char *descr = opt->name + strlen(opt->name) + 1;
 
235
 
 
236
                if (strchr(short_options, opt->val))
 
237
                        printf("\n  -%c, --%s", opt->val, opt->name);
 
238
                else
 
239
                        printf("\n  --%s", opt->name);
 
240
                if (opt->has_arg)
 
241
                        printf(" <%s>", opt->name);
 
242
                if (strlen(descr))
 
243
                        printf("\t%s",descr);
 
244
        }
 
245
        printf("\n");
 
246
}
 
247
 
 
248
int main(int argc, char **argv)
 
249
{
 
250
        static struct option long_options[] = {
 
251
                { "pidfile\0\tSet pid file name", required_argument, NULL, 'p' },
 
252
                { "foreground\0\t\tDon't fork into background", no_argument, NULL, 'f' },
 
253
                { "chroot\0\t\tChroot to directory", required_argument, NULL, 'C' },
 
254
                { "prompt-prog\0Program to execute for user prompt", required_argument, NULL, 'R' },
 
255
                { "version\0\t\t\tShow version information", no_argument, NULL, 'V' },
 
256
                { "help\0\t\t\tShow usage information", no_argument, NULL, 'h' },
 
257
                { NULL, 0, NULL, 0 }
 
258
        };
 
259
        static char *short_options = "p:f:C:R:Vh";
 
260
        int long_options_ret;
 
261
        struct rlimit core = { 0, 0 };
 
262
        int foreground = 0;
 
263
        char *chrootdir = NULL;
 
264
        char *tty = NULL;
 
265
        int rc = 0;
 
266
 
 
267
        while ((long_options_ret = getopt_long (argc, argv, short_options,
 
268
                                                long_options, NULL)) != -1) {
 
269
                switch (long_options_ret) {
 
270
                        case 'p':
 
271
                                pidfile = strdup(optarg);
 
272
                        break;
 
273
                        case 'f':
 
274
                                foreground = 1;
 
275
                        break;
 
276
                        case 'C':
 
277
                                chrootdir = strdup(optarg);
 
278
                        break;
 
279
                        case 'R':
 
280
                                prompt_prog = strdup(optarg);
 
281
                        break;
 
282
                        case 'V':
 
283
                                printf(("%s (%s) %s\n"
 
284
                                        "\n"
 
285
                                        "This is free software.  You may redistribute copies of it under the terms of\n"
 
286
                                        "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
 
287
                                        "There is NO WARRANTY, to the extent permitted by law.\n"
 
288
                                        ),
 
289
                                        basename(argv[0]),
 
290
                                        PACKAGE_NAME,
 
291
                                        PACKAGE_VERSION
 
292
                                );
 
293
                        break;
 
294
                        case 'h':
 
295
                        default:
 
296
                                usage(basename(argv[0]), long_options,
 
297
                                      short_options);
 
298
                                exit(1);
 
299
                        break;
 
300
                }
 
301
        }
 
302
        tty = ttyname(0); /* We may need the tty name later */
 
303
        if (tty != NULL)
 
304
                setenv ("TERM_DEVICE", tty, 0);
 
305
        if (!foreground)
 
306
                daemonize(); /* This will exit if cannot be completed */
 
307
        /* Disallow core file; secret values may be in it */
 
308
        if (setrlimit(RLIMIT_CORE, &core) == -1) {
 
309
                rc = -errno;
 
310
                syslog(LOG_ERR, "Cannot setrlimit: %s", strerror (errno));
 
311
                goto daemon_out;
 
312
        }
 
313
        if (chrootdir != NULL) {
 
314
                if (chroot(chrootdir) == -1) {
 
315
                        rc = -errno;
 
316
                        syslog(LOG_ERR, "Failed to chroot to '%s': %s",
 
317
                               chrootdir, strerror(errno));
 
318
                        goto daemon_out;
 
319
                }
 
320
                free(chrootdir);
 
321
                chrootdir = NULL;
 
322
        }
 
323
        if (pidfile != NULL) {
 
324
                FILE *fp = fopen(pidfile, "w");
 
325
 
 
326
                if (fp == NULL) {
 
327
                        rc = -errno;
 
328
                        syslog(LOG_ERR, "Failed to open pid file '%s': %s",
 
329
                               pidfile, strerror(errno));
 
330
                        goto daemon_out;
 
331
                }
 
332
                fprintf(fp, "%d", (int)getpid());
 
333
                fclose(fp);
 
334
        }
 
335
        if (signal(SIGTERM, sigterm_handler) == SIG_ERR) {
 
336
                rc = -ENOTSUP;
 
337
                syslog(LOG_ERR, "Failed to attach handler to SIGTERM");
 
338
                goto daemon_out;
 
339
        }
 
340
        if (signal(SIGINT, sigterm_handler) == SIG_ERR) {
 
341
                rc = -ENOTSUP;
 
342
                syslog(LOG_ERR, "Failed to attach handler to SIGINT");
 
343
                goto daemon_out;
 
344
        }
 
345
        /* TODO: eCryptfs context via daemon */
 
346
        cryptfs_get_ctx_opts()->prompt = prompt_callback;
 
347
        rc = init_netlink_daemon();
 
348
        if (rc) {
 
349
                syslog(LOG_ERR,
 
350
                       "Error initializing netlink daemon; rc = [%d]\n", rc);
 
351
                goto daemon_out;
 
352
        }
 
353
        rc = ecryptfs_init_netlink(&ecryptfs_socket);
 
354
        if (rc) {
 
355
                syslog(LOG_ERR, "Failed to run netlink daemon\n");
 
356
                goto daemon_out;
 
357
        }
 
358
        rc = ecryptfs_send_netlink(ecryptfs_socket, NULL,
 
359
                                   ECRYPTFS_NLMSG_HELO, 0, 0);
 
360
        if (rc < 0) {
 
361
                syslog(LOG_ERR, "Failed to register netlink daemon with the "
 
362
                       "eCryptfs kernel module\n");
 
363
                goto daemon_out;
 
364
        }
 
365
        rc = ecryptfs_run_netlink_daemon(ecryptfs_socket);
 
366
daemon_out:
 
367
        ecryptfsd_exit(rc);
 
368
        return rc;
 
369
}