1##############################################################################
2#
3# Copyright (c) 2010 Zope Foundation and Contributors.
4# All Rights Reserved.
5#
6# This software is subject to the provisions of the Zope Public License,
7# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11# FOR A PARTICULAR PURPOSE.
12#
13##############################################################################
14
15# Test user and groups options
16
17from zope.testing import setupstack
18import doctest
19import mock
20import os
21import sys
22import zdaemon.zdctl
23
24
25def write(name, text):
26    with open(name, 'w') as f:
27        f.write(text)
28
29
30class O:
31    def __init__(self, **kw):
32        self.__dict__.update(kw)
33
34
35def test_user_fails_when_not_root():
36    """
37
38    >>> write('conf',
39    ... '''
40    ... <runner>
41    ...   program sleep 9
42    ...   user zope
43    ... </runner>
44    ... ''')
45
46    >>> with mock.patch('os.geteuid') as geteuid:
47    ...   with mock.patch('sys.stderr'):
48    ...     sys.stderr = sys.stdout
49    ...     geteuid.return_value = 42
50    ...     try:
51    ...         zdaemon.zdctl.main(['-C', 'conf', 'status'])
52    ...     except SystemExit:
53    ...         pass
54    ...     else:
55    ...         print('oops')
56    ... # doctest: +ELLIPSIS
57    Error: only root can use -u USER to change users
58    For help, use ... -h
59
60    >>> import pwd
61    >>> pwd.getpwnam.assert_called_with('zope')
62
63    """
64
65
66def test_user_sets_supplemtary_groups():
67    """
68
69    >>> write('conf',
70    ... '''
71    ... <runner>
72    ...   program sleep 9
73    ...   user zope
74    ... </runner>
75    ... ''')
76
77    >>> import grp
78    >>> grp.getgrall.return_value = [
79    ...   O(gr_gid=8, gr_mem =['g', 'zope', ]),
80    ...   O(gr_gid=1, gr_mem =['a', 'x', ]),
81    ...   O(gr_gid=2, gr_mem =['b', 'x', 'zope']),
82    ...   O(gr_gid=5, gr_mem =['c', 'x', ]),
83    ...   O(gr_gid=4, gr_mem =['d', 'x', ]),
84    ...   O(gr_gid=3, gr_mem =['e', 'x', 'zope', ]),
85    ...   O(gr_gid=6, gr_mem =['f', ]),
86    ...   O(gr_gid=7, gr_mem =['h', ]),
87    ... ]
88
89    >>> with mock.patch('sys.exit'):
90    ...     zdaemon.zdctl.main(['-C', 'conf', 'status'])
91    daemon manager not running
92
93    >>> import pwd, os
94    >>> os.geteuid.assert_called_with()
95    >>> pwd.getpwnam.assert_called_with('zope')
96    >>> grp.getgrall.assert_called_with()
97    >>> os.setuid.assert_called_with(99)
98    >>> os.setgid.assert_called_with(5)
99    >>> os.setgroups.assert_called_with([2, 3, 8])
100
101    """
102
103
104def test_do_nothing_if_effective_user_is_configured_user():
105    """
106
107    >>> write('conf',
108    ... '''
109    ... <runner>
110    ...   program sleep 9
111    ...   user zope
112    ... </runner>
113    ... ''')
114
115    >>> with mock.patch('os.geteuid') as geteuid:
116    ...   with mock.patch('sys.exit'):
117    ...     geteuid.return_value = 99
118    ...     zdaemon.zdctl.main(['-C', 'conf', 'status'])
119    ...     os.geteuid.assert_called_with()
120    daemon manager not running
121
122    >>> import pwd, os, grp
123    >>> pwd.getpwnam.assert_called_with('zope')
124    >>> _ = grp.getgrall.assert_not_called()
125    >>> _ = os.setuid.assert_not_called()
126    >>> _ = os.setgid.assert_not_called()
127    >>> _ = os.setgroups.assert_not_called()
128
129    """
130
131
132def setUp(test):
133    setupstack.setUpDirectory(test)
134    getpwname = setupstack.context_manager(test, mock.patch('pwd.getpwnam'))
135    getpwname.return_value = O(pw_gid=5, pw_uid=99, pw_name='zope')
136    setupstack.context_manager(test, mock.patch('os.geteuid')).return_value = 0
137    setupstack.context_manager(test, mock.patch('grp.getgrall'))
138    setupstack.context_manager(test, mock.patch('os.setgroups'))
139    setupstack.context_manager(test, mock.patch('os.setuid'))
140    setupstack.context_manager(test, mock.patch('os.setgid'))
141
142
143def test_suite():
144    return doctest.DocTestSuite(setUp=setUp, tearDown=setupstack.tearDown)
145