We have created our own .sshd
SCR Agent in the
previous section. Let's see how we can use it in our project.
In this section, we will modify the scr/Sshd.ycp
YCP module.
As we could have seen during testing the .sshd
SCR
Agent, it returns a list of strings as values and variables are strings. So, let's
decide to create an internal variable defined as
map <string, list<string>>. Then we should know
whether the sshd daemon was running during starting the
configuration, because it this case we would have to restart it after changing the
configuration file. Add this part just below the SetModified()
function definition in the scr/Sshd.ycp
:
/** * map of SSHD settings */ map <string, list<string> > SETTINGS = $[]; map <string, list<string> > DEFAULT_CONFIG = $[ "Port" : ["22"], "AllowTcpForwarding" : ["yes"], "X11Forwarding" : ["no"], "Compression" : ["yes"], "PrintMotd" : ["yes"], "PermitRootLogin" : ["yes"], "IgnoreUserKnownHosts" : ["no"], "MaxAuthTries" : ["6"], "PasswordAuthentication" : ["yes"], "RSAAuthentication" : ["no"], "PubkeyAuthentication" : ["yes"], ];
This part also defines the DEFAULT_CONFIG with default settings which we will use instead of the current one if the current one is not explicitly defined in the configuration file.
This part describes using the SCR Agent inside the YCP Module, reading and writing the current sshd service status and calling this functionality from the major Read() and Write() functions.
Once we have the SCR Agent and the Data Model, we are about to create functions which will connect these two parts.
Into the upper part of the src/Sshd.ycp
add the import of
the SCR module:
import "SCR";
Now we can use the SCR functions.
Add this part below the PollAbort() function definition:
/** * Reads current sshd configuration */ boolean ReadSSHDSettings () { foreach (string key, (list <string>) SCR::Dir(.sshd), { list <string> val = (list <string>) SCR::Read(add(.sshd, key)); if (val != nil) SETTINGS[key] = val; }); y2milestone("SSHD configuration has been read: %1", SETTINGS); return true; } /** * Writes current sshd configuration */ boolean WriteSSHDSettings () { y2milestone("Writing SSHD configuration: %1", SETTINGS); foreach (string option_key, list <string> option_val, SETTINGS, { SCR::Write(add(.sshd, option_key), option_val); }); // This is very important // it flushes the cache, and stores the configuration on the disk SCR::Write(.sshd, nil); return true; }
The ReadSSHDSettings() function lists all already set options from the configuration file using the SCR::Dir() function, reads these options using the SCR::Read() function and if they have some value, stores them to the SETTINGS map.
The WriteSSHDSettings() function writes all variables from the SETTINGS map to the agent's writing cache using the SCR::Write() function and then sends the nil to the same function to store this configuration to the configuration file.
Below the previous functions we will also add functions for reading the current status of the sshd service and for restarting if it is needed:
/** * Reads current sshd status */ boolean ReadSSHDService () { if (Service::Status("sshd") == 0) { sshd_is_running = true; } else { sshd_is_running = false; } y2milestone((sshd_is_running ? "SSH is running":"SSH is not running")); return true; } /** * Restarts the sshd when the daemon was running when starting the configuration */ boolean WriteSSHDService () { boolean all_ok = true; if (sshd_is_running) { y2milestone("Restarting sshd daemon"); all_ok = Service::Restart("sshd"); } else { y2milestone("Sshd is not running - leaving..."); } return all_ok; }
Here is the documentation for more information about the Service module.
Then we have to change some lines in the general Read() and Write() functions to get the configuration read by starting the configuration and to get it written by finishing it.
Here are the changes:
In the Read() function:
if(false) Report::Error(Message::CannotReadCurrentSettings());
replace with:
if(!ReadSSHDSettings()) Report::Error(Message::CannotReadCurrentSettings());
and
if(false) Report::Error(_("Cannot read current SSHD state."));
replace with:
if(!ReadSSHDService()) Report::Error(_("Cannot read current SSHD state."));
In the Write() function:
if(false) Report::Error (_("Cannot write SSHD settings."));
replace with:
if(!WriteSSHDSettings()) Report::Error (_("Cannot write SSHD settings."));
and
if(false) Report::Error (Message::CannotAdjustService("sshd"));
replace with:
if(!WriteSSHDService()) Report::Error (Message::CannotAdjustService("sshd"));
/** * File: modules/Sshd.ycp * Package: Configuration of SSHD * Summary: SSHD settings, input and output functions * Authors: John The Fish <john@thesmallfish.net> * * Representation of the configuration of SSHD. * Input and output routines. */ { module "Sshd"; textdomain "sshd"; import "Progress"; import "Report"; import "Message"; import "Service"; import "Popup"; import "SCR"; /** * Data was modified? */ boolean modified = false; /** * Sleep time between Read or Write steps */ integer sl = 1000; /** * Returns whether the configuration has been modified. */ global boolean GetModified() { return modified; } /** * Sets that the configuration has been modified. */ global void SetModified() { modified = true; } /** * map of SSHD settings */ map <string, list<string> > SETTINGS = $[]; map <string, list<string> > DEFAULT_CONFIG = $[ "Port" : ["22"], "AllowTcpForwarding" : ["yes"], "X11Forwarding" : ["no"], "Compression" : ["yes"], "PrintMotd" : ["yes"], "PermitRootLogin" : ["yes"], "IgnoreUserKnownHosts" : ["no"], "MaxAuthTries" : ["6"], "PasswordAuthentication" : ["yes"], "RSAAuthentication" : ["no"], "PubkeyAuthentication" : ["yes"], ]; /** * Describes whether the daemon is running */ boolean sshd_is_running = false; /** * Returns a confirmation popup dialog whether user wants to really abort. */ global boolean Abort() { return Popup::ReallyAbort(GetModified()); } /** * Checks whether an Abort button has been pressed. * If so, calls function to confirm the abort call. * * @return boolean true if abort confirmed */ global boolean PollAbort() { if (UI::PollInput() == `abort) return Abort(); return false; } /** * Reads current sshd configuration */ boolean ReadSSHDSettings () { foreach (string key, (list <string>) SCR::Dir(.sshd), { list <string> val = (list <string>) SCR::Read(add(.sshd, key)); if (val != nil) SETTINGS[key] = val; }); y2milestone("SSHD configuration has been read: %1", SETTINGS); return true; } /** * Writes current sshd configuration */ boolean WriteSSHDSettings () { y2milestone("Writing SSHD configuration: %1", SETTINGS); foreach (string option_key, list <string> option_val, SETTINGS, { SCR::Write(add(.sshd, option_key), option_val); }); SCR::Write(.sshd, nil); return true; } /** * Reads current sshd status */ boolean ReadSSHDService () { if (Service::Status("sshd") == 0) { sshd_is_running = true; } else { sshd_is_running = false; } y2milestone((sshd_is_running ? "SSH is running":"SSH is not running")); return true; } /** * Restarts the sshd when the daemon was running when starting the configuration */ boolean WriteSSHDService () { boolean all_ok = true; if (sshd_is_running) { y2milestone("Restarting sshd daemon"); all_ok = Service::Restart("sshd"); } else { y2milestone("Sshd is not running - leaving..."); } return all_ok; } /** * Read all SSHD settings * @return true on success */ global boolean Read() { /* SSHD read dialog caption */ string caption = _("Initializing SSHD Configuration"); integer steps = 2; Progress::New( caption, " ", steps, [ /* Progress stage 1/2 */ _("Read current SSHD configuration"), /* Progress stage 2/2 */ _("Read current SSHD state") ], [ /* Progress step 1/2 */ _("Reading current SSHD configuration..."), /* Progress step 2/2 */ _("Reading current SSHD state..."), /* Progress finished */ Message::Finished() ], "" ); sleep(sl); if(PollAbort()) return false; Progress::NextStage(); /* Error message */ if(!ReadSSHDSettings()) Report::Error(Message::CannotReadCurrentSettings()); sleep(sl); if(PollAbort()) return false; Progress::NextStep(); /* Error message */ if(!ReadSSHDService()) Report::Error(_("Cannot read current SSHD state.")); sleep(sl); if(PollAbort()) return false; Progress::NextStage (); sleep(sl); modified = false; return true; } /** * Write all SSHD settings * @return true on success */ global boolean Write() { /* SSHD read dialog caption */ string caption = _("Saving SSHD Configuration"); integer steps = 2; Progress::New(caption, " ", steps, [ /* Progress stage 1/2 */ _("Write the SSHD settings"), /* Progress stage 2/2 */ _("Adjust the SSHD service") ], [ /* Progress step 1/2 */ _("Writing the SSHD settings..."), /* Progress step 2/2 */ _("Adjusting the SSHD service..."), Message::Finished() ], "" ); sleep(sl); if(PollAbort()) return false; Progress::NextStage(); /* Error message */ if(!WriteSSHDSettings()) Report::Error (_("Cannot write SSHD settings.")); sleep(sl); if(PollAbort()) return false; Progress::NextStage (); /* Error message */ if(!WriteSSHDService()) Report::Error (Message::CannotAdjustService("sshd")); sleep(sl); Progress::NextStage (); sleep(sl); return true; } }
By now, we have finished implementing the Read() and Write() functions and we should check the syntax of the the source code. This can be done by running command: /usr/bin/ycpc -E Sshd.ycp. Eventual syntax errors must be fixed.
After you finish editing the src/Sshd.ycp
, run
sudo make install to get it compiled and installed into the system.
Now you can check the progress as mentioned in the section Checking the Progress again. You should find the most important changes in the YaST log as mentioned in the section Watching YaST Logs.