File: sudo.rst

package info (click to toggle)
python-sh 2.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 900 kB
  • sloc: python: 4,157; makefile: 25
file content (149 lines) | stat: -rw-r--r-- 4,370 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
.. _sudo:

Using Sudo
==========

There are 3 ways of using ``sudo`` to execute commands in your script.  These
are listed in order of usefulness and security.  In most cases, you should just
use a variation of :ref:`contrib_sudo`.

.. _contrib_sudo:

sh.contrib.sudo
---------------

Because ``sudo`` is so frequently used, we have added a contrib version of the
command to make sudo usage more intuitive.  This contrib version is simply a
wrapper around the :ref:`sudo_raw` raw command, but we bake in some
:ref:`special keyword argument <special_arguments>` to make it well-behaved.  In
particular, the contrib version allows you to specify your password at execution
time via terminal input, or as a string in your script.

Terminal Input
^^^^^^^^^^^^^^

Via a :ref:`with context <with_contexts>`:

.. code-block:: python

    import sh

    with sh.contrib.sudo:
        print(ls("/root"))

Or alternatively via :ref:`subcommands <subcommands>`:

.. code-block:: python

    import sh
    print(sh.contrib.sudo.ls("/root"))

Output:

.. code-block:: none

    [sudo] password for youruser: *************
    your_root_files.txt

In the above example, ``sh.contrib.sudo`` automatically asks you for a password
using :func:`getpass.getpass` under the hood.

This method is the most secure, because it lowers the chances of doing something
insecure, like including your password in your python script, or by saying that
a particular user can execute anything inside of a particular script (the
NOPASSWD method).

.. note::

    ``sh.contrib.sudo`` does not do password caching like the sudo binary does.
    Thie means that each time a sudo command is run in your script, you will be
    asked to type in a password.

String Input
^^^^^^^^^^^^

You may also specify your password to ``sh.contrib.sudo`` as a string:

.. code-block:: python

    import sh

    password = get_your_password()

    with sh.contrib.sudo(password=password, _with=True):
        print(ls("/root"))

.. warning::

    This method is less secure because it becomes tempting to hard-code your
    password into the python script, and that's a bad idea.  However, it is more
    flexible, because it allows you to obtain your password from another source,
    so long as the end result is a string.

/etc/sudoers NOPASSWD
---------------------

With this method, you can use the raw ``sh.sudo`` command directly, because
you're being guaranteed that the system will not ask you for a password.  It
first requires you set up your user to have root execution privileges

Edit your sudoers file:

.. code-block:: none

    $> sudo visudo

Add or edit the line describing your user's permissions:

.. code-block:: none

    yourusername ALL = (root) NOPASSWD: /path/to/your/program

This says ``yourusername`` on ``ALL`` hosts will be able to run as root, but
only root ``(root)`` (no other users), and that no password ``NOPASSWD`` will be
asked of ``/path/to/your/program``.

.. warning::
    
    This method can be insecure if an unprivileged user can edit your script,
    because the entire script will be exited as a privileged user.  A malicious
    user could put something bad in this script.

.. _sudo_raw:

sh.sudo
-------

Using the raw command ``sh.sudo`` (which resolves directly to the system's
``sudo`` binary) without NOPASSWD is possible, provided you wire up the special
keyword arguments on your own to make it behave correctly.  This method is
discussed generally for educational purposes; if you take the time to wire up
``sh.sudo`` on your own, then you have in essence just recreated
:ref:`contrib_sudo`.

.. code-block:: python

    import sh

    # password must end in a newline
    my_password = "password\n"

    # -S says "get the password from stdin"
    my_sudo = sh.sudo.bake("-S", _in=my_password)

    print(my_sudo.ls("root"))

_fg=True
--------

Another less-obvious way of using sudo is by executing the raw ``sh.sudo``
command but also putting it in the foreground.  This way, sudo will work
correctly automatically, by hooking up stdin/out/err automatically, and by
asking you for a password if it requires one.  The downsides of using
:ref:`_fg=True <fg>`, however, are that you cannot capture its output -- everything is
just printed to your terminal as if you ran it from a shell.

.. code-block:: python

    import sh
    sh.sudo.ls("/root", _fg=True)