4 using System.Collections.Generic;
5 using System.ComponentModel;
6 using System.Windows.Forms;
7 using System.Runtime.InteropServices;
8 using System.Security.Cryptography.X509Certificates;
9 using System.Threading;
10 using System.Net.NetworkInformation;
11 using Microsoft.Win32;
12 using System.IO.Compression;
13 using System.Diagnostics;
14 using System.ServiceProcess;
15 using System.Security.AccessControl;
19 public partial class SetupWizard : Form
21 private string _TrustedFile;
25 InitializeComponent();
27 txtInstanceName.Text = Icinga2InstanceName;
30 private void FatalError(string message)
32 MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
36 private void Warning(string message)
38 MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
41 private string Icinga2InstallDir
45 RegistryKey rk = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Icinga Development Team\\ICINGA2");
50 return (string)rk.GetValue("");
54 private string Icinga2InstanceName
58 IPGlobalProperties props = IPGlobalProperties.GetIPGlobalProperties();
60 string fqdn = props.HostName;
62 if (props.DomainName != "")
63 fqdn += "." + props.DomainName;
69 private bool GetMasterHostPort(out string host, out string port)
71 foreach (ListViewItem lvi in lvwEndpoints.Items) {
72 if (lvi.SubItems.Count > 1) {
73 host = lvi.SubItems[1].Text;
74 port = lvi.SubItems[2].Text;
84 private void EnableFeature(string feature)
88 fp = File.Open(Icinga2InstallDir + String.Format("\\etc\\icinga2\\features-enabled\\{0}.conf", feature), FileMode.Create);
89 using (StreamWriter sw = new StreamWriter(fp, Encoding.ASCII)) {
91 sw.Write(String.Format("include \"../features-available/{0}.conf\"\n", feature));
99 private void SetRetrievalStatus(int pct)
101 if (InvokeRequired) {
102 Invoke((MethodInvoker)delegate { SetRetrievalStatus(pct); });
106 prgRetrieveCertificate.Value = pct;
109 private void SetConfigureStatus(int pct, string message)
111 if (InvokeRequired) {
112 Invoke((MethodInvoker)delegate { SetConfigureStatus(pct, message); });
116 prgConfig.Value = pct;
117 lblConfigStatus.Text = message;
120 private void ShowErrorText(string text)
122 if (InvokeRequired) {
123 Invoke((MethodInvoker)delegate { ShowErrorText(text); });
127 txtError.Text = text;
128 tbcPages.SelectedTab = tabError;
131 private bool RunProcess(string filename, string arguments, out string output)
133 ProcessStartInfo psi = new ProcessStartInfo();
134 psi.FileName = filename;
135 psi.Arguments = arguments;
136 psi.CreateNoWindow = true;
137 psi.UseShellExecute = false;
138 psi.RedirectStandardOutput = true;
139 psi.RedirectStandardError = true;
143 using (Process proc = Process.Start(psi)) {
144 proc.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs args) {
145 result += args.Data + "\r\n";
147 proc.OutputDataReceived += delegate(object sender, DataReceivedEventArgs args) {
148 result += args.Data + "\r\n";
150 proc.BeginOutputReadLine();
151 proc.BeginErrorReadLine();
156 if (proc.ExitCode != 0)
163 private void VerifyCertificate(string host, string port)
165 SetRetrievalStatus(25);
167 string pathPrefix = Icinga2InstallDir + "\\etc\\icinga2\\pki\\" + txtInstanceName.Text;
171 if (!File.Exists(pathPrefix + ".crt")) {
172 if (!RunProcess(Icinga2InstallDir + "\\sbin\\icinga2.exe",
173 "pki new-cert --cn \"" + txtInstanceName.Text + "\" --key \"" + pathPrefix + ".key\" --cert \"" + pathPrefix + ".crt\"",
175 ShowErrorText(output);
180 SetRetrievalStatus(50);
182 _TrustedFile = Path.GetTempFileName();
184 if (!RunProcess(Icinga2InstallDir + "\\sbin\\icinga2.exe",
185 "pki save-cert --host \"" + host + "\" --port \"" + port + "\" --key \"" + pathPrefix + ".key\" --cert \"" + pathPrefix + ".crt\" --trustedcert \"" + _TrustedFile + "\"",
187 ShowErrorText(output);
191 SetRetrievalStatus(100);
193 X509Certificate2 cert = new X509Certificate2(_TrustedFile);
194 Invoke((MethodInvoker)delegate { ShowCertificatePrompt(cert); });
197 private void ConfigureService()
199 SetConfigureStatus(0, "Updating configuration files...");
205 if (rdoNewMaster.Checked)
208 Invoke((MethodInvoker)delegate {
209 string master_host, master_port;
210 GetMasterHostPort(out master_host, out master_port);
212 args += " --master_host " + master_host + "," + master_port;
214 foreach (ListViewItem lvi in lvwEndpoints.Items) {
215 args += " --endpoint " + lvi.SubItems[0].Text;
217 if (lvi.SubItems.Count > 1)
218 args += "," + lvi.SubItems[1].Text + "," + lvi.SubItems[2].Text;
222 if (rdoListener.Checked)
223 args += " --listen ::," + txtListenerPort.Text;
225 if (chkAcceptConfig.Checked)
226 args += " --accept-config";
228 if (chkAcceptCommands.Checked)
229 args += " --accept-commands";
231 args += " --ticket " + txtTicket.Text;
232 args += " --trustedcert " + _TrustedFile;
233 args += " --cn " + txtInstanceName.Text;
234 args += " --zone " + txtInstanceName.Text;
236 if (!RunProcess(Icinga2InstallDir + "\\sbin\\icinga2.exe",
239 ShowErrorText(output);
243 SetConfigureStatus(50, "Setting ACLs for the Icinga 2 directory...");
244 DirectoryInfo di = new DirectoryInfo(Icinga2InstallDir);
245 DirectorySecurity ds = di.GetAccessControl();
246 FileSystemAccessRule rule = new FileSystemAccessRule("NT AUTHORITY\\NetworkService",
247 FileSystemRights.Modify,
248 InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow);
249 ds.AddAccessRule(rule);
250 di.SetAccessControl(ds);
252 SetConfigureStatus(75, "Installing the Icinga 2 service...");
254 RunProcess(Icinga2InstallDir + "\\sbin\\icinga2.exe",
258 if (!RunProcess(Icinga2InstallDir + "\\sbin\\icinga2.exe",
261 ShowErrorText(output);
265 if (!RunProcess(Icinga2InstallDir + "\\sbin\\icinga2.exe",
266 "--scm-install daemon",
268 ShowErrorText(output);
272 if (chkInstallNSCP.Checked)
274 SetConfigureStatus(85, "Waiting for NSClient++ installation to complete...");
276 Process proc = new Process();
277 proc.StartInfo.FileName = "msiexec.exe";
278 proc.StartInfo.Arguments = "/i \"" + Program.Icinga2InstallDir + "\\sbin\\NSCP-Win32.msi\"";
283 SetConfigureStatus(100, "Finished.");
288 private void FinishConfigure()
290 if (InvokeRequired) {
291 Invoke((MethodInvoker)FinishConfigure);
295 tbcPages.SelectedTab = tabFinish;
298 private void AgentWizard_Shown(object sender, EventArgs e)
300 string installDir = Icinga2InstallDir;
302 if (installDir == "")
303 FatalError("Icinga 2 does not seem to be installed properly.");
305 /* TODO: This is something the NSIS installer should do */
306 Directory.CreateDirectory(installDir + "\\etc\\icinga2\\pki");
307 Directory.CreateDirectory(installDir + "\\var\\cache\\icinga2");
308 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\pki");
309 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\agent\\inventory");
310 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\api\\config");
311 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\api\\log");
312 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\api\\zones");
313 Directory.CreateDirectory(installDir + "\\var\\log\\icinga2\\compat\\archive");
314 Directory.CreateDirectory(installDir + "\\var\\log\\icinga2\\crash");
315 Directory.CreateDirectory(installDir + "\\var\\run\\icinga2\\cmd");
316 Directory.CreateDirectory(installDir + "\\var\\spool\\icinga2\\perfdata");
317 Directory.CreateDirectory(installDir + "\\var\\spool\\icinga2\\tmp");
320 private void btnBack_Click(object sender, EventArgs e)
322 if (tbcPages.SelectedTab == tabError) {
323 tbcPages.SelectedIndex = 0;
329 if (tbcPages.SelectedTab == tabVerifyCertificate)
332 tbcPages.SelectedIndex -= offset;
335 private void btnNext_Click(object sender, EventArgs e)
337 if (tbcPages.SelectedTab == tabParameters) {
338 if (txtInstanceName.Text.Length == 0) {
339 Warning("Please enter an instance name.");
343 if (txtTicket.Text.Length == 0) {
344 Warning("Please enter an agent ticket.");
348 if (rdoNoMaster.Checked) {
349 if (lvwEndpoints.Items.Count == 0) {
350 Warning("You need to add at least one master endpoint.");
355 if (!GetMasterHostPort(out host, out port)) {
356 Warning("Please enter a remote host and port for at least one of your endpoints.");
361 if (rdoListener.Checked && (txtListenerPort.Text == "")) {
362 Warning("You need to specify a listener port.");
367 if (tbcPages.SelectedTab == tabFinish || tbcPages.SelectedTab == tabError)
370 tbcPages.SelectedIndex++;
373 private void btnCancel_Click(object sender, EventArgs e)
378 private void tbcPages_SelectedIndexChanged(object sender, EventArgs e)
382 btnBack.Enabled = (tbcPages.SelectedTab == tabVerifyCertificate || tbcPages.SelectedTab == tabError);
383 btnNext.Enabled = (tbcPages.SelectedTab == tabParameters || tbcPages.SelectedTab == tabVerifyCertificate || tbcPages.SelectedTab == tabFinish);
385 if (tbcPages.SelectedTab == tabFinish) {
386 btnNext.Text = "&Finish >";
387 btnCancel.Enabled = false;
390 if (tbcPages.SelectedTab == tabRetrieveCertificate) {
391 ListViewItem lvi = lvwEndpoints.Items[0];
393 string master_host, master_port;
394 GetMasterHostPort(out master_host, out master_port);
396 Thread thread = new Thread((ThreadStart)delegate { VerifyCertificate(master_host, master_port); });
400 /*if (tbcPages.SelectedTab == tabParameters &&
401 !File.Exists(Icinga2InstallDir + "\\etc\\icinga2\\pki\\agent\\agent.crt")) {
402 byte[] bytes = Convert.FromBase64String(txtBundle.Text);
403 MemoryStream ms = new MemoryStream(bytes);
404 GZipStream gz = new GZipStream(ms, CompressionMode.Decompress);
405 MemoryStream ms2 = new MemoryStream();
407 byte[] buffer = new byte[512];
409 while ((rc = gz.Read(buffer, 0, buffer.Length)) > 0)
410 ms2.Write(buffer, 0, rc);
412 TarReader tr = new TarReader(ms2);
413 tr.ReadToEnd(Icinga2InstallDir + "\\etc\\icinga2\\pki\\agent");
416 if (tbcPages.SelectedTab == tabConfigure) {
417 Thread thread = new Thread(ConfigureService);
422 private void RadioMaster_CheckedChanged(object sender, EventArgs e)
424 lvwEndpoints.Enabled = !rdoNewMaster.Checked;
425 btnAddEndpoint.Enabled = !rdoNewMaster.Checked;
426 btnRemoveEndpoint.Enabled = !rdoNewMaster.Checked && lvwEndpoints.SelectedItems.Count > 0;
429 private void RadioListener_CheckedChanged(object sender, EventArgs e)
431 txtListenerPort.Enabled = rdoListener.Checked;
434 private void AddCertificateField(string name, string shortValue, string longValue = null)
436 ListViewItem lvi = new ListViewItem();
438 lvi.SubItems.Add(shortValue);
439 if (longValue == null)
440 longValue = shortValue;
442 lvwX509Fields.Items.Add(lvi);
445 private string PadText(string input)
449 for (int i = 0; i < input.Length; i += 2) {
454 if (input.Length - i < 2)
455 len = input.Length - i;
456 output += input.Substring(i, len);
462 private void ShowCertificatePrompt(X509Certificate2 certificate)
464 txtX509Issuer.Text = certificate.Issuer;
465 txtX509Subject.Text = certificate.Subject;
467 lvwX509Fields.Items.Clear();
469 AddCertificateField("Version", "V" + certificate.Version.ToString());
470 AddCertificateField("Serial number", certificate.SerialNumber);
471 AddCertificateField("Signature algorithm", certificate.SignatureAlgorithm.FriendlyName);
472 AddCertificateField("Valid from", certificate.NotBefore.ToString());
473 AddCertificateField("Valid to", certificate.NotAfter.ToString());
475 string pkey = BitConverter.ToString(certificate.PublicKey.EncodedKeyValue.RawData).Replace("-", " ");
476 AddCertificateField("Public key", certificate.PublicKey.Oid.FriendlyName + " (" + certificate.PublicKey.Key.KeySize + " bits)", pkey);
478 string thumbprint = PadText(certificate.Thumbprint);
479 AddCertificateField("Thumbprint", thumbprint);
481 tbcPages.SelectedTab = tabVerifyCertificate;
484 private void btnAddEndpoint_Click(object sender, EventArgs e)
486 EndpointInputBox eib = new EndpointInputBox();
488 if (eib.ShowDialog(this) == DialogResult.Cancel)
491 ListViewItem lvi = new ListViewItem();
492 lvi.Text = eib.txtInstanceName.Text;
494 if (eib.chkConnect.Checked) {
495 lvi.SubItems.Add(eib.txtHost.Text);
496 lvi.SubItems.Add(eib.txtPort.Text);
499 lvwEndpoints.Items.Add(lvi);
502 private void lvwEndpoints_SelectedIndexChanged(object sender, EventArgs e)
504 btnRemoveEndpoint.Enabled = lvwEndpoints.SelectedItems.Count > 0;
507 private void lvwX509Fields_SelectedIndexChanged(object sender, EventArgs e)
509 if (lvwX509Fields.SelectedItems.Count == 0)
512 ListViewItem lvi = lvwX509Fields.SelectedItems[0];
514 txtX509Field.Text = (string)lvi.Tag;
517 private void btnRemoveEndpoint_Click(object sender, EventArgs e)
519 while (lvwEndpoints.SelectedItems.Count > 0) {
520 lvwEndpoints.Items.Remove(lvwEndpoints.SelectedItems[0]);