1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // frmHbaConfig.cpp - Backend access configuration tool
9 //
10 //////////////////////////////////////////////////////////////////////////
11 
12 
13 #include "pgAdmin3.h"
14 
15 #ifdef __WXMSW__
16 #include <io.h>
17 #include <fcntl.h>
18 #endif
19 
20 #include <wx/imaglist.h>
21 
22 #include "ctl/ctlMenuToolbar.h"
23 #include "frm/frmHbaConfig.h"
24 #include "dlg/dlgHbaConfig.h"
25 #include "frm/frmMain.h"
26 #include "utils/utffile.h"
27 #include "schema/pgServer.h"
28 #include "frm/menu.h"
29 #include "utils/pgfeatures.h"
30 
31 #define CTL_CFGVIEW 345
32 
33 #include <wx/arrimpl.cpp>
34 WX_DEFINE_OBJARRAY(pgHbaConfigLineArray);
35 
36 
BEGIN_EVENT_TABLE(frmHbaConfig,frmConfig)37 BEGIN_EVENT_TABLE(frmHbaConfig, frmConfig)
38 	EVT_MENU(MNU_UNDO,                      frmHbaConfig::OnUndo)
39 	EVT_MENU(MNU_DELETE,					frmHbaConfig::OnDelete)
40 	EVT_MENU(MNU_CONTENTS,                  frmHbaConfig::OnContents)
41 	EVT_LIST_ITEM_ACTIVATED(CTL_CFGVIEW,    frmHbaConfig::OnEditSetting)
42 	EVT_LIST_ITEM_SELECTED(CTL_CFGVIEW,     frmHbaConfig::OnSelectSetting)
43 END_EVENT_TABLE()
44 
45 #define BACE_TITLE _("Backend Access Configuration Editor")
46 
47 
48 frmHbaConfig::frmHbaConfig(frmMain *parent, pgServer *server)
49 	: frmConfig(parent, BACE_TITLE, 0)
50 {
51 	wxString applicationname = appearanceFactory->GetLongAppName() + _(" - Configuration Editor");
52 	if (server)
53 		conn = server->CreateConn(wxEmptyString, 0, applicationname);
54 	Init();
55 
56 	if (conn)
57 	{
58 		serverFileName = conn->ExecuteScalar(wxT("SHOW hba_file"));
59 		if (serverFileName == wxT("unset") || serverFileName.IsEmpty())
60 			serverFileName = wxT("pg_hba.conf");
61 
62 		wxString txt;
63 		txt.Printf(_(" - %s on %s (%s:%d)"),
64 		           serverFileName.c_str(), server->GetDescription().c_str(),
65 		           server->GetName().c_str(), server->GetPort());
66 		SetTitle(BACE_TITLE + txt);
67 
68 		wxString str;
69 		str = conn->ExecuteScalar(wxT("SELECT pg_file_read('") + serverFileName + wxT("', 0, ")
70 		                          wxT("pg_file_length('") + serverFileName + wxT("'))"));
71 
72 		DisplayFile(str);
73 
74 		statusBar->SetStatusText(wxString::Format(_(" Configuration read from %s"), conn->GetHost().c_str()));
75 	}
76 }
77 
78 
frmHbaConfig(const wxString & title,const wxString & configFile)79 frmHbaConfig::frmHbaConfig(const wxString &title, const wxString &configFile)
80 	: frmConfig(title + wxT(" - ") + _("Backend Access Configuration Editor"), configFile)
81 {
82 
83 	Init();
84 
85 	OpenLastFile();
86 }
87 
88 
~frmHbaConfig()89 frmHbaConfig::~frmHbaConfig()
90 {
91 }
92 
93 
Init()94 void frmHbaConfig::Init()
95 {
96 	appearanceFactory->SetIcons(this);
97 
98 	InitFrame(wxT("frmHbaConfig"));
99 	RestorePosition(150, 150, 650, 300, 300, 200);
100 
101 
102 	listEdit = new ctlListView(this, CTL_CFGVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
103 	listEdit->SetImageList(configImageList, wxIMAGE_LIST_SMALL);
104 
105 	listEdit->AddColumn(_("Type"), 40);
106 	listEdit->AddColumn(_("Database"), 80);
107 	listEdit->AddColumn(_("User"), 80);
108 	listEdit->AddColumn(_("IP-Address"), 100);
109 	listEdit->AddColumn(_("Method"), 40);
110 	listEdit->AddColumn(_("Option"), 100);
111 
112 	helpMenu->Enable(MNU_HINT, false);
113 	toolBar->EnableTool(MNU_HINT, false);
114 
115 	editMenu->Enable(MNU_DELETE, false);
116 	toolBar->EnableTool(MNU_DELETE, false);
117 }
118 
119 
OnSelectSetting(wxListEvent & event)120 void frmHbaConfig::OnSelectSetting(wxListEvent &event)
121 {
122 	// Enable delete because an item has been selected
123 	if (event.GetIndex() != listEdit->GetItemCount() - 1)
124 	{
125 		editMenu->Enable(MNU_DELETE, true);
126 		toolBar->EnableTool(MNU_DELETE, true);
127 	}
128 	else
129 	{
130 		editMenu->Enable(MNU_DELETE, false);
131 		toolBar->EnableTool(MNU_DELETE, false);
132 	}
133 
134 	// Disable undo because we don't want to undo the wrong line.
135 	editMenu->Enable(MNU_UNDO, false);
136 	toolBar->EnableTool(MNU_UNDO, false);
137 }
138 
139 
DisplayFile(const wxString & str)140 void frmHbaConfig::DisplayFile(const wxString &str)
141 {
142 	lines.Empty();
143 
144 	filetype = wxTextFileType_Unix;
145 	wxStringTokenizer strtok;
146 
147 	if (str.Find('\r') >= 0)
148 	{
149 		if (str.Find(wxT("\n\r")) >= 0 || str.Find(wxT("\r\n")))
150 			filetype = wxTextFileType_Dos;
151 		else
152 			filetype = wxTextFileType_Mac;
153 
154 		strtok.SetString(wxTextBuffer::Translate(str, wxTextFileType_Unix), wxT("\n"), wxTOKEN_RET_EMPTY);
155 	}
156 	else
157 		strtok.SetString(str, wxT("\n"), wxTOKEN_RET_EMPTY);
158 
159 	while (strtok.HasMoreTokens())
160 	{
161 		pgHbaConfigLine *line = new pgHbaConfigLine(strtok.GetNextToken());
162 		lines.Add(line);
163 	}
164 
165 	listEdit->DeleteAllItems();
166 
167 	size_t i = lines.GetCount();
168 
169 	// make sure the last line is empty
170 
171 	for (i = 0 ; i < lines.GetCount() ; i++)
172 	{
173 		pgHbaConfigLine &line = lines.Item(i);
174 		const wxChar *connTypeStr = line.GetConnectType();
175 		if ((line.isValid || (!line.isValid && !line.isComment)) && !line.GetText().IsEmpty())
176 		{
177 			int imgIndex = 0;
178 			if (!line.isComment)
179 				imgIndex = 1;
180 			long pos = listEdit->AppendItem(imgIndex, connTypeStr, line.database, line.user);
181 			listEdit->SetItem(pos, 3, line.ipaddress);
182 			listEdit->SetItem(pos, 4, line.GetMethod());
183 			listEdit->SetItem(pos, 5, line.option);
184 
185 			line.item = pos;
186 		}
187 	}
188 	if (!i || !lines.Item(i - 1).text.IsEmpty())
189 	{
190 		pgHbaConfigLine *line = new pgHbaConfigLine();
191 		lines.Add(line);
192 		line->item = listEdit->AppendItem(0, wxString(wxEmptyString));
193 	}
194 }
195 
196 
WriteFile(pgConn * conn)197 void frmHbaConfig::WriteFile(pgConn *conn)
198 {
199 	wxString str;
200 	size_t i;
201 	for (i = 0 ; i < lines.GetCount() - 1 ; i++)
202 		str.Append(lines.Item(i).GetText() + wxT("\n"));
203 
204 	if (DoWriteFile(str, conn))
205 	{
206 		changed = false;
207 		fileMenu->Enable(MNU_SAVE, false);
208 		editMenu->Enable(MNU_UNDO, false);
209 		toolBar->EnableTool(MNU_SAVE, false);
210 		toolBar->EnableTool(MNU_UNDO, false);
211 
212 		// make intermediate change current
213 		for (i = 0 ; i < lines.GetCount() ; i++)
214 			lines.Item(i).Init(lines.Item(i).GetText());
215 	}
216 }
217 
218 
GetHintString()219 wxString frmHbaConfig::GetHintString()
220 {
221 	wxString hint;
222 	return hint;
223 }
224 
225 
GetHelpPage() const226 wxString frmHbaConfig::GetHelpPage() const
227 {
228 	wxString page = wxT("client-authentication");
229 	return page;
230 }
231 
232 
OnContents(wxCommandEvent & event)233 void frmHbaConfig::OnContents(wxCommandEvent &event)
234 {
235 	DisplayHelp(wxT("index"), HELP_PGADMIN);
236 }
237 
238 
OnUndo(wxCommandEvent & ev)239 void frmHbaConfig::OnUndo(wxCommandEvent &ev)
240 {
241 	int pos = listEdit->GetSelection();
242 	if (pos >= 0)
243 	{
244 		size_t i;
245 		for (i = 0 ; i < lines.GetCount() ; i++)
246 		{
247 			pgHbaConfigLine &line = lines.Item(i);
248 
249 			if (line.item == pos)
250 			{
251 				line.Init(line.text);
252 				UpdateDisplay(line);
253 				break;
254 			}
255 		}
256 	}
257 }
258 
OnDelete(wxCommandEvent & event)259 void frmHbaConfig::OnDelete(wxCommandEvent &event)
260 {
261 	bool found = false;
262 	int pos = listEdit->GetSelection();
263 	if (pos >= 0)
264 	{
265 		listEdit->DeleteCurrentItem();
266 		size_t i;
267 		for (i = 0; i < lines.GetCount(); i++)
268 		{
269 			if (lines.Item(i).item == pos)
270 			{
271 				lines.RemoveAt(i);
272 				changed = true;
273 				fileMenu->Enable(MNU_SAVE, true);
274 				editMenu->Enable(MNU_UNDO, false);
275 				editMenu->Enable(MNU_DELETE, false);
276 				toolBar->EnableTool(MNU_SAVE, true);
277 				toolBar->EnableTool(MNU_UNDO, false);
278 				toolBar->EnableTool(MNU_DELETE, false);
279 				found = true;
280 				break;
281 			}
282 		}
283 		if (found)
284 		{
285 			/* Renumber all positions */
286 			for (i = 0; i < lines.GetCount(); i++)
287 			{
288 				if (lines.Item(i).item > pos)
289 					lines.Item(i).item--;
290 			}
291 		}
292 	}
293 }
294 
295 
UpdateDisplay(pgHbaConfigLine & line)296 void frmHbaConfig::UpdateDisplay(pgHbaConfigLine &line)
297 {
298 	long pos = line.item;
299 	listEdit->SetItemImage(pos, (line.isComment ? 0 : 1));
300 	listEdit->SetItem(pos, 0, line.GetConnectType());
301 	listEdit->SetItem(pos, 1, line.database);
302 	listEdit->SetItem(pos, 2, line.user);
303 	listEdit->SetItem(pos, 3, line.ipaddress);
304 	listEdit->SetItem(pos, 4, line.GetMethod());
305 	listEdit->SetItem(pos, 5, line.option);
306 }
307 
308 
OnEditSetting(wxListEvent & event)309 void frmHbaConfig::OnEditSetting(wxListEvent &event)
310 {
311 	long pos = event.GetIndex();
312 	if (pos < 0)
313 		return;
314 
315 	size_t i;
316 
317 	for (i = 0 ; i < lines.GetCount() ; i++)
318 	{
319 		if (lines.Item(i).item == pos)
320 		{
321 			pgHbaConfigLine &line = lines.Item(i);
322 			bool isLastLine = (i == lines.GetCount() - 1 && line.isComment && !line.GetConnectType());
323 
324 			dlgHbaConfig dlg(this, &line, conn);
325 			if (dlg.Go() == wxID_OK)
326 			{
327 				UpdateDisplay(line);
328 
329 				if (isLastLine)
330 				{
331 					long pos = listEdit->AppendItem(0, wxString(wxEmptyString));
332 					pgHbaConfigLine *line = new pgHbaConfigLine();
333 					line->item = pos;
334 					lines.Add(line);
335 				}
336 				changed = true;
337 				fileMenu->Enable(MNU_SAVE, true);
338 				editMenu->Enable(MNU_UNDO, true);
339 				toolBar->EnableTool(MNU_SAVE, true);
340 				toolBar->EnableTool(MNU_UNDO, true);
341 			}
342 			break;
343 		}
344 	}
345 }
346 
347 
hbaConfigFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)348 hbaConfigFactory::hbaConfigFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
349 {
350 	mnu->Append(id, wxT("pg_hba.conf"), _("Edit server access configuration file."));
351 }
352 
353 
StartDialog(frmMain * form,pgObject * obj)354 wxWindow *hbaConfigFactory::StartDialog(frmMain *form, pgObject *obj)
355 {
356 	pgServer *server = obj->GetServer();
357 	if (server)
358 	{
359 		frmHbaConfig *frm = new frmHbaConfig(form, server);
360 		frm->Go();
361 		return frm;
362 	}
363 	return 0;
364 }
365 
366 
CheckEnable(pgObject * obj)367 bool hbaConfigFactory::CheckEnable(pgObject *obj)
368 {
369 	if (obj)
370 	{
371 		pgServer *server = obj->GetServer();
372 		if (server)
373 		{
374 			pgConn *conn = server->GetConnection();
375 			return conn && server->GetSuperUser() &&  conn->HasFeature(FEATURE_FILEREAD);
376 		}
377 	}
378 	return false;
379 }
380 
381 
hbaConfigFileFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)382 hbaConfigFileFactory::hbaConfigFileFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
383 {
384 	mnu->Append(id, _("Open pg_hba.conf..."), _("Open configuration editor with pg_hba.conf."));
385 }
386 
387 
StartDialog(frmMain * form,pgObject * obj)388 wxWindow *hbaConfigFileFactory::StartDialog(frmMain *form, pgObject *obj)
389 {
390 	frmConfig *dlg = new frmHbaConfig(form);
391 	dlg->Go();
392 	dlg->DoOpen();
393 	return dlg;
394 }
395