keyutils 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/keyutils.gemspec +28 -0
- data/lib/keyutils.rb +11 -0
- data/lib/keyutils/key.rb +572 -0
- data/lib/keyutils/key_perm.rb +49 -0
- data/lib/keyutils/key_types.rb +24 -0
- data/lib/keyutils/keyring.rb +527 -0
- data/lib/keyutils/lib.rb +433 -0
- data/lib/keyutils/version.rb +3 -0
- metadata +132 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
module Keyutils
|
2
|
+
# Key permission constants.
|
3
|
+
# @see Key#setperm
|
4
|
+
module KeyPerm
|
5
|
+
KEY_POS_VIEW = 0x01000000 # possessor can view a key's attributes
|
6
|
+
KEY_POS_READ = 0x02000000 # possessor can read key payload / view keyring
|
7
|
+
KEY_POS_WRITE = 0x04000000 # possessor can update key payload / add link to keyring
|
8
|
+
KEY_POS_SEARCH = 0x08000000 # possessor can find a key in search / search a keyring
|
9
|
+
KEY_POS_LINK = 0x10000000 # possessor can create a link to a key/keyring
|
10
|
+
KEY_POS_SETATTR = 0x20000000 # possessor can set key attributes
|
11
|
+
KEY_POS_ALL = 0x3f000000
|
12
|
+
|
13
|
+
#
|
14
|
+
# user permissions...
|
15
|
+
#
|
16
|
+
|
17
|
+
KEY_USR_VIEW = 0x00010000
|
18
|
+
KEY_USR_READ = 0x00020000
|
19
|
+
KEY_USR_WRITE = 0x00040000
|
20
|
+
KEY_USR_SEARCH = 0x00080000
|
21
|
+
KEY_USR_LINK = 0x00100000
|
22
|
+
KEY_USR_SETATTR = 0x00200000
|
23
|
+
KEY_USR_ALL = 0x003f0000
|
24
|
+
|
25
|
+
#
|
26
|
+
# group permissions...
|
27
|
+
#
|
28
|
+
|
29
|
+
KEY_GRP_VIEW = 0x00000100
|
30
|
+
KEY_GRP_READ = 0x00000200
|
31
|
+
KEY_GRP_WRITE = 0x00000400
|
32
|
+
KEY_GRP_SEARCH = 0x00000800
|
33
|
+
KEY_GRP_LINK = 0x00001000
|
34
|
+
KEY_GRP_SETATTR = 0x00002000
|
35
|
+
KEY_GRP_ALL = 0x00003f00
|
36
|
+
|
37
|
+
#
|
38
|
+
# third party permissions...
|
39
|
+
#
|
40
|
+
|
41
|
+
KEY_OTH_VIEW = 0x00000001
|
42
|
+
KEY_OTH_READ = 0x00000002
|
43
|
+
KEY_OTH_WRITE = 0x00000004
|
44
|
+
KEY_OTH_SEARCH = 0x00000008
|
45
|
+
KEY_OTH_LINK = 0x00000010
|
46
|
+
KEY_OTH_SETATTR = 0x00000020
|
47
|
+
KEY_OTH_ALL = 0x0000003f
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Keyutils
|
2
|
+
module KeyTypes
|
3
|
+
class << self
|
4
|
+
def classes
|
5
|
+
@classes ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def [] type
|
9
|
+
classes[type]
|
10
|
+
end
|
11
|
+
|
12
|
+
def []= type, klass
|
13
|
+
klass.send :define_method, :initialize, ->(id, description) do
|
14
|
+
@id = id
|
15
|
+
@description = description
|
16
|
+
end
|
17
|
+
klass.send :define_method, :type, ->() do
|
18
|
+
type
|
19
|
+
end
|
20
|
+
classes[type] = klass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,527 @@
|
|
1
|
+
require 'keyutils/key'
|
2
|
+
require 'keyutils/key_types'
|
3
|
+
|
4
|
+
module Keyutils
|
5
|
+
class Keyring < Key
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
# Clear the contents of the keyring.
|
9
|
+
#
|
10
|
+
# The caller must have write permission on a keyring to be able clear it.
|
11
|
+
# @return [Keyring] self
|
12
|
+
# @raise [Errno::ENOKEY] the keyring is invalid
|
13
|
+
# @raise [Errno::EKEYEXPIRED] the keyring has expired
|
14
|
+
# @raise [Errno::EKEYREVOKED] the keyring had been revoked
|
15
|
+
# @raise [Errno::EACCES] the keyring is not writable by the calling process
|
16
|
+
def clear
|
17
|
+
Lib.keyctl_clear id
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
# Link a key to the keyring.
|
22
|
+
#
|
23
|
+
# Creates a link from this keyring to +key+, displacing any link to another
|
24
|
+
# key of the same type and description in this keyring if one exists.
|
25
|
+
#
|
26
|
+
# The caller must have write permission on a keyring to be able to create
|
27
|
+
# links in it.
|
28
|
+
#
|
29
|
+
# The caller must have link permission on a key to be able to create a
|
30
|
+
# link to it.
|
31
|
+
#
|
32
|
+
# @param key [Key] the key to link to this keyring
|
33
|
+
# @return [Keyring] self
|
34
|
+
# @raise [Errno::ENOKEY] the key or the keyring specified are invalid
|
35
|
+
# @raise [Errno::EKEYEXPIRED] the key or the keyring specified have expired
|
36
|
+
# @raise [Errno::EKEYREVOKED] the key or the keyring specified have been
|
37
|
+
# revoked
|
38
|
+
# @raise [Errno::EACCES] the keyring exists, but is not writable by the
|
39
|
+
# calling process
|
40
|
+
# @raise [Errno::ENOMEM] insufficient memory to expand the keyring
|
41
|
+
# @raise [Errno::EDQUOT] expanding the keyring would exceed the keyring
|
42
|
+
# owner's quota
|
43
|
+
# @raise [Errno::EACCES] the key exists, but is not linkable by the
|
44
|
+
# calling process
|
45
|
+
# @see #unlink
|
46
|
+
def link key
|
47
|
+
Lib.keyctl_link key.id, id
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
alias << link
|
52
|
+
|
53
|
+
# Unlink a key from the keyring.
|
54
|
+
#
|
55
|
+
# Removes a link from this keyring to +key+ if it exists.
|
56
|
+
#
|
57
|
+
# The caller must have write permission on a keyring to be able to remove
|
58
|
+
# links in it.
|
59
|
+
# @param key [Key] the key to unlink from this keyring
|
60
|
+
# @return [Keyring] self
|
61
|
+
# @raise [Errno::ENOKEY] the key or the keyring specified are invalid
|
62
|
+
# @raise [Errno::EKEYEXPIRED] the key or the keyring specified have expired
|
63
|
+
# @raise [Errno::EKEYREVOKED] the key or the keyring specified have been
|
64
|
+
# revoked
|
65
|
+
# @raise [Errno::EACCES] the keyring exists, but is not writable by the
|
66
|
+
# calling process
|
67
|
+
# @see #link
|
68
|
+
def unlink key
|
69
|
+
Lib.keyctl_unlink key.id, id
|
70
|
+
self
|
71
|
+
rescue Errno::ENOENT
|
72
|
+
# there was no link
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
# Search the keyring for a key
|
77
|
+
#
|
78
|
+
# Recursively searches the keyring for a key of the specified +type+ and
|
79
|
+
# +description+.
|
80
|
+
#
|
81
|
+
# If found, the key will be attached to the +destination+ keyring (if
|
82
|
+
# given), and returned.
|
83
|
+
#
|
84
|
+
# The source keyring must grant search permission to the caller, and for a
|
85
|
+
# key to be found, it must also grant search permission to the caller.
|
86
|
+
# Child keyrings will be only be recursively searched if they grant search
|
87
|
+
# permission to the caller as well.
|
88
|
+
#
|
89
|
+
# If the +destination+ keyring is given, then the link may only be formed
|
90
|
+
# if the found key grants the caller link permission and the destination
|
91
|
+
# keyring grants the caller write permission.
|
92
|
+
#
|
93
|
+
# If the search is successful, and if the destination keyring already
|
94
|
+
# contains a link to a key that matches the specified type and description,
|
95
|
+
# then that link will be replaced by a link to the found key.
|
96
|
+
#
|
97
|
+
# @param type [Symbol] the type of the key to find
|
98
|
+
# @param description [String] the description of the key to find
|
99
|
+
# @param destination [Keyring, nil] the keyring to attach the key if found
|
100
|
+
# @return [Key, nil] the key, if found
|
101
|
+
# @raise [Errno::EKEYEXPIRED] one of the keyrings has expired, or the only
|
102
|
+
# key found was expired
|
103
|
+
# @raise [Errno::EKEYREVOKED] one of the keyrings has been revoked, or the
|
104
|
+
# only key found was revoked
|
105
|
+
# @raise [Errno::ENOMEM] insufficient memory to expand the destination
|
106
|
+
# keyring
|
107
|
+
# @raise [Errno::EDQUOT] the key quota for this user would be exceeded by
|
108
|
+
# creating a link to the found key in the destination keyring
|
109
|
+
# @raise [Errno::EACCES] the source keyring didn't grant search permission,
|
110
|
+
# the destination keyring didn't grant write permission or the found key
|
111
|
+
# didn't grant link permission to the caller
|
112
|
+
# @see #request
|
113
|
+
def search type, description, destination = nil
|
114
|
+
serial = Lib.keyctl_search id, type.to_s, description, destination.to_i
|
115
|
+
Key.send :new_dispatch, serial, type.intern, description
|
116
|
+
rescue Errno::ENOKEY
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
# Read the keyring.
|
121
|
+
#
|
122
|
+
# Reads the list of keys in this keyring.
|
123
|
+
#
|
124
|
+
# The caller must have read permission on a key to be able to read it.
|
125
|
+
#
|
126
|
+
# @return [<Key>] the keyring members
|
127
|
+
# @raise [Errno::ENOKEY] the keyring is invalid
|
128
|
+
# @raise [Errno::EKEYEXPIRED] the keyring has expired
|
129
|
+
# @raise [Errno::EKEYREVOKED] the keyring had been revoked
|
130
|
+
# @raise [Errno::EACCES] the keyring is not readable by the calling process
|
131
|
+
# @see #each
|
132
|
+
def read
|
133
|
+
super.unpack('L*').map do |serial|
|
134
|
+
# try to map to the correct class
|
135
|
+
key = Key.send :new, serial, nil, nil
|
136
|
+
Key.send(:new_dispatch, serial, key.type, key.description) rescue key
|
137
|
+
end
|
138
|
+
end
|
139
|
+
alias to_a read
|
140
|
+
undef to_s rescue nil
|
141
|
+
|
142
|
+
# Iterate over linked keys
|
143
|
+
#
|
144
|
+
# @return [Enumerator, Keyring] self if block given, else an Enumerator
|
145
|
+
# @yieldparam key [Key] member of the keyring
|
146
|
+
# @see #read
|
147
|
+
def each &b
|
148
|
+
read.each &b
|
149
|
+
end
|
150
|
+
|
151
|
+
# Iterate over keys recursively
|
152
|
+
#
|
153
|
+
# Performs a depth-first recursive scan of the keyring tree and yields for
|
154
|
+
# every link found in the accessible keyrings in that tree.
|
155
|
+
#
|
156
|
+
# Errors are ignored. Inaccessible keyrings are not scanned, but links to
|
157
|
+
# them are still yielded. If key attributes (and hence ype) cannot be
|
158
|
+
# retrieved, a generic {Key} object is yielded and an error that prevented
|
159
|
+
# it is indicated.
|
160
|
+
#
|
161
|
+
# This method yields for each link found in all the keyrings in the tree
|
162
|
+
# and so may be called multiple times for a particular key if that key has
|
163
|
+
# multiple links to it.
|
164
|
+
#
|
165
|
+
# @yieldparam key [Key] the key to which the link points
|
166
|
+
# @yieldparam parent [Keyring, nil] the keyring containing the link or nil
|
167
|
+
# for the initial key.
|
168
|
+
# @yieldparam attributes [Hash] key attributes, as returned by
|
169
|
+
# {Key#describe}
|
170
|
+
# @yieldparam error [SystemCallError, nil] error that prevented retrieving
|
171
|
+
# key attributes
|
172
|
+
#
|
173
|
+
# @return [Enumerator, Keyring] self if block given, else an Enumerator
|
174
|
+
def each_recursive
|
175
|
+
return enum_for __method__ unless block_given?
|
176
|
+
|
177
|
+
Lib.recursive_key_scan serial, ->(parent, key, desc, desc_len, _) do
|
178
|
+
parent = parent == 0 ? nil : Keyring.send(:new, parent, nil)
|
179
|
+
if desc_len > 0
|
180
|
+
attributes = Key.send :parse_describe, desc.read_string(desc_len)
|
181
|
+
key = Key.send :new_dispatch, key, attributes[:type], attributes[:desc]
|
182
|
+
error = nil
|
183
|
+
else
|
184
|
+
attributes = nil
|
185
|
+
key = Key.send :new, key, nil, nil
|
186
|
+
error = SystemCallError.new FFI.errno
|
187
|
+
end
|
188
|
+
yield key, parent, attributes, error
|
189
|
+
0
|
190
|
+
end, nil
|
191
|
+
self
|
192
|
+
end
|
193
|
+
|
194
|
+
# @return [Fixnum] number of keys linked to this keyring
|
195
|
+
def length
|
196
|
+
read.length
|
197
|
+
end
|
198
|
+
|
199
|
+
# Add a key to the kernel's key management facility.
|
200
|
+
#
|
201
|
+
# Asks the kernel to create or update a key of the given +type+ and
|
202
|
+
# +description+, instantiate it with the +payload+, and to attach it to
|
203
|
+
# this keyring.
|
204
|
+
#
|
205
|
+
# The key type may reject the data if it's in the wrong format or in
|
206
|
+
# some other way invalid.
|
207
|
+
#
|
208
|
+
# Keys of the user-defined key type ("user") may contain a blob of
|
209
|
+
# arbitrary data, and the description may be any valid string, though it
|
210
|
+
# is preferred that the description be prefixed with a string
|
211
|
+
# representing the service to which the key is of interest and a colon
|
212
|
+
# (for instance "afs:mykey").
|
213
|
+
#
|
214
|
+
# If this keyring already contains a key that matches the specified type
|
215
|
+
# and description then, if the key type supports it, that key will be
|
216
|
+
# updated rather than a new key being created; if not, a new key will be
|
217
|
+
# created and it will displace the link to the extant key from the keyring.
|
218
|
+
#
|
219
|
+
# @param type [Symbol] key type
|
220
|
+
# @param description [String] key description
|
221
|
+
# @param payload [#to_s, nil] payload
|
222
|
+
# @return [Key] the key created or updated
|
223
|
+
# @raise [Errno::ENOKEY] the keyring doesn't exist
|
224
|
+
# @raise [Errno::EKEYEXPIRED] the keyring has expired
|
225
|
+
# @raise [Errno::EKEYREVOKED] the keyring has been revoked
|
226
|
+
# @raise [Errno::EINVAL] the payload data was invalid
|
227
|
+
# @raise [Errno::ENODEV] the key type was invalid
|
228
|
+
# @raise [Errno::ENOMEM] insufficient memory to create a key
|
229
|
+
# @raise [Errno::EDQUOT] the key quota for this user would be exceeded by
|
230
|
+
# creating this key or linking it to the keyring
|
231
|
+
# @raise [Errno::EACCES] the keyring wasn't available for modification by
|
232
|
+
# the user
|
233
|
+
def add type, description, payload
|
234
|
+
serial = Lib.add_key \
|
235
|
+
type.to_s,
|
236
|
+
description,
|
237
|
+
payload && payload.to_s,
|
238
|
+
payload && payload.to_s.length || 0,
|
239
|
+
to_i
|
240
|
+
Key.send :new_dispatch, serial, type.intern, description
|
241
|
+
end
|
242
|
+
|
243
|
+
# Request a key from the kernel's key management facility.
|
244
|
+
#
|
245
|
+
# Asks the kernel to find a key of the given +type+ that matches the
|
246
|
+
# specified +description+ and, if successful, to attach it this keyring.
|
247
|
+
#
|
248
|
+
# {#request} first recursively searches all the keyrings attached to the
|
249
|
+
# calling process in the order thread-specific keyring, process-specific
|
250
|
+
# keyring and then session keyring for a matching key.
|
251
|
+
#
|
252
|
+
# If {#request} is called from a program invoked by request_key(2) on
|
253
|
+
# behalf of some other process to generate a key, then the keyrings of
|
254
|
+
# that other process will be searched next, using that other process's
|
255
|
+
# UID, GID, groups and security context to control access.
|
256
|
+
#
|
257
|
+
# The keys in each keyring searched are checked for a match before any
|
258
|
+
# child keyrings are recursed into. Only keys that are searchable for
|
259
|
+
# the caller may be found, and only searchable keyrings may be searched.
|
260
|
+
#
|
261
|
+
# If the key is not found then, if +callout_info+ is not nil, this
|
262
|
+
# function will attempt to look further afield. In such a case, the
|
263
|
+
# +callout_info+ is passed to a user-space service such as
|
264
|
+
# +/sbin/request-key+ to generate the key.
|
265
|
+
#
|
266
|
+
# If that is unsuccessful also, then an error will be raised, and a
|
267
|
+
# temporary negative key will be installed in the keyring. This
|
268
|
+
# will expire after a few seconds, but will cause subsequent calls to
|
269
|
+
# {#request} to fail until it does.
|
270
|
+
#
|
271
|
+
# If a key is created, no matter whether it's a valid key or a negative
|
272
|
+
# key, it will displace any other key of the same type and description
|
273
|
+
# from the keyring.
|
274
|
+
# @param type [Symbol] key type
|
275
|
+
# @param description [String] key description
|
276
|
+
# @param callout_info [String, nil] additional parameters for the
|
277
|
+
# request-key(8) facility
|
278
|
+
# @return [Key, nil] the key, if found
|
279
|
+
# @raise [Errno::EACCES] the keyring wasn't available for modification by the user
|
280
|
+
# @raise [Errno::EINTR] the request was interrupted by a signal
|
281
|
+
# @raise [Errno::EDQUOT] the key quota for this user would be exceeded by creating this key or linking it to the keyring
|
282
|
+
# @raise [Errno::EKEYEXPIRED] an expired key was found, but no replacement could be obtained
|
283
|
+
# @raise [Errno::EKEYREJECTED] the attempt to generate a new key was rejected
|
284
|
+
# @raise [Errno::EKEYREVOKED] a revoked key was found, but no replacement could be obtained
|
285
|
+
# @raise [Errno::ENOMEM] insufficient memory to create a key
|
286
|
+
# @see Keyring#search
|
287
|
+
# @see http://man7.org/linux/man-pages/man2/request_key.2.html request_key(2)
|
288
|
+
# @see #assume_authority
|
289
|
+
def request type, description, callout_info = ''
|
290
|
+
serial = Lib.request_key \
|
291
|
+
type.to_s,
|
292
|
+
description,
|
293
|
+
callout_info,
|
294
|
+
to_i
|
295
|
+
new_dispatch serial, type.intern, description
|
296
|
+
rescue Errno::ENOKEY
|
297
|
+
nil
|
298
|
+
end
|
299
|
+
|
300
|
+
# Get a member "user" key
|
301
|
+
#
|
302
|
+
# Searches the members of the keyring for a :user type key with the
|
303
|
+
# given +description+
|
304
|
+
#
|
305
|
+
# @param description [String] description of the key to find
|
306
|
+
# @return [Key, nil] the key, if found
|
307
|
+
def [] description
|
308
|
+
find do |key|
|
309
|
+
key.type == :user && key.description == description rescue false
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Set a member "user" key
|
314
|
+
#
|
315
|
+
# Updates or creates a member key of type "user" and given description
|
316
|
+
#
|
317
|
+
# @param description [String] the description of the key to update or
|
318
|
+
# create
|
319
|
+
# @param payload [String] the new key payload
|
320
|
+
# @return [String] +payload+
|
321
|
+
def []= description, payload
|
322
|
+
add :user, description, payload
|
323
|
+
end
|
324
|
+
|
325
|
+
# Return all "user" subkeys
|
326
|
+
#
|
327
|
+
# Keys that cannot be read are ommited.
|
328
|
+
#
|
329
|
+
# @return [{String => String}] user keys' descriptions and their payloads
|
330
|
+
def to_h
|
331
|
+
keys = find_all { |k| k.type == :user rescue false }
|
332
|
+
pairs = keys.map { |k| [k.description, k.to_s] rescue nil }
|
333
|
+
Hash[*pairs.compact.flatten]
|
334
|
+
end
|
335
|
+
|
336
|
+
class << self
|
337
|
+
# Set the implicit destination keyring
|
338
|
+
#
|
339
|
+
# Sets the default destination for implicit key requests for the current
|
340
|
+
# thread.
|
341
|
+
#
|
342
|
+
# After this operation has been issued, keys acquired by implicit key
|
343
|
+
# requests, such as might be performed by open() on an AFS or NFS
|
344
|
+
# filesystem, will be linked by default to the specified keyring by this
|
345
|
+
# function.
|
346
|
+
#
|
347
|
+
# Only one of the special keyrings can be set as default:
|
348
|
+
# - {Thread}
|
349
|
+
# - {Process}
|
350
|
+
# - {Session}
|
351
|
+
# - {User}
|
352
|
+
# - {UserSession}
|
353
|
+
# - {Group}
|
354
|
+
#
|
355
|
+
# If +keyring+ is nil, the default behaviour is selected, which is to
|
356
|
+
# use the thread-specific keyring if there is one, otherwise the
|
357
|
+
# process-specific keyring if there is one, otherwise the session
|
358
|
+
# keyring if there is one, otherwise the UID-specific session keyring.
|
359
|
+
#
|
360
|
+
# @param keyring [Keyring, nil] the new default keyring
|
361
|
+
# @return [Keyring, nil] +keyring+
|
362
|
+
# @see .default
|
363
|
+
def default= keyring = nil
|
364
|
+
id = keyring.to_i
|
365
|
+
raise ArgumentError, 'only special keyrings can be default' \
|
366
|
+
if id > 0
|
367
|
+
Lib.keyctl_set_reqkey_keyring -id
|
368
|
+
end
|
369
|
+
|
370
|
+
# Get the implicit destination keyring
|
371
|
+
#
|
372
|
+
# Gets the default destination for implicit key requests for the current
|
373
|
+
# thread.
|
374
|
+
#
|
375
|
+
# Keys acquired by implicit key requests, such as might be performed
|
376
|
+
# by open() on an AFS or NFS filesystem, will be linked by default to
|
377
|
+
# that keyring.
|
378
|
+
#
|
379
|
+
# Only one of the special keyrings can be returned:
|
380
|
+
# - {Thread}
|
381
|
+
# - {Process}
|
382
|
+
# - {Session}
|
383
|
+
# - {User}
|
384
|
+
# - {UserSession}
|
385
|
+
# - {Group}
|
386
|
+
#
|
387
|
+
# If nil is returned, the default behaviour is selected, which is to
|
388
|
+
# use the thread-specific keyring if there is one, otherwise the
|
389
|
+
# process-specific keyring if there is one, otherwise the session
|
390
|
+
# keyring if there is one, otherwise the UID-specific session keyring.
|
391
|
+
#
|
392
|
+
# @return [Keyring, nil] the default keyring
|
393
|
+
# @see .default=
|
394
|
+
def default
|
395
|
+
[nil, Thread, Process, Session, User, UserSession, Group]\
|
396
|
+
[Lib.keyctl_set_reqkey_keyring -1]
|
397
|
+
end
|
398
|
+
|
399
|
+
# Get the persistent keyring for a user.
|
400
|
+
#
|
401
|
+
# @note Not every system supports persistent keyrings.
|
402
|
+
#
|
403
|
+
# Unlike the session and user keyrings, this keyring will persist once
|
404
|
+
# all login sessions have been deleted and can thus be used to carry
|
405
|
+
# authentication tokens for processes that run without user interaction,
|
406
|
+
# such as programs started by cron.
|
407
|
+
#
|
408
|
+
# The persistent keyring will be created by the kernel if it does not
|
409
|
+
# yet exist. Each time this function is called, the persistent keyring
|
410
|
+
# will have its expiration timeout reset to the value in
|
411
|
+
# +/proc/sys/kernel/keys/persistent_keyring_expiry+ (by default three
|
412
|
+
# days). Should the timeout be reached, the persistent keyring will be
|
413
|
+
# removed and everything it pins can then be garbage collected.
|
414
|
+
#
|
415
|
+
# If UID is nil then the calling process's real user ID will be used. If
|
416
|
+
# UID is not nil then {Errno::EPERM} will be raised if the user ID
|
417
|
+
# requested does not match either the caller's real or effective user
|
418
|
+
# IDs or if the calling process does not have _SetUid_ capability.
|
419
|
+
#
|
420
|
+
# If successful, a link to the persistent keyring will be added into
|
421
|
+
# +destination+.
|
422
|
+
#
|
423
|
+
# @param uid [Fixnum, nil] UID of the user for which the persistent
|
424
|
+
# keyring is requested
|
425
|
+
# @param destination [Keyring, nil] keyring to add the persistent keyring
|
426
|
+
# to
|
427
|
+
# @return [Keyring] the persistent keyring
|
428
|
+
# @raise [Errno::EPERM] not permitted to access the persistent keyring
|
429
|
+
# for the requested UID.
|
430
|
+
# @raise [Errno::ENOMEM] insufficient memory to create the persistent
|
431
|
+
# keyring or to extend +destination+.
|
432
|
+
# @raise [Errno::ENOKEY] +destination+ does not exist.
|
433
|
+
# @raise [Errno::EKEYEXPIRED] +destination+ has expired.
|
434
|
+
# @raise [Errno::EKEYREVOKED] +destination+ has been revoked.
|
435
|
+
# @raise [Errno::EDQUOT] the user does not have sufficient quota to
|
436
|
+
# extend +destination+.
|
437
|
+
# @raise [Errno::EACCES] +destination+ exists, but does not grant write
|
438
|
+
# permission to the calling process.
|
439
|
+
# @raise [Errno::EOPNOTSUPP] persistent keyrings are not supported by this
|
440
|
+
# system
|
441
|
+
def persistent uid = nil, destination = nil
|
442
|
+
Keyring.send \
|
443
|
+
:new,
|
444
|
+
Lib.keyctl_get_persistent(uid || -1, destination.to_i),
|
445
|
+
nil,
|
446
|
+
nil
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
# This module contains the additional methods included in {Keyutils::Keyring::Session}.
|
452
|
+
module SessionKeyring
|
453
|
+
# Join a different session keyring
|
454
|
+
#
|
455
|
+
# Change the session keyring to which a process is subscribed.
|
456
|
+
#
|
457
|
+
# If +name+ is nil then a new anonymous keyring will be created, and the
|
458
|
+
# process will be subscribed to that.
|
459
|
+
#
|
460
|
+
# If +name+ is provided, then if a keyring of that name is available,
|
461
|
+
# the process will attempt to subscribe to that keyring, raising an
|
462
|
+
# error if that is not permitted; otherwise a new keyring of that name
|
463
|
+
# is created and attached as the session keyring.
|
464
|
+
#
|
465
|
+
# To attach to an extant named keyring, the keyring must have search
|
466
|
+
# permission available to the calling process.
|
467
|
+
# @param name [String, nil] name of the keyring to join
|
468
|
+
# @return [Keyring] the keyring found or created
|
469
|
+
# @raise [Errno::ENOMEM] insufficient memory to create a key
|
470
|
+
# @raise [Errno::EDQUOT] the key quota for this user would be exceeded
|
471
|
+
# by creating this key or linking it to the keyring
|
472
|
+
# @raise [Errno::EACCES] the named keyring exists, but is not searchable
|
473
|
+
# by the calling process
|
474
|
+
def join name = nil
|
475
|
+
Keyring.send :new, Lib.keyctl_join_session_keyring(name), name
|
476
|
+
end
|
477
|
+
|
478
|
+
# Set the parent process's session keyring.
|
479
|
+
#
|
480
|
+
# Changes the session keyring to which the calling process's parent
|
481
|
+
# subscribes to be the that of the calling process.
|
482
|
+
#
|
483
|
+
# The keyring must have link permission available to the calling process,
|
484
|
+
# the parent process must have the same UIDs/GIDs as the calling process,
|
485
|
+
# and the LSM must not reject the replacement. Furthermore, this may not
|
486
|
+
# be used to affect init or a kernel thread.
|
487
|
+
#
|
488
|
+
# Note that the replacement will not take immediate effect upon the parent
|
489
|
+
# process, but will rather be deferred to the next time it returns to
|
490
|
+
# userspace from kernel space.
|
491
|
+
#
|
492
|
+
# @return [Keyring] self
|
493
|
+
# @raise [Errno::ENOMEM] insufficient memory to create a key.
|
494
|
+
# @raise [Errno::EPERM] the credentials of the parent don't match those of
|
495
|
+
# the caller.
|
496
|
+
# @raise [Errno::EACCES] the named keyring exists, but is not linkable by
|
497
|
+
# the calling process.
|
498
|
+
def to_parent
|
499
|
+
Lib.keyctl_session_to_parent
|
500
|
+
self
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
KeyTypes[:keyring] = Keyring
|
505
|
+
|
506
|
+
class Keyring
|
507
|
+
# thread-specific keyring
|
508
|
+
Thread = Keyring.new Lib::KEY_SPEC[:THREAD_KEYRING], nil
|
509
|
+
|
510
|
+
# process-specific keyring
|
511
|
+
Process = Keyring.new Lib::KEY_SPEC[:PROCESS_KEYRING], nil
|
512
|
+
|
513
|
+
# session-specific keyring
|
514
|
+
# @see Keyutils::SessionKeyring
|
515
|
+
Session = Keyring.new(Lib::KEY_SPEC[:SESSION_KEYRING], nil).
|
516
|
+
extend SessionKeyring
|
517
|
+
|
518
|
+
# UID-specific keyring
|
519
|
+
User = Keyring.new Lib::KEY_SPEC[:USER_KEYRING], nil
|
520
|
+
|
521
|
+
# UID-session keyring
|
522
|
+
UserSession = Keyring.new Lib::KEY_SPEC[:USER_SESSION_KEYRING], nil
|
523
|
+
|
524
|
+
# GID-specific keyring
|
525
|
+
Group = Keyring.new Lib::KEY_SPEC[:GROUP_KEYRING], nil
|
526
|
+
end
|
527
|
+
end
|