~ecryptfs/ecryptfs/trunk

« back to all changes in this revision

Viewing changes to src/utils/mount.ecryptfs.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
 * Copyright (C) 2006 International Business Machines
 
3
 * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
 
4
 *            Stephan Mueller <smueller@chronox.de>
 
5
 *            Tyler Hicks <tyhicks@ou.edu>
 
6
 *            Michael C. Thompson <mcthomps@us.ibm.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation; either version 2 of the
 
11
 * License, or (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
21
 * 02111-1307, USA.
 
22
 */
 
23
 
 
24
#include <errno.h>
 
25
#include <fcntl.h>
 
26
#include <gcrypt.h>
 
27
#include <getopt.h>
 
28
#include <keyutils.h>
 
29
#include <stdio.h>
 
30
#include <stdlib.h>
 
31
#include <string.h>
 
32
#include <pwd.h>
 
33
#include <sys/mman.h>
 
34
#include <sys/mount.h>
 
35
#include <sys/stat.h>
 
36
#include <sys/types.h>
 
37
#include "config.h"
 
38
#include "ecryptfs.h"
 
39
#include "decision_graph.h"
 
40
#include "io.h"
 
41
 
 
42
#define NUM_REQUIRED_ARGS 3
 
43
 
 
44
static void usage()
 
45
{
 
46
        fprintf(stderr, "\teCryptfs mount helper\n\tusage: "
 
47
                "mount -t ecryptfs [lower directory] [ecryptfs mount point]\n"
 
48
                "Available options:\n"
 
49
                "\tkey=<pki alias>\n"
 
50
                "\n\t\tAvailable pki aliases: passphrase\n"
 
51
                "\tpassthrough\n"
 
52
                "\tplaintext_passthrough\n"
 
53
                );
 
54
        exit(-EINVAL);
 
55
}
 
56
 
 
57
/**
 
58
 * This function will malloc any argument that is passed in as non-NULL.
 
59
 * In the event of a failure, all returned pointers are invalid and no
 
60
 * memory is left allocated.
 
61
 *
 
62
 * returns 0 on success
 
63
 */
 
64
static int parse_arguments(int argc, char **argv, char **src, char **target,
 
65
                           char **options)
 
66
{
 
67
        int rc = 0;
 
68
        char *ptr;
 
69
        size_t len;
 
70
 
 
71
        if (src)
 
72
                *src = NULL;
 
73
        if (target)
 
74
                *target = NULL;
 
75
        if (options)
 
76
                *options = NULL;
 
77
 
 
78
        if (src) {
 
79
                ptr = argv[1];
 
80
                len = strlen(ptr) + 1; /* + NULL terminator */
 
81
                *src = malloc(len);
 
82
                if (!*src) {
 
83
                        fprintf(stderr, "Unable to allocate source buffer\n");
 
84
                        rc = -ENOMEM;
 
85
                        goto out;
 
86
                }
 
87
                memcpy(*src, ptr, len);
 
88
                if ((*src)[len - 1] == '/')
 
89
                        (*src)[len - 1] = '\0';
 
90
        }
 
91
        if (target) {
 
92
                ptr = argv[2];
 
93
                len = strlen(ptr) + 1; /* + NULL-terminator */
 
94
                *target = malloc(len);
 
95
                if (!*target) {
 
96
                        fprintf(stderr, "Unable to allocate target buffer\n");
 
97
                        rc = -ENOMEM;
 
98
                        goto out;
 
99
                }
 
100
                memcpy(*target, ptr, len);
 
101
                if ((*target)[len - 1] == '/')
 
102
                        (*target)[len - 1] = '\0';
 
103
        }
 
104
        if (options && (argc == NUM_REQUIRED_ARGS)) {
 
105
                fprintf(stderr, "Not enough remaining data for options\n");
 
106
                return -EINVAL;
 
107
        } else if ((options) && (argc > NUM_REQUIRED_ARGS)) {
 
108
                int i;
 
109
 
 
110
                ptr = NULL;
 
111
                for (i = 3; i < (argc-1); i++)
 
112
                        if (!strcmp("-o", argv[i])) {
 
113
                                ptr = argv[i+1];
 
114
                                break;
 
115
                        }
 
116
                if (!ptr) {
 
117
                        fprintf(stderr, "Unable to find a list of options to "
 
118
                                        "parse, defaulting to interactive "
 
119
                                        "mount\n");
 
120
                        rc = -ENOENT;
 
121
                        goto out;
 
122
                }
 
123
                len = strlen(ptr) + 1; /* + NULL-terminator */
 
124
                *options = malloc(len);
 
125
                if (!*options){
 
126
                        fprintf(stderr, "Unable to allocate memory for options "
 
127
                                        "buffer\n");
 
128
                        rc = -ENOMEM;
 
129
                        goto out;
 
130
                }
 
131
                memcpy(*options, ptr, len);
 
132
        }
 
133
        return 0;
 
134
out:
 
135
        if (src && *src)
 
136
                free(*src);
 
137
        if (target && *target)
 
138
                free(*target);
 
139
        if (options && *options)
 
140
                free(*options);
 
141
        return rc;
 
142
}
 
143
 
 
144
static int ecryptfs_generate_mount_flags(char *options, int *flags)
 
145
{
 
146
        char *opt;
 
147
        char *next_opt;
 
148
        char *end;
 
149
        int num_options = 0;
 
150
 
 
151
        end = strchr(options, '\0');
 
152
        opt = options;
 
153
        while (opt) {
 
154
                if ((next_opt = strchr(opt, ',')))
 
155
                        next_opt++;
 
156
                /* the following mount options should be
 
157
                 * stripped out from what is passed into the
 
158
                 * kernel since these eight options are best
 
159
                 * passed as the mount flags rather than
 
160
                 * redundantly to the kernel and could
 
161
                 * generate spurious warnings depending on the
 
162
                 * level of the corresponding cifs vfs kernel
 
163
                 * code */
 
164
                if (!strncmp(opt, "nosuid", 6))
 
165
                        *flags |= MS_NOSUID;
 
166
                else if (!strncmp(opt, "suid", 4))
 
167
                        *flags &= ~MS_NOSUID;
 
168
                else if (!strncmp(opt, "nodev", 5))
 
169
                        *flags |= MS_NODEV;
 
170
                else if (!strncmp(opt, "dev", 3))
 
171
                        *flags &= ~MS_NODEV;
 
172
                else if (!strncmp(opt, "noexec", 6))
 
173
                        *flags |= MS_NOEXEC;
 
174
                else if (!strncmp(opt, "exec", 4))
 
175
                        *flags &= ~MS_NOEXEC;
 
176
                else if (!strncmp(opt, "ro", 2))
 
177
                        *flags |= MS_RDONLY;
 
178
                else if (!strncmp(opt, "rw", 2))
 
179
                        *flags &= ~MS_RDONLY;
 
180
                else if (!strncmp(opt, "remount", 7))
 
181
                        *flags |= MS_REMOUNT;
 
182
                else {
 
183
                        opt = next_opt;
 
184
                        num_options++;
 
185
                        continue;
 
186
                }
 
187
                if (!next_opt) {
 
188
                        if (opt != options)
 
189
                                end = --opt;
 
190
                        else
 
191
                                end = options;
 
192
                        *end = '\0';
 
193
                        break;
 
194
                }
 
195
                memcpy(opt, next_opt, end - next_opt);
 
196
                end = end - (next_opt - opt);
 
197
                *end = '\0';
 
198
        }
 
199
        return num_options;
 
200
}
 
201
 
 
202
char *parameters_to_scrub[] = {
 
203
        "key=",
 
204
        "cipher=",
 
205
        "passthrough",
 
206
        "xattr",
 
207
        "encrypted_view",
 
208
        "user",
 
209
        "sig",
 
210
        "no_sig_cache",
 
211
        "verbose",
 
212
        NULL
 
213
};
 
214
 
 
215
char *parameters_to_not_scrub[] = {
 
216
        "xattr_user",
 
217
        NULL
 
218
};
 
219
 
 
220
static int parameter_should_not_be_scrubbed(char *str) {
 
221
        int i;
 
222
 
 
223
        for (i = 0; parameters_to_not_scrub[i]; i++)
 
224
                if (strstr(str, parameters_to_not_scrub[i]) == str)
 
225
                        return 1;
 
226
        return 0;
 
227
}
 
228
 
 
229
static int parameter_should_be_scrubbed(char *str)
 
230
{
 
231
        int i;
 
232
 
 
233
        for (i = 0; parameters_to_scrub[i]; i++)
 
234
                if (strstr(str, parameters_to_scrub[i]) == str
 
235
                    && !parameter_should_not_be_scrubbed(str))
 
236
                        return 1;
 
237
        return 0;
 
238
}
 
239
 
 
240
/**
 
241
 * Remove from the options string known options which should not be passed
 
242
 * into the kernel. Any options that are unknown will be passed in.
 
243
 * This is to account for options like "rw".
 
244
 *
 
245
 * Returns zero on success, non-zero otherwise
 
246
 */
 
247
static int strip_userland_opts(char *options)
 
248
{
 
249
        char *cur = NULL, *next = NULL;
 
250
        char *temp, *temp_end;
 
251
        size_t len;
 
252
        int used = 0, first = 1;
 
253
 
 
254
        len = (strlen(options) + 1);
 
255
        if ((temp = (char*)malloc(len)) == NULL) {
 
256
                fprintf(stderr, "Out of memory\n");
 
257
                return -1;
 
258
        }
 
259
        temp_end = temp;
 
260
        memset(temp, 0, len);
 
261
        cur = options;
 
262
        while (cur) {
 
263
                int opt_len;
 
264
 
 
265
                next = strstr(cur, ",");
 
266
                if (next) {
 
267
                        *next='\0';
 
268
                        next++;
 
269
                }
 
270
                if (!parameter_should_be_scrubbed(cur)) {
 
271
                        if (!first) {
 
272
                                memcpy(temp_end, ",", 1);
 
273
                                temp_end++;
 
274
                        }
 
275
                        opt_len = strlen(cur);
 
276
                        memcpy(temp_end, cur, opt_len);
 
277
                        temp_end = temp_end + opt_len;
 
278
                        used += opt_len;
 
279
                        first = 0;
 
280
                }
 
281
                cur = next;
 
282
        }
 
283
        memcpy(options,temp,len);
 
284
        free(temp);
 
285
        return 0;
 
286
}
 
287
 
 
288
static int process_sig(char *auth_tok_sig)
 
289
{
 
290
        char *home;
 
291
        struct passwd *pw;
 
292
        uid_t id;
 
293
        char *sig_cache_filename = NULL;
 
294
        char *dot_ecryptfs_dir;
 
295
        int flags;
 
296
        char yesno[4];
 
297
        int i;
 
298
        int rc;
 
299
 
 
300
        id = getuid();
 
301
        pw = getpwuid(id);
 
302
        if (!pw) {
 
303
                rc = -EIO;
 
304
                goto out;
 
305
        }
 
306
        home = pw->pw_dir;
 
307
        rc = asprintf(&dot_ecryptfs_dir, "%s/.ecryptfs", home);
 
308
        if (rc == -1) {
 
309
                rc = -ENOMEM;
 
310
                goto out;
 
311
        }
 
312
        mkdir(dot_ecryptfs_dir, S_IRWXU);
 
313
        free(dot_ecryptfs_dir);
 
314
        rc = asprintf(&sig_cache_filename, "%s/.ecryptfs/sig-cache.txt",
 
315
                      home);
 
316
        if (rc == -1) {
 
317
                rc = -ENOMEM;
 
318
                goto out;
 
319
        }
 
320
        flags = 0;
 
321
        if ((rc = ecryptfs_check_sig(auth_tok_sig, sig_cache_filename,
 
322
                                     &flags)))
 
323
                goto out;
 
324
        if (flags & ECRYPTFS_SIG_FLAG_NOENT) {
 
325
                printf("WARNING: Based on the contents of [%s],\n"
 
326
                       "it looks like you have never mounted with this key \n"
 
327
                       "before. This could mean that you have typed your \n"
 
328
                       "passphrase wrong.\n\n", sig_cache_filename);
 
329
                printf("Would you like to proceed with the mount (yes/no)? ");
 
330
                i = 0;
 
331
                do {
 
332
                        yesno[i++] = mygetchar();
 
333
                } while (yesno[i-1] != '\n' && i < 3);
 
334
                yesno[i] = '\0';
 
335
                if (yesno[i-1] != '\n')
 
336
                        while (mygetchar() != '\n');
 
337
                if (memcmp(yesno, "yes", 3) == 0) {
 
338
                        printf("Would you like to append sig [%s] to\n"
 
339
                               "[%s] \n"
 
340
                               "in order to avoid this warning in the future "
 
341
                               "(yes/no)? ", auth_tok_sig, sig_cache_filename);
 
342
                        i = 0;
 
343
                        do {
 
344
                                yesno[i++] = mygetchar();
 
345
                        } while (yesno[i-1] != '\n' && i < 3);
 
346
                        yesno[i] = '\0';
 
347
                        if (yesno[i-1] != '\n')
 
348
                                while (mygetchar() != '\n');
 
349
                        if (memcmp(yesno, "yes", 3) == 0) {
 
350
                                if ((rc = ecryptfs_append_sig(
 
351
                                             auth_tok_sig,
 
352
                                             sig_cache_filename))) {
 
353
                                        printf("Error appending to [%s]; rc = "
 
354
                                               "[%d]. Aborting mount.\n",
 
355
                                               sig_cache_filename, rc);
 
356
                                        goto out;
 
357
                                }
 
358
                                printf("Successfully appended new sig to user "
 
359
                                       "sig cache file\n");
 
360
                        } else
 
361
                                printf("Not adding sig to user sig cache "
 
362
                                       "file; continuing with mount.\n");
 
363
                } else {
 
364
                        printf("Aborting mount.\n");
 
365
                        rc = -EINVAL;
 
366
                        goto out;
 
367
                }
 
368
        }
 
369
out:
 
370
        free(sig_cache_filename);
 
371
        return rc;
 
372
}
 
373
 
 
374
static int opts_str_contains_option(char *options, char *option)
 
375
{
 
376
        char *opt;
 
377
        char *next_opt;
 
378
        char *end;
 
379
        int option_len = strlen(option);
 
380
 
 
381
        end = strchr(options, '\0');
 
382
        opt = options;
 
383
        while (opt) {
 
384
                if ((next_opt = strchr(opt, ',')))
 
385
                        next_opt++;
 
386
                if (!strncmp(opt, option, option_len))
 
387
                        return 1;
 
388
                else {
 
389
                        opt = next_opt;
 
390
                        continue;
 
391
                }
 
392
                if (!next_opt) {
 
393
                        if (opt != options)
 
394
                                end = --opt;
 
395
                        else
 
396
                                end = options;
 
397
                        *end = '\0';
 
398
                        break;
 
399
                }
 
400
                memcpy(opt, next_opt, end - next_opt);
 
401
                end = end - (next_opt - opt);
 
402
                *end = '\0';
 
403
        }
 
404
        return 0;
 
405
}
 
406
 
 
407
char *required_mount_opts[] = {
 
408
        "ecryptfs_key_bytes=",
 
409
        NULL
 
410
};
 
411
 
 
412
static int ecryptfs_validate_mount_opts(char *opts)
 
413
{
 
414
        int i = 0;
 
415
        int rc = 0;
 
416
 
 
417
        while (required_mount_opts[i]) {
 
418
                if (!opts_str_contains_option(opts, required_mount_opts[i])) {
 
419
                        printf("Required mount option not provided: [%s]\n",
 
420
                               required_mount_opts[i]);
 
421
                        rc = 1;
 
422
                        goto out;
 
423
                }
 
424
                i++;
 
425
        }
 
426
out:
 
427
        return rc;
 
428
}
 
429
 
 
430
/**
 
431
 * ecryptfs_do_mount
 
432
 * @params:
 
433
 *
 
434
 * The mount options actually sent to the kernel are in the @params
 
435
 * linked list of struct val_node objects. params <-
 
436
 * ecryptfs_process_decision_graph(head) -> decision_graph_mount(head)
 
437
 * -> eval_param_tree(val_stack_head) -> do_transition(val_stack_head)
 
438
 * -> trans_func(head). 
 
439
 */
 
440
static int ecryptfs_do_mount(int argc, char **argv, struct val_node *mnt_params,
 
441
                             int sig_cache)
 
442
{
 
443
        int rc;
 
444
        int flags = 0;
 
445
        int num_opts = 0;
 
446
        char *src = NULL, *targ = NULL, *opts = NULL, *new_opts = NULL, *temp;
 
447
        char *val;
 
448
 
 
449
        if ((rc = parse_arguments(argc, argv, &src, &targ, &opts))) {
 
450
                fprintf(stderr, "Unable to understand the mount options\n");
 
451
                goto out;
 
452
        }
 
453
        rc = strip_userland_opts(opts);
 
454
        if (rc)
 
455
                goto out;
 
456
        num_opts = ecryptfs_generate_mount_flags(opts, &flags);
 
457
        asprintf(&new_opts, "%s", opts);
 
458
        printf("Attempting to mount with the following options:\n");
 
459
        while (!stack_pop_val(&mnt_params, (void *)&val)) {
 
460
                if(!val)
 
461
                        break;
 
462
                temp = new_opts;
 
463
                printf("  %s\n", val);
 
464
                if (sig_cache && memcmp(val, "ecryptfs_sig=", 13) == 0) {
 
465
                        if ((rc = process_sig(&val[13]))) {
 
466
                                printf("Error processing sig; rc = [%d]\n", rc);
 
467
                                goto out;
 
468
                        }
 
469
                }
 
470
                rc = asprintf(&new_opts, "%s,%s", val, temp);
 
471
                if (rc == -1) {
 
472
                        new_opts = NULL;
 
473
                        rc = -ENOMEM;
 
474
                        goto out;
 
475
                }
 
476
                rc = 0;
 
477
                free(temp);
 
478
        }
 
479
        if ((rc = ecryptfs_validate_mount_opts(new_opts)) != 0) {
 
480
                printf("Invalid mount options; aborting. rc = [%d]\n",
 
481
                       rc);
 
482
                goto out;
 
483
        }
 
484
        rc = ecryptfs_mount(src, targ, flags, new_opts);
 
485
out:
 
486
        free(src);
 
487
        free(targ);
 
488
        free(opts);
 
489
        free(new_opts);
 
490
        return rc;
 
491
}
 
492
 
 
493
static int dump_args = 0;
 
494
 
 
495
int main(int argc, char **argv)
 
496
{
 
497
        uint32_t version;
 
498
        char *opts_str;
 
499
        struct val_node *mnt_params;
 
500
        struct ecryptfs_ctx ctx;
 
501
        int sig_cache = 1;
 
502
        int rc;
 
503
 
 
504
        rc = mlockall(MCL_FUTURE);
 
505
        if (rc) {
 
506
                fprintf(stderr, "Exiting. Unable to mlockall address space\n");
 
507
                return 0;
 
508
        }
 
509
        if (dump_args) {
 
510
                int i;
 
511
 
 
512
                for (i = 0; i < argc; i++)
 
513
                        printf("argv[%d] = [%s]\n", i, argv[i]);
 
514
        }
 
515
        if (argc < NUM_REQUIRED_ARGS) {
 
516
                fprintf(stderr, "Insufficient number of arguments\n");
 
517
                usage();
 
518
                rc = -EINVAL;
 
519
                goto out;
 
520
        }
 
521
        rc = ecryptfs_get_version(&version);
 
522
        if (rc) {
 
523
                printf("\nUnable to get the version number of the kernel\n");
 
524
                printf("module. Please make sure that you have the eCryptfs\n");
 
525
                printf("kernel module loaded, you have sysfs mounted, and\n");
 
526
                printf("the sysfs mount point is in /etc/mtab. This is\n");
 
527
                printf("necessary so that the mount helper knows which \n");
 
528
                printf("kernel options are supported.\n\n");
 
529
                printf("Make sure that your system is set up to auto-load\n"
 
530
                       "your filesystem kernel module on mount.\n\n");
 
531
                printf("Enabling passphrase-mode only for now.\n\n");
 
532
                version = ECRYPTFS_VERSIONING_PASSPHRASE;
 
533
        }
 
534
        if ((rc = ecryptfs_validate_keyring())) {
 
535
                printf("Unable to link the KEY_SPEC_USER_KEYRING into the "
 
536
                       "KEY_SPEC_SESSION_KEYRING; there is something wrong "
 
537
                       "with your kernel keyring. Did you build key retention "
 
538
                       "support into your kernel?\n");
 
539
                goto out;
 
540
        }
 
541
        mnt_params = malloc(sizeof(struct val_node));
 
542
        memset(mnt_params, 0, sizeof(struct val_node));
 
543
        memset(&ctx, 0, sizeof(struct ecryptfs_ctx));
 
544
        ctx.get_string = &get_string_stdin;
 
545
        if ((rc = parse_arguments(argc, argv, NULL, NULL, &opts_str)))
 
546
                goto out;
 
547
        if (opts_str_contains_option(opts_str, "verbose"))
 
548
                ecryptfs_verbosity = 1;
 
549
        if (!opts_str_contains_option(opts_str, "remount")) {
 
550
                if (opts_str_contains_option(opts_str, "no_sig_cache"))
 
551
                        sig_cache = 0;
 
552
                rc = ecryptfs_process_decision_graph(
 
553
                        &ctx, &mnt_params, version, opts_str,
 
554
                        ECRYPTFS_ASK_FOR_ALL_MOUNT_OPTIONS);
 
555
                if (rc) {
 
556
                        printf("Error attempting to evaluate mount options; "
 
557
                               "rc = [%d]. Try updating/reinstalling your "
 
558
                               "ecryptfs-utils package, or submit a bug "
 
559
                               "report.\n", rc);
 
560
                        goto out;
 
561
                }
 
562
                rc = ecryptfs_do_mount(argc, argv, mnt_params, sig_cache);
 
563
                if (rc) {
 
564
                        if (rc > 0)
 
565
                                rc = -rc;
 
566
                        printf("Error mounting eCryptfs; rc = [%d]; strerr = "
 
567
                               "[%s]. Check your system logs; visit "
 
568
                               "<http://ecryptfs.sourceforge.net/"
 
569
                               "ecryptfs-faq.html>.\n", rc, strerror(-rc));
 
570
                        if (rc == -ENODEV)
 
571
                                printf("Try ``modprobe ecryptfs''\n");
 
572
                } else
 
573
                        printf("Mounted eCryptfs\n");
 
574
        } else {
 
575
                fprintf(stderr, "When are remounting eCryptfs, you need "
 
576
                        "to pass the mount utility the -i parameter to avoid "
 
577
                        "calling the mount helper\n");
 
578
                rc = -EINVAL;
 
579
        }
 
580
 
 
581
out:
 
582
        munlockall();
 
583
        return rc;
 
584
}