1from k5test import *
2import os
3
4realm = K5Realm(create_host=False, create_user=False)
5
6def make_client(name):
7    global realm
8    realm.addprinc(name, password(name))
9    ccache = os.path.join(realm.testdir,
10                          'kadmin_ccache_' + name.replace('/', '_'))
11    realm.kinit(name, password(name),
12                flags=['-S', 'kadmin/admin', '-c', ccache])
13    return ccache
14
15def kadmin_as(client, query, **kwargs):
16    global realm
17    return realm.run([kadmin, '-c', client] + query, **kwargs)
18
19all_add = make_client('all_add')
20all_changepw = make_client('all_changepw')
21all_delete = make_client('all_delete')
22all_inquire = make_client('all_inquire')
23all_list = make_client('all_list')
24all_modify = make_client('all_modify')
25all_rename = make_client('all_rename')
26all_wildcard = make_client('all_wildcard')
27all_extract = make_client('all_extract')
28some_add = make_client('some_add')
29some_changepw = make_client('some_changepw')
30some_delete = make_client('some_delete')
31some_inquire = make_client('some_inquire')
32some_modify = make_client('some_modify')
33some_rename = make_client('some_rename')
34restricted_add = make_client('restricted_add')
35restricted_modify = make_client('restricted_modify')
36restricted_rename = make_client('restricted_rename')
37wctarget = make_client('wctarget')
38admin = make_client('user/admin')
39none = make_client('none')
40restrictions = make_client('restrictions')
41onetwothreefour = make_client('one/two/three/four')
42
43realm.run([kadminl, 'addpol', '-minlife', '1 day', 'minlife'])
44
45f = open(os.path.join(realm.testdir, 'acl'), 'w')
46f.write('''
47all_add            a
48all_changepw       c
49all_delete         d
50all_inquire        i
51all_list           l
52all_modify         im
53all_rename         ad
54all_wildcard       x
55all_extract        ie
56some_add           a   selected
57some_changepw      c   selected
58some_delete        d   selected
59some_inquire       i   selected
60some_modify        im  selected
61some_rename        d   from
62some_rename        a   to
63restricted_add     a   *         +preauth
64restricted_modify  im  *         +preauth
65restricted_rename  ad  *         +preauth
66
67*/*                d   *2/*1
68# The next line is a regression test for #8154; it is not used directly.
69one/*/*/five       l
70*/two/*/*          d   *3/*1/*2
71*/admin            a
72wctarget           a   wild/*
73restrictions       a   type1     -policy minlife
74restrictions       a   type2     -clearpolicy
75restrictions       a   type3     -maxlife 1h -maxrenewlife 2h
76''')
77f.close()
78
79realm.start_kadmind()
80
81# cpw can generate four different RPC calls depending on options.
82realm.addprinc('selected', 'oldpw')
83realm.addprinc('unselected', 'oldpw')
84for pw in (['-pw', 'newpw'], ['-randkey']):
85    for ks in ([], ['-e', 'aes256-cts']):
86        mark('cpw: %s %s' % (repr(pw), repr(ks)))
87        args = pw + ks
88        kadmin_as(all_changepw, ['cpw'] + args + ['unselected'])
89        kadmin_as(some_changepw, ['cpw'] + args + ['selected'])
90        msg = "Operation requires ``change-password'' privilege"
91        kadmin_as(none, ['cpw'] + args + ['selected'], expected_code=1,
92                  expected_msg=msg)
93        kadmin_as(some_changepw, ['cpw'] + args + ['unselected'],
94                  expected_code=1, expected_msg=msg)
95        kadmin_as(none, ['cpw'] + args + ['none'])
96        realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none'])
97        msg = "Current password's minimum life has not expired"
98        kadmin_as(none, ['cpw'] + args + ['none'], expected_code=1,
99                  expected_msg=msg)
100        realm.run([kadminl, 'modprinc', '-clearpolicy', 'none'])
101realm.run([kadminl, 'delprinc', 'selected'])
102realm.run([kadminl, 'delprinc', 'unselected'])
103
104mark('addpol')
105kadmin_as(all_add, ['addpol', 'policy'])
106realm.run([kadminl, 'delpol', 'policy'])
107kadmin_as(none, ['addpol', 'policy'], expected_code=1,
108          expected_msg="Operation requires ``add'' privilege")
109
110# addprinc can generate two different RPC calls depending on options.
111for ks in ([], ['-e', 'aes256-cts']):
112    mark('addprinc: %s' % repr(ks))
113    args = ['-pw', 'pw'] + ks
114    kadmin_as(all_add, ['addprinc'] + args + ['unselected'])
115    realm.run([kadminl, 'delprinc', 'unselected'])
116    kadmin_as(some_add, ['addprinc'] + args + ['selected'])
117    realm.run([kadminl, 'delprinc', 'selected'])
118    kadmin_as(restricted_add, ['addprinc'] + args + ['unselected'])
119    realm.run([kadminl, 'getprinc', 'unselected'],
120              expected_msg='REQUIRES_PRE_AUTH')
121    realm.run([kadminl, 'delprinc', 'unselected'])
122    kadmin_as(none, ['addprinc'] + args + ['selected'], expected_code=1,
123              expected_msg="Operation requires ``add'' privilege")
124    kadmin_as(some_add, ['addprinc'] + args + ['unselected'], expected_code=1,
125              expected_msg="Operation requires ``add'' privilege")
126
127mark('delprinc')
128realm.addprinc('unselected', 'pw')
129kadmin_as(all_delete, ['delprinc', 'unselected'])
130realm.addprinc('selected', 'pw')
131kadmin_as(some_delete, ['delprinc', 'selected'])
132realm.addprinc('unselected', 'pw')
133kadmin_as(none, ['delprinc', 'unselected'], expected_code=1,
134          expected_msg="Operation requires ``delete'' privilege")
135kadmin_as(some_delete, ['delprinc', 'unselected'], expected_code=1,
136          expected_msg="Operation requires ``delete'' privilege")
137realm.run([kadminl, 'delprinc', 'unselected'])
138
139mark('getpol')
140kadmin_as(all_inquire, ['getpol', 'minlife'], expected_msg='Policy: minlife')
141kadmin_as(none, ['getpol', 'minlife'], expected_code=1,
142          expected_msg="Operation requires ``get'' privilege")
143realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none'])
144kadmin_as(none, ['getpol', 'minlife'], expected_msg='Policy: minlife')
145realm.run([kadminl, 'modprinc', '-clearpolicy', 'none'])
146
147mark('getprinc')
148realm.addprinc('selected', 'pw')
149realm.addprinc('unselected', 'pw')
150kadmin_as(all_inquire, ['getprinc', 'unselected'],
151          expected_msg='Principal: unselected@KRBTEST.COM')
152kadmin_as(some_inquire, ['getprinc', 'selected'],
153          expected_msg='Principal: selected@KRBTEST.COM')
154kadmin_as(none, ['getprinc', 'selected'], expected_code=1,
155          expected_msg="Operation requires ``get'' privilege")
156kadmin_as(some_inquire, ['getprinc', 'unselected'], expected_code=1,
157          expected_msg="Operation requires ``get'' privilege")
158kadmin_as(none, ['getprinc', 'none'],
159          expected_msg='Principal: none@KRBTEST.COM')
160realm.run([kadminl, 'delprinc', 'selected'])
161realm.run([kadminl, 'delprinc', 'unselected'])
162
163mark('listprincs')
164kadmin_as(all_list, ['listprincs'], expected_msg='K/M@KRBTEST.COM')
165kadmin_as(none, ['listprincs'], expected_code=1,
166          expected_msg="Operation requires ``list'' privilege")
167
168mark('getstrs')
169realm.addprinc('selected', 'pw')
170realm.addprinc('unselected', 'pw')
171realm.run([kadminl, 'setstr', 'selected', 'key', 'value'])
172realm.run([kadminl, 'setstr', 'unselected', 'key', 'value'])
173kadmin_as(all_inquire, ['getstrs', 'unselected'], expected_msg='key: value')
174kadmin_as(some_inquire, ['getstrs', 'selected'], expected_msg='key: value')
175kadmin_as(none, ['getstrs', 'selected'], expected_code=1,
176          expected_msg="Operation requires ``get'' privilege")
177kadmin_as(some_inquire, ['getstrs', 'unselected'], expected_code=1,
178          expected_msg="Operation requires ``get'' privilege")
179kadmin_as(none, ['getstrs', 'none'], expected_msg='(No string attributes.)')
180realm.run([kadminl, 'delprinc', 'selected'])
181realm.run([kadminl, 'delprinc', 'unselected'])
182
183mark('modpol')
184out = kadmin_as(all_modify, ['modpol', '-maxlife', '1 hour', 'policy'],
185                expected_code=1)
186if 'Operation requires' in out:
187    fail('modpol success (acl)')
188kadmin_as(none, ['modpol', '-maxlife', '1 hour', 'policy'], expected_code=1,
189          expected_msg="Operation requires ``modify'' privilege")
190
191mark('modprinc')
192realm.addprinc('selected', 'pw')
193realm.addprinc('unselected', 'pw')
194kadmin_as(all_modify, ['modprinc', '-maxlife', '1 hour',  'unselected'])
195kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'selected'])
196kadmin_as(restricted_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'])
197realm.run([kadminl, 'getprinc', 'unselected'],
198          expected_msg='REQUIRES_PRE_AUTH')
199kadmin_as(all_inquire, ['modprinc', '-maxlife', '1 hour', 'selected'],
200          expected_code=1,
201          expected_msg="Operation requires ``modify'' privilege")
202kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'],
203          expected_code=1, expected_msg='Operation requires')
204realm.run([kadminl, 'delprinc', 'selected'])
205realm.run([kadminl, 'delprinc', 'unselected'])
206
207mark('purgekeys')
208realm.addprinc('selected', 'pw')
209realm.addprinc('unselected', 'pw')
210kadmin_as(all_modify, ['purgekeys', 'unselected'])
211kadmin_as(some_modify, ['purgekeys', 'selected'])
212kadmin_as(none, ['purgekeys', 'selected'], expected_code=1,
213          expected_msg="Operation requires ``modify'' privilege")
214kadmin_as(some_modify, ['purgekeys', 'unselected'], expected_code=1,
215          expected_msg="Operation requires ``modify'' privilege")
216kadmin_as(none, ['purgekeys', 'none'])
217realm.run([kadminl, 'delprinc', 'selected'])
218realm.run([kadminl, 'delprinc', 'unselected'])
219
220mark('renprinc')
221realm.addprinc('from', 'pw')
222kadmin_as(all_rename, ['renprinc', 'from', 'to'])
223realm.run([kadminl, 'renprinc', 'to', 'from'])
224kadmin_as(some_rename, ['renprinc', 'from', 'to'])
225realm.run([kadminl, 'renprinc', 'to', 'from'])
226kadmin_as(all_add, ['renprinc', 'from', 'to'], expected_code=1,
227          expected_msg="Insufficient authorization for operation")
228kadmin_as(all_delete, ['renprinc', 'from', 'to'], expected_code=1,
229          expected_msg="Insufficient authorization for operation")
230kadmin_as(some_rename, ['renprinc', 'from', 'notto'], expected_code=1,
231          expected_msg="Insufficient authorization for operation")
232realm.run([kadminl, 'renprinc', 'from', 'notfrom'])
233kadmin_as(some_rename, ['renprinc', 'notfrom', 'to'], expected_code=1,
234          expected_msg="Insufficient authorization for operation")
235kadmin_as(restricted_rename, ['renprinc', 'notfrom', 'to'], expected_code=1,
236          expected_msg="Insufficient authorization for operation")
237realm.run([kadminl, 'delprinc', 'notfrom'])
238
239mark('setstr')
240realm.addprinc('selected', 'pw')
241realm.addprinc('unselected', 'pw')
242kadmin_as(all_modify, ['setstr', 'unselected', 'key', 'value'])
243kadmin_as(some_modify, ['setstr', 'selected', 'key', 'value'])
244kadmin_as(none, ['setstr', 'selected',  'key', 'value'], expected_code=1,
245          expected_msg="Operation requires ``modify'' privilege")
246kadmin_as(some_modify, ['setstr', 'unselected', 'key', 'value'],
247          expected_code=1, expected_msg='Operation requires')
248realm.run([kadminl, 'delprinc', 'selected'])
249realm.run([kadminl, 'delprinc', 'unselected'])
250
251mark('addprinc/delprinc (wildcard)')
252kadmin_as(admin, ['addprinc', '-pw', 'pw', 'anytarget'])
253realm.run([kadminl, 'delprinc', 'anytarget'])
254kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card'])
255realm.run([kadminl, 'delprinc', 'wild/card'])
256kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card/extra'],
257          expected_code=1, expected_msg='Operation requires')
258realm.addprinc('admin/user', 'pw')
259kadmin_as(admin, ['delprinc', 'admin/user'])
260kadmin_as(admin, ['delprinc', 'none'], expected_code=1,
261          expected_msg='Operation requires')
262realm.addprinc('four/one/three', 'pw')
263kadmin_as(onetwothreefour, ['delprinc', 'four/one/three'])
264
265mark('addprinc (restrictions)')
266kadmin_as(restrictions, ['addprinc', '-pw', 'pw', 'type1'])
267realm.run([kadminl, 'getprinc', 'type1'], expected_msg='Policy: minlife')
268realm.run([kadminl, 'delprinc', 'type1'])
269kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-policy', 'minlife',
270                         'type2'])
271realm.run([kadminl, 'getprinc', 'type2'], expected_msg='Policy: [none]')
272realm.run([kadminl, 'delprinc', 'type2'])
273kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxlife', '1 minute',
274                         'type3'])
275out = realm.run([kadminl, 'getprinc', 'type3'])
276if ('Maximum ticket life: 0 days 00:01:00' not in out or
277    'Maximum renewable life: 0 days 02:00:00' not in out):
278    fail('restriction (maxlife low, maxrenewlife unspec)')
279realm.run([kadminl, 'delprinc', 'type3'])
280kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxrenewlife', '1 day',
281                         'type3'])
282realm.run([kadminl, 'getprinc', 'type3'],
283          expected_msg='Maximum renewable life: 0 days 02:00:00')
284
285mark('extract')
286realm.run([kadminl, 'addprinc', '-pw', 'pw', 'extractkeys'])
287kadmin_as(all_wildcard, ['ktadd', '-norandkey', 'extractkeys'],
288          expected_code=1,
289          expected_msg="Operation requires ``extract-keys'' privilege")
290kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'])
291realm.kinit('extractkeys', flags=['-k'])
292os.remove(realm.keytab)
293
294mark('lockdown_keys')
295kadmin_as(all_modify, ['modprinc', '+lockdown_keys', 'extractkeys'])
296kadmin_as(all_changepw, ['cpw', '-pw', 'newpw', 'extractkeys'],
297          expected_code=1,
298          expected_msg="Operation requires ``change-password'' privilege")
299kadmin_as(all_changepw, ['cpw', '-randkey', 'extractkeys'])
300kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'], expected_code=1,
301          expected_msg="Operation requires ``extract-keys'' privilege")
302kadmin_as(all_delete, ['delprinc', 'extractkeys'], expected_code=1,
303          expected_msg="Operation requires ``delete'' privilege")
304kadmin_as(all_rename, ['renprinc', 'extractkeys', 'renamedprinc'],
305          expected_code=1,
306          expected_msg="Operation requires ``delete'' privilege")
307kadmin_as(all_modify, ['modprinc', '-lockdown_keys', 'extractkeys'],
308          expected_code=1,
309          expected_msg="Operation requires ``modify'' privilege")
310realm.run([kadminl, 'modprinc', '-lockdown_keys', 'extractkeys'])
311kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'])
312realm.kinit('extractkeys', flags=['-k'])
313os.remove(realm.keytab)
314
315# Verify that self-service key changes require an initial ticket.
316mark('self-service initial ticket')
317realm.run([kadminl, 'cpw', '-pw', password('none'), 'none'])
318realm.run([kadminl, 'modprinc', '+allow_tgs_req', 'kadmin/admin'])
319realm.kinit('none', password('none'))
320realm.run([kvno, 'kadmin/admin'])
321msg = 'Operation requires initial ticket'
322realm.run([kadmin, '-c', realm.ccache, 'cpw', '-pw', 'newpw', 'none'],
323          expected_code=1, expected_msg=msg)
324realm.run([kadmin, '-c', realm.ccache, 'cpw', '-pw', 'newpw',
325           '-e', 'aes256-cts', 'none'], expected_code=1, expected_msg=msg)
326realm.run([kadmin, '-c', realm.ccache, 'cpw', '-randkey', 'none'],
327          expected_code=1, expected_msg=msg)
328realm.run([kadmin, '-c', realm.ccache, 'cpw', '-randkey', '-e', 'aes256-cts',
329           'none'], expected_code=1, expected_msg=msg)
330
331# Test authentication to kadmin/hostname.
332mark('authentication to kadmin/hostname')
333kadmin_hostname = 'kadmin/' + hostname
334realm.addprinc(kadmin_hostname)
335realm.run([kadminl, 'delprinc', 'kadmin/admin'])
336msgs = ('Getting initial credentials for user/admin@KRBTEST.COM',
337        'Setting initial creds service to kadmin/admin',
338        '/Server not found in Kerberos database',
339        'Getting initial credentials for user/admin@KRBTEST.COM',
340        'Setting initial creds service to ' + kadmin_hostname,
341        'Decrypted AS reply')
342realm.run([kadmin, '-p', 'user/admin', 'listprincs'], expected_code=1,
343          expected_msg="Operation requires ``list'' privilege",
344          input=password('user/admin'), expected_trace=msgs)
345
346# Test operations disallowed at the libkadm5 layer.
347realm.run([kadminl, 'delprinc', 'K/M'],
348          expected_code=1, expected_msg='Cannot change protected principal')
349realm.run([kadminl, 'cpw', '-pw', 'pw', 'kadmin/history'],
350          expected_code=1, expected_msg='Cannot change protected principal')
351
352success('kadmin ACL enforcement')
353