~mrooney/ecryptfs/nautilus-integration

« back to all changes in this revision

Viewing changes to src/libecryptfs/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
 * Copyright (C) 2006 International Business Machines Corp.
 
3
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
 
4
 *              Tyler Hicks <tyhicks@ou.edu>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License as
 
8
 * published by the Free Software Foundation; either version 2 of the
 
9
 * License, or (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful, but
 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
 * 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include <errno.h>
 
23
#include <gcrypt.h>
 
24
#include <mntent.h>
 
25
#ifndef S_SPLINT_S
 
26
#include <stdio.h>
 
27
#endif
 
28
#include <stdlib.h>
 
29
#include <string.h>
 
30
#include <unistd.h>
 
31
#include <signal.h>
 
32
#include <sys/mount.h>
 
33
#include <gcrypt.h>
 
34
#include <getopt.h>
 
35
#include <keyutils.h>
 
36
#include <sys/types.h>
 
37
#include <sys/ipc.h>
 
38
#include <sys/shm.h>
 
39
#include <sys/sem.h>
 
40
#include "config.h"
 
41
#include "../include/ecryptfs.h"
 
42
 
 
43
int ecryptfs_verbosity = 0;
 
44
 
 
45
void ecryptfs_get_versions(int *major, int *minor, int *file_version)
 
46
{
 
47
        *major = ECRYPTFS_VERSION_MAJOR;
 
48
        *minor = ECRYPTFS_VERSION_MINOR;
 
49
        if (file_version)
 
50
                *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION;
 
51
}
 
52
 
 
53
inline void to_hex(char *dst, char *src, int src_size)
 
54
{
 
55
        int x;
 
56
 
 
57
        for (x = 0; x < src_size; x++)
 
58
                sprintf(&dst[x*2], "%.2x", (unsigned char)src[x] );
 
59
        dst[src_size*2] = '\0';
 
60
}
 
61
 
 
62
void from_hex(char *dst, char *src, int dst_size)
 
63
{
 
64
        int x;
 
65
        char tmp[3] = { 0, };
 
66
 
 
67
        for (x = 0; x < dst_size; x++) {
 
68
                tmp[0] = src[x * 2];
 
69
                tmp[1] = src[x * 2 + 1];
 
70
                dst[x] = (char)strtol(tmp, NULL, 16);
 
71
        }
 
72
}
 
73
 
 
74
int do_hash(char *src, int src_size, char *dst, int algo)
 
75
{
 
76
        gcry_md_hd_t hd;
 
77
        gcry_error_t err = 0;
 
78
        unsigned char * hash;
 
79
        unsigned int mdlen;
 
80
 
 
81
        err = gcry_md_open(&hd, algo, 0);
 
82
        mdlen = gcry_md_get_algo_dlen(algo);
 
83
        if (err) {
 
84
                syslog(LOG_ERR, "Failed to open hash algo [%d]: "
 
85
                       "[%d]\n", algo, err);
 
86
                goto out;
 
87
        }
 
88
        gcry_md_write(hd, src, src_size);
 
89
        hash = gcry_md_read(hd, algo);
 
90
        memcpy(dst, hash, mdlen);
 
91
        gcry_md_close(hd);
 
92
 out:
 
93
        return (int) err;
 
94
}
 
95
 
 
96
/**
 
97
 * TODO: We need to support more hash algs
 
98
 *
 
99
 * @passphrase A NULL-terminated char array
 
100
 *
 
101
 * @salt A salt
 
102
 *
 
103
 * @passphrase_sig An allocated char array into which the generated
 
104
 * signature is written; PASSWORD_SIG_SIZE bytes should be allocated
 
105
 *
 
106
 */
 
107
int
 
108
generate_passphrase_sig(char *passphrase_sig, char *passphrase, char *salt,
 
109
                        char *session_key_encryption_key)
 
110
{
 
111
        char salt_and_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES
 
112
                                          + ECRYPTFS_SALT_SIZE];
 
113
        int passphrase_size;
 
114
        int alg = GCRY_MD_SHA512;
 
115
        int dig_len = SHA512_DIGEST_LENGTH;
 
116
        char buf[SHA512_DIGEST_LENGTH];
 
117
        int hash_iterations = ECRYPTFS_DEFAULT_NUM_HASH_ITERATIONS;
 
118
        int rc = 0;
 
119
 
 
120
        passphrase_size = strlen(passphrase);
 
121
        if (passphrase_size > ECRYPTFS_MAX_PASSPHRASE_BYTES) {
 
122
                passphrase_sig = NULL;
 
123
                syslog(LOG_ERR, "Passphrase too large (%d bytes)\n",
 
124
                       passphrase_size);
 
125
                return -EINVAL;
 
126
        }
 
127
        memcpy(salt_and_passphrase, salt, ECRYPTFS_SALT_SIZE);
 
128
        memcpy((salt_and_passphrase + ECRYPTFS_SALT_SIZE), passphrase,
 
129
                passphrase_size);
 
130
        if ((rc = do_hash(salt_and_passphrase,
 
131
                          (ECRYPTFS_SALT_SIZE + passphrase_size), buf, alg))) {
 
132
                return rc;
 
133
        }
 
134
        hash_iterations--;
 
135
        while (hash_iterations--) {
 
136
                if ((rc = do_hash(buf, dig_len, buf, alg))) {
 
137
                        return rc;
 
138
                }
 
139
        }
 
140
        memcpy(session_key_encryption_key, buf, ECRYPTFS_MAX_KEY_BYTES);
 
141
        if ((rc = do_hash(buf, dig_len, buf, alg))) {
 
142
                return rc;
 
143
        }
 
144
        to_hex(passphrase_sig, buf, ECRYPTFS_SIG_SIZE);
 
145
        return 0;
 
146
}
 
147
 
 
148
/**
 
149
 * @return Zero on success
 
150
 */
 
151
int
 
152
generate_payload(struct ecryptfs_auth_tok *auth_tok, char *passphrase_sig,
 
153
                 char *salt, char *session_key_encryption_key)
 
154
{
 
155
        int rc = 0;
 
156
        int major, minor;
 
157
 
 
158
        memset(auth_tok, 0, sizeof(struct ecryptfs_auth_tok));
 
159
        ecryptfs_get_versions(&major, &minor, NULL);
 
160
        auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
 
161
                             | ((uint16_t)minor & 0x00FF));
 
162
        auth_tok->token_type = ECRYPTFS_PASSWORD;
 
163
        strncpy(auth_tok->token.password.signature, passphrase_sig,
 
164
                ECRYPTFS_PASSWORD_SIG_SIZE);
 
165
        memcpy(auth_tok->token.password.salt, salt, ECRYPTFS_SALT_SIZE);
 
166
        memcpy(auth_tok->token.password.session_key_encryption_key,
 
167
               session_key_encryption_key, ECRYPTFS_MAX_KEY_BYTES);
 
168
        /* TODO: Make the hash parameterizable via policy */
 
169
        auth_tok->token.password.session_key_encryption_key_bytes =
 
170
                ECRYPTFS_MAX_KEY_BYTES;
 
171
        auth_tok->token.password.flags |=
 
172
                ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
 
173
        /* The kernel code will encrypt the session key. */
 
174
        auth_tok->session_key.encrypted_key[0] = 0;
 
175
        auth_tok->session_key.encrypted_key_size = 0;
 
176
        /* Default; subject to change by kernel eCryptfs */
 
177
        auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512;
 
178
        auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD);
 
179
        return rc;
 
180
}
 
181
 
 
182
/**
 
183
 * @auth_tok: A previous call to get_blob() by the callee determined
 
184
 *            how much space to allocate at the end of the auth_tok
 
185
 *            memory for the blob; this memory is already allocated
 
186
 *            and ready to be written into
 
187
 */
 
188
int
 
189
ecryptfs_generate_key_payload(struct ecryptfs_auth_tok *auth_tok,
 
190
                              struct ecryptfs_key_mod *key_mod,
 
191
                              char *sig, size_t blob_size)
 
192
{
 
193
        int major, minor;
 
194
        unsigned char *key_data;
 
195
        size_t key_data_len;
 
196
        size_t blob_size_tmp;
 
197
        int rc = 0;
 
198
 
 
199
        memset(auth_tok, 0, sizeof(struct ecryptfs_auth_tok) + blob_size);
 
200
        ecryptfs_get_versions(&major, &minor, NULL);
 
201
        auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
 
202
                             | ((uint16_t)minor & 0x00FF));
 
203
        auth_tok->token_type = ECRYPTFS_PRIVATE_KEY;
 
204
        if (key_mod->blob == NULL) {
 
205
                if ((rc = (key_mod->ops->get_blob)
 
206
                     (auth_tok->token.private_key.data, &blob_size_tmp,
 
207
                      key_mod->param_vals, key_mod->num_param_vals))) {
 
208
                        syslog(LOG_ERR, "Call into key module's get_blob "
 
209
                               "failed; rc = [%d]\n", rc);
 
210
                        goto out;
 
211
                }
 
212
        } else {
 
213
                blob_size_tmp = key_mod->blob_size;
 
214
                memcpy(auth_tok->token.private_key.data, key_mod->blob,
 
215
                       key_mod->blob_size);
 
216
        }
 
217
        if (blob_size != blob_size_tmp) {
 
218
                rc = -EINVAL;
 
219
                syslog(LOG_ERR, "BUG: blob_size != blob_size_tmp; key module "
 
220
                       "is having a hard time getting the two to match between "
 
221
                       "get_blob() calls, and this has probably led to memory "
 
222
                       "corruption. Bombing out.\n");
 
223
                exit(1);
 
224
                goto out;
 
225
        }
 
226
        if ((rc = (key_mod->ops->get_key_data)
 
227
             (NULL, &key_data_len, auth_tok->token.private_key.data))) {
 
228
                syslog(LOG_ERR, "Call into key module's get_key_data failed; "
 
229
                       "rc = [%d]\n", rc);
 
230
                goto out;
 
231
        }
 
232
        if (key_data_len == 0) {
 
233
                if ((rc = (key_mod->ops->get_key_sig)(
 
234
                             sig,
 
235
                             auth_tok->token.private_key.data))) {
 
236
                        syslog(LOG_ERR, "Call into key module's get_key_sig "
 
237
                               "failed; rc = [%d]\n", rc);
 
238
                        goto out;
 
239
                }
 
240
        } else {
 
241
                if ((key_data = malloc(key_data_len)) == NULL) {
 
242
                        rc = -ENOMEM;
 
243
                        goto out;
 
244
                }
 
245
                if ((rc = (key_mod->ops->get_key_data)
 
246
                     (key_data, &key_data_len,
 
247
                      auth_tok->token.private_key.data))) {
 
248
                        syslog(LOG_ERR, "Call into key module's get_key_data "
 
249
                               "failed; rc = [%d]\n", rc);
 
250
                        goto out;
 
251
                }
 
252
                if ((rc = ecryptfs_generate_sig_from_key_data(
 
253
                             sig, key_data, key_data_len))) {
 
254
                        syslog(LOG_ERR, "Error attempting to generate "
 
255
                               "signature from key data; rc = [%d]\n", rc);
 
256
                        goto out;
 
257
                }
 
258
                if (sig[0] == '\0') {
 
259
                        if ((rc = (key_mod->ops->get_key_sig)(
 
260
                                     sig,
 
261
                                     auth_tok->token.private_key.data))) {
 
262
                                syslog(LOG_ERR, "Call into key module's "
 
263
                                       "get_key_sig failed; rc = [%d]\n", rc);
 
264
                                goto out;
 
265
                        }
 
266
                }
 
267
        }
 
268
        strncpy(auth_tok->token.private_key.key_mod_alias, key_mod->alias,
 
269
                ECRYPTFS_MAX_KEY_MOD_NAME_BYTES);
 
270
        /* TODO: Get rid of this */
 
271
        auth_tok->token.private_key.key_size = ECRYPTFS_MAX_KEY_MOD_NAME_BYTES;
 
272
        auth_tok->token.private_key.data_len = blob_size;
 
273
        memcpy(auth_tok->token.private_key.signature, sig,
 
274
               ECRYPTFS_SIG_SIZE_HEX);
 
275
        auth_tok->token.private_key.signature[ECRYPTFS_SIG_SIZE_HEX] = '\0';
 
276
out:
 
277
        return rc;
 
278
}
 
279
 
 
280
int ecryptfs_mount(char *source, char *target, unsigned long flags, char *opts)
 
281
{
 
282
        FILE *mtab_fd = NULL;
 
283
        struct mntent mountent;
 
284
        char cwd[MAX_PATH_SIZE];
 
285
        char *cwdptr;
 
286
        char *fullpath_source = NULL;
 
287
        char *fullpath_target = NULL;
 
288
        int i;
 
289
        int rc;
 
290
 
 
291
        mountent.mnt_opts = NULL;
 
292
        if (!source) {
 
293
                rc = -EINVAL;
 
294
                syslog(LOG_ERR, "Invalid source directory\n");
 
295
                goto out;
 
296
        }
 
297
        if (!target) {
 
298
                rc = -EINVAL;
 
299
                syslog(LOG_ERR, "Invalid target directory\n");
 
300
                goto out;
 
301
        }
 
302
        if (strlen(opts) > 200) {
 
303
                rc = -EINVAL;
 
304
                syslog(LOG_ERR, "Invalid mount options length\n");
 
305
                goto out;
 
306
        }
 
307
        if (mount(source, target, "ecryptfs", flags, opts)) {
 
308
                rc = -errno;
 
309
                syslog(LOG_ERR, "Failed to perform eCryptfs mount: "
 
310
                       "[%s]\n", strerror(errno));
 
311
                goto out;
 
312
        }
 
313
        mtab_fd = setmntent("/etc/mtab", "a");
 
314
        if (!mtab_fd) {
 
315
                rc = -EACCES;
 
316
                syslog(LOG_ERR, "Failed to update the mount table\n");
 
317
                goto out;
 
318
        }
 
319
        cwdptr = getcwd(cwd, MAX_PATH_SIZE);
 
320
        if (!cwdptr) {
 
321
                rc = -errno;
 
322
                syslog(LOG_ERR, "Failed to get the current working directory; "
 
323
                       "errno = [%d]\n", errno);
 
324
                goto out;
 
325
        }
 
326
        if (source[0] != '/') {
 
327
                rc = asprintf(&fullpath_source, "%s%s", cwd, source);
 
328
        } else
 
329
                rc = asprintf(&fullpath_source, "%s", source);
 
330
        if (rc == -1) {
 
331
                rc = -ENOMEM;
 
332
                fullpath_source = NULL;
 
333
                syslog(LOG_ERR, "Out of memory\n");
 
334
                goto out;
 
335
        }
 
336
        if (target[0] != '/') {
 
337
                rc = asprintf(&fullpath_target, "%s%s", cwd, target);
 
338
        } else
 
339
                rc = asprintf(&fullpath_target, "%s", target);
 
340
        if (rc == -1) {
 
341
                rc = -ENOMEM;
 
342
                fullpath_target = NULL;
 
343
                syslog(LOG_ERR, "Out of memory\n");
 
344
                goto out;
 
345
        }
 
346
        rc = 0;
 
347
        i = strlen(fullpath_source);
 
348
        if (i > 1 && fullpath_source[i - 1] == '/')
 
349
                fullpath_source[i - 1] = '\0';
 
350
        i = strlen(fullpath_target);
 
351
        if (i > 1 && fullpath_target[i - 1] == '/')
 
352
                fullpath_target[i - 1] = '\0';
 
353
        mountent.mnt_fsname = fullpath_source;
 
354
        mountent.mnt_dir = fullpath_target;
 
355
        mountent.mnt_type = "ecryptfs";
 
356
        /* we need the following byte count:
 
357
         * 200 max for opts
 
358
         * 23  max for strings below
 
359
         * 1   the final \0
 
360
         */
 
361
        mountent.mnt_opts = malloc(224);
 
362
        if (!mountent.mnt_opts) {
 
363
                rc = -ENOMEM;
 
364
                syslog(LOG_ERR, "Failed to allocate memory for mount "
 
365
                       "options\n");
 
366
                goto out;
 
367
        }
 
368
        memset(mountent.mnt_opts, 0, 224);
 
369
        /* reporting the right mount opts */
 
370
        if (flags & MS_RDONLY)
 
371
                strcat(mountent.mnt_opts,"ro");
 
372
        else
 
373
                strcat(mountent.mnt_opts,"rw");
 
374
        if (flags & MS_NOEXEC)
 
375
                strcat(mountent.mnt_opts,",noexec");
 
376
        if (flags & MS_NOSUID)
 
377
                strcat(mountent.mnt_opts,",nosuid");
 
378
        if (flags & MS_NODEV)
 
379
                strcat(mountent.mnt_opts,",nodev");
 
380
        if (opts) {
 
381
                strcat(mountent.mnt_opts, ",");
 
382
                strcat(mountent.mnt_opts, opts);
 
383
        }
 
384
        mountent.mnt_freq = 0;
 
385
        mountent.mnt_passno = 0;
 
386
        if (addmntent(mtab_fd, &mountent)) {
 
387
                rc = -EIO;
 
388
                syslog(LOG_ERR, "Failed to write to the mount "
 
389
                       "table\n");
 
390
                goto out;
 
391
        }
 
392
        rc = 0;
 
393
out:
 
394
        free(fullpath_source);
 
395
        free(fullpath_target);
 
396
        free(mountent.mnt_opts);
 
397
        if (mtab_fd)
 
398
                endmntent(mtab_fd);
 
399
        return rc;
 
400
}
 
401
 
 
402
static int zombie_semaphore_get(void)
 
403
{
 
404
        int sem_id;
 
405
        struct semid_ds semid_ds;
 
406
        struct sembuf sb;
 
407
        int i;
 
408
        int rc;
 
409
 
 
410
        sem_id = semget(ECRYPTFS_SEM_KEY, 1, (0666 | IPC_EXCL | IPC_CREAT));
 
411
        if (sem_id >= 0) {
 
412
                sb.sem_op = 1;
 
413
                sb.sem_flg = 0;
 
414
                sb.sem_num = 0;
 
415
 
 
416
                rc = semop(sem_id, &sb, 1);
 
417
                if (rc == -1) {
 
418
                        semctl(sem_id, 0, IPC_RMID);
 
419
                        syslog(LOG_ERR, "Error initializing semaphore\n");
 
420
                        rc = -1;
 
421
                        goto out;
 
422
                }
 
423
        } else if (errno == EEXIST) {
 
424
                int initialized = 0;
 
425
 
 
426
                sem_id = semget(ECRYPTFS_SEM_KEY, 1, 0);
 
427
                if (sem_id < 0) {
 
428
                        syslog(LOG_ERR, "Error getting existing semaphore");
 
429
                        rc = -1;
 
430
                        goto out;
 
431
                }
 
432
#define RETRY_LIMIT 3
 
433
                for (i = 0; i < RETRY_LIMIT; i++) {
 
434
                        semctl(sem_id, 0, IPC_STAT, &semid_ds);
 
435
                        if (semid_ds.sem_otime != 0) {
 
436
                                initialized = 1;
 
437
                                break;
 
438
                        } else
 
439
                                sleep(1);
 
440
                }
 
441
                if (!initialized) {
 
442
                        syslog(LOG_ERR, "Waited too long for initialized "
 
443
                               "semaphore; something's wrong\n");
 
444
                        rc = -1;
 
445
                        goto out;
 
446
                }
 
447
        } else {
 
448
                syslog(LOG_ERR, "Error attempting to get semaphore\n");
 
449
                rc = -1;
 
450
                goto out;
 
451
        }
 
452
        rc = sem_id;
 
453
out:
 
454
        return rc;
 
455
}
 
456
 
 
457
static void zombie_semaphore_lock(int sem_id)
 
458
{
 
459
        struct sembuf sb;
 
460
        int i;
 
461
        int rc;
 
462
 
 
463
        sb.sem_num = 0;
 
464
        sb.sem_op = -1;
 
465
        sb.sem_flg = IPC_NOWAIT;
 
466
        for (i = 0; i < RETRY_LIMIT; i++) {
 
467
                rc = semop(sem_id, &sb, 1);
 
468
                if (rc == -1 && errno == EAGAIN) {
 
469
                        sleep(1);
 
470
                } else if (rc == -1) {
 
471
                        syslog(LOG_ERR, "Error locking semaphore; errno "
 
472
                               "string = [%m]\n", errno);
 
473
                        goto out;
 
474
                } else
 
475
                        goto out;
 
476
        }
 
477
        syslog(LOG_ERR, "Error locking semaphore; hit max retries\n");
 
478
out:
 
479
        return;
 
480
}
 
481
 
 
482
static void zombie_semaphore_unlock(int sem_id)
 
483
{
 
484
        struct sembuf sb;
 
485
        int rc;
 
486
 
 
487
        sb.sem_num = 0;
 
488
        sb.sem_op = 1;
 
489
        sb.sem_flg = 0;
 
490
        rc = semop(sem_id, &sb, 1);
 
491
        if (rc == -1) {
 
492
                syslog(LOG_ERR, "Error unlocking semaphore\n");
 
493
                goto out;
 
494
        }
 
495
out:
 
496
        return;
 
497
}
 
498
 
 
499
static int get_zombie_shared_mem_locked(int *shm_id, int *sem_id)
 
500
{
 
501
        int rc;
 
502
        
 
503
        (*sem_id) = zombie_semaphore_get();
 
504
        if ((*sem_id) == -1) {
 
505
                syslog(LOG_ERR, "Error attempting to get zombie semaphore\n");
 
506
                rc = -EIO;
 
507
                goto out;
 
508
        }
 
509
        zombie_semaphore_lock((*sem_id));
 
510
        rc = shmget(ECRYPTFS_SHM_KEY, ECRYPTFS_SHM_SIZE, (0666 | IPC_CREAT
 
511
                                                          | IPC_EXCL));
 
512
        if (rc == -1 && errno == EEXIST)
 
513
                rc = shmget(ECRYPTFS_SHM_KEY, ECRYPTFS_SHM_SIZE, 0);
 
514
        else {
 
515
                char *shm_virt;
 
516
 
 
517
                (*shm_id) = rc;
 
518
                shm_virt = shmat((*shm_id), NULL, 0);
 
519
                if (shm_virt == (void *)-1) {
 
520
                        syslog(LOG_ERR, "Error attaching to newly allocated "
 
521
                               "shared memory; errno string = [%m]\n", errno);
 
522
                        rc = -EIO;
 
523
                        zombie_semaphore_unlock((*sem_id));
 
524
                        goto out;
 
525
                }
 
526
                memset(shm_virt, 0, ECRYPTFS_SHM_SIZE);
 
527
                if ((rc = shmdt(shm_virt))) {
 
528
                        rc = -EIO;
 
529
                        zombie_semaphore_unlock((*sem_id));
 
530
                        goto out;
 
531
                }
 
532
                rc = shmget(ECRYPTFS_SHM_KEY, ECRYPTFS_SHM_SIZE, 0);
 
533
        }
 
534
        if (rc == -1) {
 
535
                syslog(LOG_ERR, "Error attempting to get identifier for "
 
536
                       "shared memory with key [0x.8x]\n", ECRYPTFS_SHM_KEY);
 
537
                rc = -EIO;
 
538
                zombie_semaphore_unlock((*sem_id));
 
539
                goto out;
 
540
        }
 
541
        (*shm_id) = rc;
 
542
        rc = 0;
 
543
out:
 
544
        return rc;
 
545
}
 
546
 
 
547
static int list_pid_sid_pairs(int shm_id)
 
548
{
 
549
        pid_t sid_tmp;
 
550
        pid_t pid_tmp;
 
551
        char *shm_virt;
 
552
        int i;
 
553
        int rc;
 
554
 
 
555
        if (sizeof(pid_t) != sizeof(uint32_t)) {
 
556
                syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
 
557
                       "needs some tweaking to work on this architecture\n");
 
558
                rc = -EINVAL;
 
559
                goto out;
 
560
        }
 
561
        shm_virt = shmat(shm_id, NULL, 0);
 
562
        if (shm_virt == (void *)-1) {
 
563
                rc = -EIO;
 
564
                goto out;
 
565
        }
 
566
        i = 0;
 
567
        memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
568
        i += sizeof(pid_t);
 
569
        sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
570
        memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
571
        i += sizeof(pid_t);
 
572
        pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
573
        while (!(sid_tmp == 0 && pid_tmp == 0)) {
 
574
                if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE)
 
575
                        break;
 
576
                memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
577
                i += sizeof(pid_t);
 
578
                sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
579
                memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
580
                i += sizeof(pid_t);
 
581
                pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
582
        }
 
583
        if ((rc = shmdt(shm_virt)))
 
584
                rc = -EIO;
 
585
out:
 
586
        return rc;
 
587
}
 
588
 
 
589
static int find_pid_for_this_sid(pid_t *pid, int shm_id)
 
590
{
 
591
        pid_t sid_tmp;
 
592
        pid_t sid;
 
593
        pid_t pid_tmp;
 
594
        pid_t this_pid;
 
595
        char *shm_virt;
 
596
        int i;
 
597
        int rc;
 
598
 
 
599
        (*pid) = 0;
 
600
        if (sizeof(pid_t) != sizeof(uint32_t)) {
 
601
                syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
 
602
                       "needs some tweaking to work on this architecture\n");
 
603
                rc = -EINVAL;
 
604
                goto out;
 
605
        }
 
606
        shm_virt = shmat(shm_id, NULL, 0);
 
607
        if (shm_virt == (void *)-1) {
 
608
                rc = -EIO;
 
609
                goto out;
 
610
        }
 
611
        i = 0;
 
612
        memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
613
        i += sizeof(pid_t);
 
614
        sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
615
        memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
616
        i += sizeof(pid_t);
 
617
        pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
618
        this_pid = getpid();
 
619
        sid = getsid(this_pid);
 
620
        while (!(sid_tmp == 0 && pid_tmp == 0)) {
 
621
                if (sid_tmp == sid) {
 
622
                        (*pid) = pid_tmp;
 
623
                        goto end_search;
 
624
                }
 
625
                if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE)
 
626
                        break;
 
627
                memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
628
                i += sizeof(pid_t);
 
629
                sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
630
                memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
631
                i += sizeof(pid_t);
 
632
                pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
633
        }
 
634
end_search:
 
635
        if ((rc = shmdt(shm_virt))) {
 
636
                rc = -EIO;
 
637
                (*pid) = 0;
 
638
        }
 
639
out:
 
640
        return rc;
 
641
}
 
642
 
 
643
static int remove_pid_for_this_sid(int shm_id)
 
644
{
 
645
        pid_t sid_tmp;
 
646
        pid_t sid;
 
647
        pid_t pid_tmp;
 
648
        pid_t pid;
 
649
        pid_t this_pid;
 
650
        char *shm_virt;
 
651
        int i;
 
652
        int rc;
 
653
 
 
654
        pid = 0;
 
655
        if (sizeof(pid_t) != sizeof(uint32_t)) {
 
656
                syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
 
657
                       "needs some tweaking to work on this architecture\n");
 
658
                rc = -EINVAL;
 
659
                goto out;
 
660
        }
 
661
        shm_virt = shmat(shm_id, NULL, 0);
 
662
        if (shm_virt == (void *)-1) {
 
663
                rc = -EIO;
 
664
                goto out;
 
665
        }
 
666
        i = 0;
 
667
        memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
668
        i += sizeof(pid_t);
 
669
        sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
670
        memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
671
        i += sizeof(pid_t);
 
672
        pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
673
        this_pid = getpid();
 
674
        sid = getsid(this_pid);
 
675
        while (!(sid_tmp == 0 && pid_tmp == 0)) {
 
676
                if (sid_tmp == sid) {
 
677
                        pid = pid_tmp;
 
678
                        break;
 
679
                }
 
680
                if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE)
 
681
                        break;
 
682
                memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
683
                i += sizeof(pid_t);
 
684
                sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
685
                memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
686
                i += sizeof(pid_t);
 
687
                pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
688
        }
 
689
        if (pid != 0) {
 
690
                char *tmp;
 
691
                int remainder = (ECRYPTFS_SHM_SIZE - i);
 
692
 
 
693
                if (remainder != 0) {
 
694
                        if ((tmp = malloc(remainder)) == NULL) {
 
695
                                rc = -ENOMEM;
 
696
                                shmdt(shm_virt);
 
697
                                goto out;
 
698
                        }
 
699
                        memcpy(tmp, &shm_virt[i], remainder);
 
700
                        i -= (2 * sizeof(pid_t));
 
701
                        memcpy(&shm_virt[i], tmp, remainder);
 
702
                        i += remainder;
 
703
                } else
 
704
                        i -= (2 * sizeof(pid_t));
 
705
                memset(&shm_virt[i], 0, (2 * sizeof(pid_t)));
 
706
                if (remainder != 0)
 
707
                        free(tmp);
 
708
        }
 
709
        if ((rc = shmdt(shm_virt)))
 
710
                rc = -EIO;
 
711
out:
 
712
        return rc;
 
713
}
 
714
 
 
715
static int add_sid_pid_pair_to_shm(int shm_id)
 
716
{
 
717
        pid_t sid_tmp;
 
718
        pid_t sid;
 
719
        pid_t pid_tmp;
 
720
        pid_t pid;
 
721
        char *shm_virt;
 
722
        int i;
 
723
        int rc;
 
724
 
 
725
        if (sizeof(pid_t) != sizeof(uint32_t)) {
 
726
                syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
 
727
                       "needs some tweaking to work on this architecture\n");
 
728
                rc = -EINVAL;
 
729
                goto out;
 
730
        }
 
731
        shm_virt = shmat(shm_id, NULL, 0);
 
732
        if (shm_virt == (void *)-1) {
 
733
                syslog(LOG_ERR, "Error attaching to shared memory; error "
 
734
                       "string = [%m]\n", errno);
 
735
                shm_virt = shmat(shm_id, NULL, 0);
 
736
                if (shm_virt == (void *)-1) {
 
737
                        syslog(LOG_ERR, "Error attaching to shared memory; error "
 
738
                               "string = [%m]\n", errno);
 
739
                        rc = -EIO;
 
740
                        goto out;
 
741
                }
 
742
                rc = -EIO;
 
743
                goto out;
 
744
        }
 
745
        i = 0;
 
746
        memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
747
        i += sizeof(pid_t);
 
748
        sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
749
        memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
750
        i += sizeof(pid_t);
 
751
        pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
752
        while (!(sid_tmp == 0 && pid_tmp == 0)) {
 
753
                if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE) {
 
754
                        syslog(LOG_ERR,
 
755
                               "No space left in shared memory region\n");
 
756
                        rc = -ENOMEM;
 
757
                        shmdt(shm_virt);
 
758
                        goto out;
 
759
                }
 
760
                memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
 
761
                i += sizeof(pid_t);
 
762
                sid_tmp = ntohl(sid_tmp); /* uint32_t */
 
763
                memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
 
764
                i += sizeof(pid_t);
 
765
                pid_tmp = ntohl(pid_tmp); /* uint32_t */
 
766
        }
 
767
        pid = getpid();
 
768
        sid = getsid(pid);
 
769
        sid = htonl(sid);
 
770
        pid = htonl(pid);
 
771
        i -= (2 * sizeof(pid_t));
 
772
        memcpy(&shm_virt[i], &sid, sizeof(pid_t));
 
773
        i += sizeof(pid_t);
 
774
        memcpy(&shm_virt[i], &pid, sizeof(pid_t));
 
775
        i += sizeof(pid_t);
 
776
        if ((i + (2 * sizeof(pid_t))) <= ECRYPTFS_SHM_SIZE)
 
777
                memset(&shm_virt[i], 0, (i + (2 * sizeof(pid_t))));
 
778
        if ((rc = shmdt(shm_virt))) {
 
779
                syslog(LOG_ERR, "Error detaching from shared memory\n");
 
780
                rc = -EIO;
 
781
        }
 
782
out:
 
783
        return rc;
 
784
}
 
785
 
 
786
int ecryptfs_set_zombie_session_placeholder(void)
 
787
{
 
788
        int shm_id;
 
789
        int sem_id;
 
790
        int rc = 0;
 
791
 
 
792
        if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
 
793
                syslog(LOG_ERR,
 
794
                       "Error getting shared memory segment\n");
 
795
                goto out;
 
796
        }
 
797
        if ((rc = add_sid_pid_pair_to_shm(shm_id))) {
 
798
                syslog(LOG_ERR, "Error adding sid/pid pair to shared memory "
 
799
                       "segment; rc = [%d]\n", rc);
 
800
                zombie_semaphore_unlock(sem_id);
 
801
                goto out;
 
802
        }
 
803
        zombie_semaphore_unlock(sem_id);
 
804
        sleep(ECRYPTFS_ZOMBIE_SLEEP_SECONDS);
 
805
        if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
 
806
                syslog(LOG_ERR,
 
807
                       "Error getting shared memory segment\n");
 
808
                goto out;
 
809
        }
 
810
        if ((rc = remove_pid_for_this_sid(shm_id))) {
 
811
                syslog(LOG_ERR, "Error attempting to remove pid/sid "
 
812
                       "pair from shared memory segment; rc = [%d]\n",
 
813
                       rc);
 
814
                zombie_semaphore_unlock(sem_id);
 
815
                goto out;
 
816
        }
 
817
        zombie_semaphore_unlock(sem_id);
 
818
        exit(1);
 
819
out:
 
820
        return rc;
 
821
}
 
822
 
 
823
int ecryptfs_kill_and_clear_zombie_session_placeholder(void)
 
824
{
 
825
        int shm_id;
 
826
        int sem_id;
 
827
        int pid;
 
828
        int rc = 0;
 
829
 
 
830
        if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
 
831
                syslog(LOG_ERR, "Error getting shared memory segment\n");
 
832
                goto out;
 
833
        }
 
834
        if ((rc = find_pid_for_this_sid(&pid, shm_id))) {
 
835
                syslog(LOG_ERR, "Error finding pid for sid in shared memory "
 
836
                       "segment; rc = [%d]\n", rc);
 
837
                zombie_semaphore_unlock(sem_id);
 
838
                goto out;
 
839
        }
 
840
        if (pid == 0) {
 
841
                syslog(LOG_WARNING, "No valid pid found for this sid\n");
 
842
        } else {
 
843
                if ((rc = kill(pid, SIGKILL))) {
 
844
                        syslog(LOG_ERR, "Error attempting to kill process "
 
845
                               "[%d]; rc = [%d]; errno string = [%m]\n", pid,
 
846
                               rc, errno);
 
847
                }
 
848
                if ((rc = remove_pid_for_this_sid(shm_id))) {
 
849
                        syslog(LOG_ERR, "Error attempting to remove pid/sid "
 
850
                               "pair from shared memory segment; rc = [%d]\n",
 
851
                               rc);
 
852
                        zombie_semaphore_unlock(sem_id);
 
853
                        goto out;
 
854
                }
 
855
        }
 
856
        zombie_semaphore_unlock(sem_id);
 
857
out:
 
858
        return rc;
 
859
}
 
860
 
 
861
int ecryptfs_list_zombie_session_placeholders(void)
 
862
{
 
863
        int shm_id;
 
864
        int sem_id;
 
865
        int rc = 0;
 
866
 
 
867
        if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
 
868
                syslog(LOG_ERR,
 
869
                       "Error getting shared memory segment\n");
 
870
                goto out;
 
871
        }
 
872
        if ((rc = list_pid_sid_pairs(shm_id))) {
 
873
                syslog(LOG_ERR, "Error listing sid/pid pairs in shared memory "
 
874
                       "segment; rc = [%d]\n", rc);
 
875
                zombie_semaphore_unlock(sem_id);
 
876
                goto out;
 
877
        }
 
878
        zombie_semaphore_unlock(sem_id);
 
879
out:
 
880
        return rc;
 
881
}
 
882
 
 
883
static struct ecryptfs_ctx_ops ctx_ops;
 
884
 
 
885
struct ecryptfs_ctx_ops *cryptfs_get_ctx_opts (void)
 
886
{
 
887
        return &ctx_ops;
 
888
}