Opensource Systemadmin module

Hi,

i’ve created a module that can be used to administer the system. This module consists of some php-files to set some system-settings through the Admin-Interface of the PBX and some binary files (c++ code), which do the changes. As most of the changes can only be done by root, these binaries need to be owned by root and have the setuid-bit enabled.

To prevent regular users with shell access to the PBX system from changing system settings, the module creates an entry in a MySQL table containing the “section” and the current timestamp when it is accessed through the admin interface. The corresponding binary checks before making changes whether such an entry has been created in the appropriate table within a certain time frame and only executes the changes if it finds such an entry. So for example if you change the IP address through the Web-Interface, the module creates an entry in the table with the section “network” and the current timestamp and then executes the corresponding binary. This binary checks if an entry with the section “netowrk” and a timestamp within a configurable time frame exists. If so, then these changes are applied.

The following changes could be done through this module so far:

  • Network Settings (support for ifupdown, network-manager, systemd-networkd and netplan)
    – IPv4 and IPv6 assignment method
    – IPv4/v6 Address, Netmask and Gateway
    – Ipv6 Autoconf enabled/disabled
    – Accept IPv6 Router Advertisment (enabled/disabled)
  • DNS (if /etc/resolv.conf is updated through another program (e.g. systemd-resolved), this module is aware of this and does not change /etc/resolv.conf directly)
    – Change name servers
    – Change dns search list
  • Change Hostname/Domainname
  • Change Timezone
  • Notification Settings*
    – Change sender email address
    – Change Storage email-address
  • eMail Configuration (Currently, only Postfix is supported)
    – Send email via remote or directly via local MTA
    – Support for TLS encryption
    – Use authentication when sending mail via remote MTA (yes/no)
  • Power management
    – Shut down
    – Restart
  • Packet Capture (via tcpdump)
    – Start/Stop/Download/Delete capture
  • Storage
    – View current disk space used
    – Support for different raid-levels including sync-status and spare devices
    – Sends a warning email when the used storage exceeds a configurable threshold

*Since some (all?) modules which send email rely on the function sysadmin_get_storage_email, this setting is currently not recognized by these modules. Either these modules would need to be revised to work with the open-source version, or an alias function would need to be created in the open-source module.

Since I am not a software developer and only program for fun in my spare time, I cannot support the module as much as it needs. Therefore, the module would need to be supported and further developed also by others/the community.

Any thoughts on that? Do you think this is a nice/needed module? Any comments are appreciated.

Best regards,
Hannes

4 Likes

Sounds interesting. Where is this module at for review, etc?

Hi,
Since the module is still in an early alpha version, please only use/test it in a development environment.

The module itself is available at GitHub - hannes427/systemadmin_php. The C++ source code can be viewed at GitHub - hannes427/sysadmin.

Where are the files in /usr/local/freepbx being installed from?

So far, you have to compile the binaries yourself. I think the simplest option for the future would be to provide a deb package that can be easily downloaded/installed with apt-get install from a repository.

You can compile it on debian using the following commands:

su -c 'apt install cmake libboost-program-options-dev'
git clone https://github.com/hannes427/sysadmin
cd sysadmin
cmake CMakeLists.txt -DCMAKE_INSTALL_PREFIX=/usr/local/freepbx
cmake --build .
su -c 'mkdir /usr/local/freepbx'
su -c 'cmake --install .'
su -c 'chmod u+s /usr/local/freepbx/bin/*'
su -c 'cp -rp php /usr/local/freepbx'
1 Like

I like.
If the goal is to replace the curent sysadmin module, there is many modules calling methods to sysadmin. There’s a risk of breaking other modules. Be careful. Even if there is only commercial modules are calling sysadmin. But some other modules could use sysadmin too.

You can scan all methods used in sysadmin module and compare them.

If the goal is to add another module sysadmin, yes…

Where will this be cloned to? Anywhere on the local drive?

Why do I need binaries for this? Seems a bit overkill to have to compile a binary just to edit/create Postfix or other options in System Admin.

Overall it looks decent but needs a lot of clean of up the code and moving around of some of the code. So I need to understand why binaries are being used for things that don’t need them. Is that due to skill/knowledge level?

Thank you for the comments so far.

@franck.danard: It was intended as an open-source replacement for the Sysadmin module. Initially, I was just curious about how Sangoma addresses the “problem” of unprivileged users not being able to change system settings. So, I looked at the “unencrypted” part of the Sysadmin module. This happened to be shortly before many people expressed concerns about the future of FreePBX, and there was significant criticism regarding how Sangoma was handling the community, with some members receiving temporary bans in the FreePBX forum. This, combined with the fact that with closed-source software, you never know what “extra-steps” are taken by the software or if some information might be sent to the developer (e.g. during an update), led to the idea of creating an open-source version.

Regarding your concerns: As far as I know, commercial modules can only be installed if you’re using FreePBX and have the supported operating system (CentOS for FreePBX 16 and Debian 12 for FreePBX 17) installed. In those cases, you can certainly use Sangoma’s Sysadmin module as well. From what I can see, the open-source modules check whether Sysadmin is enabled or if the functions provided by the Sysadmin module exist. For example, the Backup module does this when it needs to send an email after a backup. It checks if the function sysadminget storage_email is defined, and if so, it uses the configured sender address. Otherwise, it defaults to a general email address (freepbx@freepbx.local). This happens regardless of whether the open-source version is installed or not. Therefore, I don’t see how installing the module could break anything—unless I’ve overlooked something.

@airsay Since the files are only needed during compilation, they can be cloned “anywhere.” So maybe it is a good idea to do a “cd /tmp/” before cloning. As mentioned above, I believe the simplest solution for the future would be for someone to provide a Debian repository for the binaries, from which the package could be downloaded. This would be similar to how Sangoma provides the Debian packages sangoma-pbx17, freepbx17 and sysadmin17. Of course, this would only happen if someone wants to support or further develop my module. The advantage would be that updates (bug fixes or new features) for the binaries would be installed automatically with a system update. Another option would be to make the binaries available for download on a web server and develop a different update routine. I haven’t looked into it closely, but that seems to me how incrediblepbx operates. When you log in as root, incrediblepbx checks for updates, downloads them, and installs them.

@AMI These binaries are necessary to change System-Settings as an unprivileged user. The webserver is run as an unprivileged user (in FreePBX normally the user “asterisk”) and all commands, which are run through the Webinterface, are run by this user with its privileges. Normally, an unprivileged user is not allowed to change System-Settings or run certain commands (e.g. reboot the system or execute tcpdump). So you have to find a way, that the user asterisk is allowed to do these things. In my opinion there are 3 ways:

  • The “Sangoma way”: Some parts are obfuscated so not the full process can be reviewed. But it seems to me that the unprivileged user asterisk writes a file to a special directory, where it has write privileges (/var/spool/asterisk/incron). This file does not contain the actual commands needed to change the respective system setting; instead, it only contains the information about what should be changed (e.g., that the IP address of the interface eth0 should be changed to the specified IP). Sangoma has written a program that is executed by the incron service as the root user whenever a file is written to the directory /var/spool/asterisk/incron. This program then parses the file written to /var/spool/asterisk/incron and executes the necessary commands as root. I am not a lawyer, but I am unsure whether it is a good idea to copy it almost 1:1. And you have to make sure, that nobody can inject “bad code” to the file written in /var/spool/asterisk/incron (e.g. “rm -rf /”).
  • Use sudo. You could change the module’s php-files to run the necessary command through sudo and configure sudo so that the user asterisk is allowed to run these commands. The downside of this is, that on some linux-derivates (e.g. Debian) sudo is not installed by default and i am unsure whether there are linux-derivates where sudo is not even available. And you would have to make sure, that the sudo setttings can’t be exploited. There are some Blog-Posts about how some changes in the sudo-config can be exploited (e.g. Dangerous Sudoers Entries – PART 1: Command Execution – Compass Security Blog and the following posts).
  • Use Binaries with setuid-Bit enabled. As I mentioned above, programs are usually executed with the permissions of the user running them. However, this is different in Unix/Linux when the setuid bit is set for a program. In that case, the program runs with the privileges of the user who owns the program. Since the binaries belong to root, they are executed with root privileges, allowing an unprivileged user to change system settings. This is the way i used. This way is used in some cases in Linux-Derivates. For example, if an unprivileged user wants to change the password, the command “passwd” hast the setuid-bit enabled. This is because the program passwd needs to write the new password to the file /etc/shadow. Since the file is write-protected for regular users for good reason, the program passwd`must be executed with root privileges. This is accomplished using the setUID bit.

Can you give me a hint, which parts of the code need clean up/needs to be moved around?

Hannes

The unprivileged user is a PITA, I’m not sure the option that lets any unprivileged user make system level changes is the best of them though. But that’s just my thought.

It lacks comments, there’s some structure formatting that needs fixing, I’m not 100% on how you are handling the form submissions and there are instances where you do $_POST[something] instead of $_POST['something'] which can cause issues.

A lot of it is just making it look cleaner and easier to work with. One of the problems I have with the FreePBX project is how they have really ignored code standards both internally and with contributions. I’d just like to not see that here.

How do you mean that? Do you mean that no unprivileged user should be allowed to change system settings or do you mean that if the binaries have the setuid bit enabled, any unprivileged user can make those changes? Or do you mean something else?

If you mean the former how would you solve the problem? Would you divide it into the parts ‘Defining the Changes’ in the web interface (as an unprivileged user) and ‘Applying the Changes’ (as root)? For example, like Sangoma did with incron? Or would you simply say that there should be no option in the web interface to change system settings and neither Sangoma’s Sysadmin nor the open-source module should be used/endorsed?" Or would you use some other methods?

If you mean the second: It was planned that not every user with shell access could chnage these settings. To achieve that the binaries should check if an entry for the changes exists in a MySQL Table (–> someone with access to the web interface requested the changes). You can see that in the source-code of the packet capture c++ code (sysadmin/packet_capture.cpp at master · hannes427/sysadmin · GitHub). This part of the code is currently commented out for development reasons, and the PHP files are not yet creating entries in the corresponding MySQL table. I’m still unsure what the best approach is for the programs to access the MySQL table: Should they parse the file /etc/freepbx.conf to use the credentials of the freepbx user, or should an additional MySQL user with a random password be created during the installation of the Debian package, with the password written to a file that only root can read, and the binaries read the password from that file? But it should be easy to add this function and then an user must have write access to the MySQL-Table or must have access to the web interface.

1 Like

I’ve spun up a new TangoPBX instance and ran your install and these errors crop up:

-- Build files have been written to: /root/sysadmin
[  3%] Building CXX object CMakeFiles/packet_capture.dir/packet_capture.cpp.o
[  6%] Building CXX object CMakeFiles/packet_capture.dir/functions.cpp.o
/root/sysadmin/functions.cpp:10:10: fatal error: mariadb/mysql.h: No such file or directory
   10 | #include <mariadb/mysql.h>
      |          ^~~~~~~~~~~~~~~~~
compilation terminated.
gmake[2]: *** [CMakeFiles/packet_capture.dir/build.make:90: CMakeFiles/packet_capture.dir/functions.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:101: CMakeFiles/packet_capture.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2
-- Install configuration: ""
CMake Error at cmake_install.cmake:52 (file):
  file INSTALL cannot find "/root/sysadmin/packet_capture": No such file or
  directory.


chmod: cannot access '/usr/local/freepbx/bin/*': No such file or directory
root@newcloud4:~/sysadmin#

Post the exact steps you took. That directory doesn’t exist unless you create yourself.

Installed TangoPBX. Logged in as root.`
``
cd /tmp
su -c ‘apt install cmake libboost-program-options-dev’
git clone GitHub - hannes427/sysadmin
cd sysadmin
cmake CMakeLists.txt -DCMAKE_INSTALL_PREFIX=/usr/local/freepbx
cmake --build .
su -c ‘mkdir /usr/local/freepbx’
su -c ‘cmake --install .’
su -c ‘chmod u+s /usr/local/freepbx/bin/*’
su -c ‘cp -rp php /usr/local/freepbx’


Results:

su -c ‘apt install cmake libboost-program-options-dev’
git clone GitHub - hannes427/sysadmin
cd sysadmin
cmake CMakeLists.txt -DCMAKE_INSTALL_PREFIX=/usr/local/freepbx
cmake --build .
su -c ‘mkdir /usr/local/freepbx’
su -c ‘cmake --install .’
su -c ‘chmod u+s /usr/local/freepbx/bin/*’
su -c ‘cp -rp php /usr/local/freepbx’
Reading package lists… Done
Building dependency tree… Done
Reading state information… Done
libboost-program-options-dev is already the newest version (1.74.0.3ubuntu7).
cmake is already the newest version (3.22.1-1ubuntu1.22.04.2).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Cloning into ‘sysadmin’…
remote: Enumerating objects: 133, done.
remote: Counting objects: 100% (133/133), done.
remote: Compressing objects: 100% (96/96), done.
remote: Total 133 (delta 63), reused 99 (delta 33), pack-reused 0 (from 0)
Receiving objects: 100% (133/133), 46.19 KiB | 4.62 MiB/s, done.
Resolving deltas: 100% (63/63), done.
– The C compiler identification is GNU 11.4.0
– The CXX compiler identification is GNU 11.4.0
– Detecting C compiler ABI info
– Detecting C compiler ABI info - done
– Check for working C compiler: /usr/bin/cc - skipped
– Detecting C compile features
– Detecting C compile features - done
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info - done
– Check for working CXX compiler: /usr/bin/c++ - skipped
– Detecting CXX compile features
– Detecting CXX compile features - done
– Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake (found version “1.74.0”) found components: program_options
– Configuring done
– Generating done
– Build files have been written to: /tmp/sysadmin
[ 3%] Building CXX object CMakeFiles/packet_capture.dir/packet_capture.cpp.o
[ 6%] Building CXX object CMakeFiles/packet_capture.dir/functions.cpp.o
/tmp/sysadmin/functions.cpp:10:10: fatal error: mariadb/mysql.h: No such file or directory
10 | #include <mariadb/mysql.h>
| ^~~~~~~~~~~~~~~~~
compilation terminated.
gmake[2]: *** [CMakeFiles/packet_capture.dir/build.make:90: CMakeFiles/packet_capture.dir/functions.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:101: CMakeFiles/packet_capture.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2
mkdir: cannot create directory ‘/usr/local/freepbx’: File exists
– Install configuration: “”
CMake Error at cmake_install.cmake:52 (file):
file INSTALL cannot find “/tmp/sysadmin/packet_capture”: No such file or
directory.

chmod: cannot access ‘/usr/local/freepbx/bin/*’: No such file or directory

You’re missing something here. Probably a dev library from mariadb, so that needs to be solved. The rest looks like something with the code being compiled.

I believe the issue is a difference in install directory locations for FreePBX open source only vs. the FreePBX packaged install version.

What do you mean by the packaged version? What are you referring to there?

On the FreePBX site, they offer this:
https://sangomakb.atlassian.net/wiki/spaces/FP/pages/230326391/FreePBX+17+Installation

I encourage others to spin up a TangoPBX instance for themselves to test with.

Right, that’s the official install process. It’s not a package.