keyutils 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|