LCOV - code coverage report
Current view: top level - snapdev - as_root.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 13 100.0 %
Date: 2022-07-09 19:51:09 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2016-2022  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/snapdev
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      19             : #pragma once
      20             : 
      21             : // self
      22             : //
      23             : #include    <snapdev/not_used.h>
      24             : 
      25             : 
      26             : // C++
      27             : //
      28             : #include    <algorithm>
      29             : #include    <string>
      30             : #include    <type_traits>
      31             : 
      32             : 
      33             : 
      34             : namespace snapdev
      35             : {
      36             : 
      37             : 
      38             : 
      39             : /** \brief Safely become root and back.
      40             :  *
      41             :  * This class defines a way to become root and then come back as the
      42             :  * original user one your work requiring root is done.
      43             :  *
      44             :  * The class uses RAII so when an object of that type gets destroyed,
      45             :  * it automatically restore the user. You can also restore the user
      46             :  * sooner if safer.
      47             :  *
      48             :  * This class is used only when a process is given root as the owner
      49             :  * of the file and when the set user identifier flag is set on the
      50             :  * executable (a.k.a. `chmod u+s /usr/bin/my-tool`).
      51             :  *
      52             :  * The class constructor attempts the change to root. If that fails,
      53             :  * the valid() function returns false. It is likely important that
      54             :  * you verified whether the user change worked or not to make sure
      55             :  * that you can run the following commands as root.
      56             :  *
      57             :  * The class can be used recursively. So if function A uses as_root,
      58             :  * then calls function B which also uses as_root, the second time
      59             :  * the switch will do nothing since you are already root. Function A
      60             :  * will stil properly restore the user to the normal user instead of
      61             :  * root.
      62             :  *
      63             :  * The class is only expected to be used on the stack. If you use it
      64             :  * in an object, then the restore may not work as expected (i.e. it
      65             :  * could happen in the wrong order).
      66             :  */
      67             : class as_root
      68             : {
      69             : public:
      70             :     /** \brief Save the current user then switch to root.
      71             :      *
      72             :      * This function switches us to the root user. If that fails,
      73             :      * then the valid() function will return false. You can get
      74             :      * the exact error using the error_number() function.
      75             :      *
      76             :      * The destructor will automatically revert back to your
      77             :      * original user.
      78             :      */
      79           1 :     as_root()
      80           1 :         : f_user_uid(getuid())
      81             :     {
      82           1 :         if(seteuid(0) != 0)
      83             :         {
      84           1 :             f_errno = errno;
      85             :         }
      86           1 :     }
      87             : 
      88             :     /** \brief Restore the user as it was on construction.
      89             :      *
      90             :      * This function restores the user as found in the construtor. If
      91             :      * the constructor could not switch to root, then the function fails.
      92             :      */
      93           1 :     ~as_root()
      94           1 :     {
      95           1 :         if(f_errno == 0)
      96             :         {
      97             :             NOT_USED(seteuid(f_user_uid));  // LCOV_EXCL_LINE -- our unit tests cannot switch to root user
      98             :         }
      99           1 :     }
     100             : 
     101             :     /** \brief Check whether the as_root object is considered valid.
     102             :      *
     103             :      * The constructor of the function attempts to switch to the root
     104             :      * user. If the function fails, then the errno value is saved.
     105             :      * This function checks that error, if not zero, then the switch
     106             :      * to the root user did not happen so the as_root object is not
     107             :      * considered valid.
     108             :      *
     109             :      * To get the actual error number, use the error_number() function.
     110             :      *
     111             :      * \return true if the constructor worked and thus we are root.
     112             :      *
     113             :      * \sa error_number()
     114             :      */
     115           1 :     bool valid() const
     116             :     {
     117           1 :         return f_errno == 0;
     118             :     }
     119             : 
     120             :     /** \brief Get the error number.
     121             :      *
     122             :      * The constructor saves the error number of the seteuid() function
     123             :      * fails. That error number can be retrieved using this function.
     124             :      * If you do not call any other system function, the errno variable
     125             :      * will still be set to the correct value, however, you must use
     126             :      * the valid() function to make sure that an error actually occurred.
     127             :      *
     128             :      * \return The errno as set by the seteuid() on an error, otherwise 0.
     129             :      */
     130           1 :     int error_number() const
     131             :     {
     132           1 :         return f_errno;
     133             :     }
     134             : 
     135             : private:
     136             :     /** \brief The user UID on entry.
     137             :      *
     138             :      * The constructor saves the current user identifier so we can restore
     139             :      * it on exit. This may be 0 if you use the object multiple times in
     140             :      * a recursive manner.
     141             :      */
     142             :     uid_t       f_user_uid = 0;
     143             : 
     144             :     /** \brief The error number.
     145             :      *
     146             :      * If the seteuid() found in the constructor fails, then this value is
     147             :      * set to the errno parameter as set by the seteuid() function.
     148             :      *
     149             :      * By default, the value is 0 which means that the seteuid() function
     150             :      * suceeded in changing the user identifier to the root user identifier.
     151             :      */
     152             :     int         f_errno = 0;
     153             : };
     154             : 
     155             : 
     156             : 
     157             : } // namespace snapdev
     158             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13