]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2011 New Dream Network | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <string.h> | |
16 | #include <stdio.h> | |
7c673cae FG |
17 | #include <unistd.h> |
18 | #include <errno.h> | |
19 | #include <fcntl.h> | |
20 | #include <keyutils.h> | |
7c673cae FG |
21 | |
22 | #include "common/armor.h" | |
23 | #include "common/safe_io.h" | |
24 | ||
25 | int read_secret_from_file(const char *filename, char *secret, size_t max_len) | |
26 | { | |
27 | char *end; | |
28 | int fd; | |
29 | int len; | |
30 | ||
31 | fd = open(filename, O_RDONLY); | |
32 | if (fd < 0) { | |
33 | perror("unable to read secretfile"); | |
34 | return -1; | |
35 | } | |
36 | len = safe_read(fd, secret, max_len); | |
37 | if (len <= 0) { | |
38 | perror("unable to read secret from file"); | |
39 | close(fd); | |
40 | return -1; | |
41 | } | |
42 | end = secret; | |
43 | while (end < secret + len && *end && *end != '\n' && *end != '\r') | |
44 | end++; | |
45 | *end = '\0'; | |
46 | close(fd); | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | int set_kernel_secret(const char *secret, const char *key_name) | |
52 | { | |
53 | /* try to submit key to kernel via the keys api */ | |
54 | key_serial_t serial; | |
55 | int ret; | |
56 | int secret_len = strlen(secret); | |
57 | char payload[((secret_len * 3) / 4) + 4]; | |
58 | ||
59 | if (!secret_len) { | |
60 | fprintf(stderr, "secret is empty.\n"); | |
61 | return -EINVAL; | |
62 | } | |
63 | ||
64 | ret = ceph_unarmor(payload, payload+sizeof(payload), secret, secret+secret_len); | |
65 | if (ret < 0) { | |
66 | char error_buf[80]; | |
67 | fprintf(stderr, "secret is not valid base64: %s.\n", | |
68 | strerror_r(-ret, error_buf, sizeof(error_buf))); | |
69 | return ret; | |
70 | } | |
71 | ||
72 | serial = add_key("ceph", key_name, payload, sizeof(payload), KEY_SPEC_PROCESS_KEYRING); | |
73 | if (serial == -1) { | |
74 | ret = -errno; | |
75 | } | |
76 | ||
77 | return ret; | |
78 | } | |
79 | ||
80 | int is_kernel_secret(const char *key_name) | |
81 | { | |
82 | key_serial_t serial; | |
83 | serial = request_key("ceph", key_name, NULL, KEY_SPEC_USER_KEYRING); | |
84 | return serial != -1; | |
85 | } | |
86 | ||
87 | int get_secret_option(const char *secret, const char *key_name, | |
88 | char *secret_option, size_t max_len) | |
89 | { | |
90 | if (!key_name) { | |
91 | return -EINVAL; | |
92 | } | |
93 | ||
94 | int ret = 0; | |
95 | int olen = strlen(key_name) + 7; | |
96 | if (secret) { | |
97 | olen += strlen(secret); | |
98 | } | |
99 | char option[olen+1]; | |
100 | int use_key = 1; | |
101 | ||
102 | option[olen] = '\0'; | |
103 | ||
104 | ||
105 | if (secret) { | |
106 | ret = set_kernel_secret(secret, key_name); | |
107 | if (ret < 0) { | |
108 | if (ret == -ENODEV || ret == -ENOSYS) { | |
109 | /* running against older kernel; fall back to secret= in options */ | |
110 | snprintf(option, olen, "secret=%s", secret); | |
111 | ret = 0; | |
112 | use_key = 0; | |
113 | } else { | |
114 | char error_buf[80]; | |
115 | fprintf(stderr, "adding ceph secret key to kernel failed: %s.\n", | |
116 | strerror_r(-ret, error_buf, sizeof(error_buf))); | |
117 | return ret; | |
118 | } | |
119 | } | |
120 | } | |
121 | ||
122 | if (use_key) { | |
123 | /* add key= option to identify key to use */ | |
124 | snprintf(option, olen, "key=%s", key_name); | |
125 | } | |
126 | ||
127 | if (strlen(option) + 1 > max_len) { | |
128 | ret = -ERANGE; | |
129 | } else { | |
130 | secret_option[max_len-1] = '\0'; | |
131 | strncpy(secret_option, option, max_len-1); | |
132 | } | |
133 | ||
134 | return ret; | |
135 | } |