1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2008 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.org
8 
9   $Id$
10 
11   This program is free software which we release under the GNU General Public
12   License. You may redistribute and/or modify this program under the terms
13   of that license as published by the Free Software Foundation; either
14   version 2 of the License, or (at your option) any later version.
15 
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20 
21   To get a copy of the GNU General Public License, write to the Free Software
22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 
24 */
25 
26 #include "config.h"
27 #include "global.h"
28 #include "utils.h"
29 #include "utils_no_qt.h"
30 
31 #include "FirewallInstallerCisco.h"
32 #include "instDialog.h"
33 #include "SSHPIX.h"
34 #include "SSHIOS.h"
35 #include "SSHNXOS.h"
36 #include "Configlet.h"
37 
38 #include "fwbuilder/Resources.h"
39 #include "fwbuilder/FWObjectDatabase.h"
40 #include "fwbuilder/Firewall.h"
41 #include "fwbuilder/XMLTools.h"
42 #include "fwbuilder/Interface.h"
43 #include "fwbuilder/Management.h"
44 #include "fwbuilder/XMLTools.h"
45 
46 #include <QFileInfo>
47 #include <QTextStream>
48 #include <QMessageBox>
49 #include <QtDebug>
50 
51 using namespace std;
52 using namespace libfwbuilder;
53 
54 
FirewallInstallerCisco(instDialog * _dlg,instConf * _cnf,const QString & _p)55 FirewallInstallerCisco::FirewallInstallerCisco(instDialog *_dlg,
56                                                instConf *_cnf, const QString &_p):
57     FirewallInstaller(_dlg, _cnf, _p)
58 {
59 //     string platform = cnf->fwobj->getStr("platform");
60 //     if (cnf->fwdir.isEmpty())
61 //     {
62 //         if (platform=="nxosacl") cnf->fwdir = "volatile:";
63 //         else cnf->fwdir = "flash:";
64 //     }
65 }
66 
packInstallJobsList(Firewall *)67 bool FirewallInstallerCisco::packInstallJobsList(Firewall*)
68 {
69     if (fwbdebug)
70         qDebug("FirewallInstallerCisco::packInstallJobList  script=%s",
71        #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
72                cnf->script.toAscii().constData());
73        #else
74                cnf->script.toLatin1().constData());
75        #endif
76     job_list.clear();
77 
78     Management *mgmt = cnf->fwobj->getManagementObject();
79     assert(mgmt!=NULL);
80     PolicyInstallScript *pis = mgmt->getPolicyInstallScript();
81     if (pis->getCommand()!="")
82     {
83         QString cmd = pis->getCommand().c_str();
84         QString args = pis->getArguments().c_str();
85         job_list.push_back(
86             instJob(RUN_EXTERNAL_SCRIPT, cmd, args));
87         inst_dlg->addToLog(QString("Run script %1 %2\n").arg(cmd).arg(args));
88         return true;
89     }
90 
91     // Load configuration file early so we can abort installation if
92     // it is not accessible
93 
94     // Note about option "install only acl, icmp, telnet, ssh, nat,
95     // global and static" for PIX. This option used to read generated
96     // config but cuts off everything before the magic comment line
97     // "!################". This way, it only read object-group,
98     // access-list, access-group, nat, static and global commands. It
99     // skipped all interface configurations, timeouts and inspector
100     // commands. It is difficult to implement now that we (can) use
101     // scp to copy configuration to the firewall. We would have to
102     // create temporary file with modified configuration in order to
103     // do this.  To avoid hassles with temporary files, we move the
104     // same function to the compiler. The checkbox moves to the
105     // "script" tab of the pix advanced settings dialog and when it is on,
106     // compiler generates the script with only acl, icmp, telnet, ssh
107     // nat,static and global commands
108     //
109     // This mode of installation is not supported on IOS at all.
110 
111     QString ff;
112     QFileInfo script_info(cnf->script);
113     if (script_info.isAbsolute()) ff = cnf->script;
114     else ff = cnf->wdir + "/" + cnf->script;
115 
116     QFile data(ff);
117     if (data.open(QFile::ReadOnly))
118     {
119         QTextStream strm(&data);
120         QString line;
121         do
122         {
123             line = strm.readLine();
124             config_lines.push_back(line.trimmed());
125         } while (!strm.atEnd());
126     } else
127     {
128         QMessageBox::critical(
129             inst_dlg, "Firewall Builder",
130             tr("Can not read generated script %1").arg(ff),
131             tr("&Continue"), QString::null,QString::null,
132             0, 1 );
133         return false;
134     }
135 
136     string platform = cnf->fwobj->getStr("platform");
137 
138     if (cnf->useSCPForRouter)
139     {
140         QMap<QString,QString> all_files;
141 
142         // readManifest() modifies cnf (assigns cnf->remote_script) !
143         if (readManifest(cnf->script, &all_files))
144         {
145             QMap<QString, QString>::iterator it;
146             for (it=all_files.begin(); it!=all_files.end(); ++it)
147             {
148                 QString local_name = it.key();
149                 QString remote_name = it.value();
150                 job_list.push_back(instJob(COPY_FILE, local_name, remote_name));
151             }
152         }
153 
154         QString cmd = getActivationCmd();
155         job_list.push_back(instJob(ACTIVATE_POLICY, cmd, ""));
156     } else
157     {
158         job_list.push_back(instJob(ACTIVATE_POLICY, cnf->script, ""));
159     }
160 
161     return true;
162 }
163 
activatePolicy(const QString &,const QString &)164 void FirewallInstallerCisco::activatePolicy(const QString&, const QString&)
165 {
166     QStringList args;
167 
168     packSSHArgs(args);
169     if (cnf->verbose) inst_dlg->displayCommand(args);
170 
171     SSHCisco *ssh_object = NULL;
172     if (cnf->fwobj->getStr("platform")=="pix" ||
173         cnf->fwobj->getStr("platform")=="fwsm")
174     {
175         ssh_object = new SSHPIX(inst_dlg,
176                                 cnf->fwobj->getName().c_str(),
177                                 args,
178                                 cnf->pwd,
179                                 cnf->epwd,
180                                 list<string>());
181     } else if (cnf->fwobj->getStr("platform")=="nxosacl")
182     {
183         ssh_object = new SSHNXOS(inst_dlg,
184                                 cnf->fwobj->getName().c_str(),
185                                 args,
186                                 cnf->pwd,
187                                 cnf->epwd,
188                                 list<string>());
189     } else   // ios
190     {
191         ssh_object = new SSHIOS(inst_dlg,
192                                 cnf->fwobj->getName().c_str(),
193                                 args,
194                                 cnf->pwd,
195                                 cnf->epwd,
196                                 list<string>());
197     }
198     /*
199      * TODO:
200      * the structure of scriptlets (command templates) for PIX and
201      * IOS is nice and generic, it uses generalized "pre_config"
202      * and "post_config" hooks in SSHPIX / SSHIOS classes. Need to
203      * do the same for Unix firewalls.
204      */
205 
206     QString cmd = "";
207     QStringList pre_config_commands;
208     QStringList post_config_commands;
209 
210     string version = cnf->fwobj->getStr("version");
211     bool version_lt_124 = XMLTools::version_compare(version, "12.4") < 0;
212     bool version_ge_124 = XMLTools::version_compare(version, "12.4") >= 0;
213 
214     string host_os = cnf->fwobj->getStr("host_OS");
215     string os_family = Resources::os_res[host_os]->
216         getResourceStr("/FWBuilderResources/Target/family");
217 
218     // installer configlets should be different for each OS, but if
219     // some OS can use the same script, it will be placed in the file
220     // under os_family name. For example:
221     // for PIX configlet is in src/res/configlets/pix_os
222     // but since fwsm and pix can use the same script and fwsm_os.xml
223     // declares family as "pix_os", it uses the same configlet.
224 
225     Configlet pre_config(host_os, os_family, "installer_commands_pre_config");
226     pre_config.removeComments();
227 
228     // test run and rollback were deprecated in 4.2.0. On Linux, BSD
229     // and PIX rollback was implemented by rebooting firewall which is
230     // too heavy-handed and it did not work on BSD at all.
231     pre_config.setVariable("test", false);
232     pre_config.setVariable("run", true);
233     pre_config.setVariable("schedule_rollback", false);
234     pre_config.setVariable("cancel_rollback", false);
235 
236     pre_config.setVariable("save_standby", cnf->saveStandby);
237     pre_config.setVariable("version_lt_124", version_lt_124);
238     pre_config.setVariable("version_ge_124", version_ge_124);
239 
240     replaceMacrosInCommand(&pre_config);
241 
242     Configlet post_config(host_os, os_family, "installer_commands_post_config");
243     post_config.removeComments();
244 
245     post_config.setVariable("test", false);
246     post_config.setVariable("run", true);
247     post_config.setVariable("schedule_rollback", false);
248     post_config.setVariable("cancel_rollback", false);
249 
250     post_config.setVariable("save_standby", cnf->saveStandby);
251     post_config.setVariable("version_lt_124", version_lt_124);
252     post_config.setVariable("version_ge_124", version_ge_124);
253 
254     replaceMacrosInCommand(&post_config);
255 
256     ssh_object->loadPreConfigCommands(
257         pre_config.expand().split("\n", QString::SkipEmptyParts) );
258 
259     ssh_object->loadPostConfigCommands(
260         post_config.expand().split("\n", QString::SkipEmptyParts) );
261 
262     Configlet activation(host_os, os_family, "installer_commands_reg_user");
263     activation.removeComments();
264 
265     replaceMacrosInCommand(&activation);
266 
267     activation.setVariable("using_scp",       cnf->useSCPForRouter);
268     activation.setVariable("not_using_scp", ! cnf->useSCPForRouter);
269 
270     activation.setVariable("using_nxos_session", cnf->useNXOSSession);
271     activation.setVariable("not_using_nxos_session", ! cnf->useNXOSSession);
272 
273     if ( ! cnf->useSCPForRouter)
274     {
275         activation.setVariable("fwbuilder_generated_configuration_lines",
276                                config_lines.join("\n"));
277     }
278 
279     ssh_object->loadActivationCommands(
280         activation.expand().split("\n", QString::SkipEmptyParts) );
281 
282     runSSHSession(ssh_object);
283 
284     return;
285 }
286 
readManifest(const QString & script,QMap<QString,QString> * all_files)287 bool FirewallInstallerCisco::readManifest(const QString &script,
288                                           QMap<QString, QString> *all_files)
289 {
290     if (fwbdebug)
291         qDebug("FirewallInstaller::readManifest");
292     QString dest_dir = getDestinationDir(cnf->fwdir);
293     // path returned by getDestinationDir always ends with separator
294     // in case of IOS, it is ":"
295     QFileInfo file_base(script);
296     QString remote_file = dest_dir + file_base.fileName();
297     qDebug() << "001 REMOTE FILE:" << remote_file;
298     QString local_name = script;
299     cnf->remote_script = remote_file;
300     (*all_files)[local_name] = remote_file;
301     return true;
302 }
303 
getDestinationDir(const QString & fwdir)304 QString FirewallInstallerCisco::getDestinationDir(const QString &fwdir)
305 {
306     if (fwbdebug)
307         qDebug() << "FirewallInstallerCisco::getDestinationDir:  "
308                  << "fwdir=" << fwdir;
309 
310     QString dir = fwdir;
311     if (!dir.endsWith(":")) return dir + ":";
312     return dir;
313 }
314 
315 
316