desktop: removed pppob path search in modem mode
[barry.git] / desktop / src / ModemDlg.cc
blob96dc881913c85748e3d539f6ad92723a5050724b
1 ///
2 /// \file ModemDlg.cc
3 /// Dialog class to handle modem functionality
4 ///
6 /*
7 Copyright (C) 2012, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "ModemDlg.h"
23 #include "windowids.h"
24 #include "exechelper.h"
25 #include "barrydesktop.h"
26 #include "tempdir.h"
27 #include <iostream>
28 #include <sstream>
29 #include <algorithm>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <grp.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <wx/dir.h>
36 #include <wx/filename.h>
37 #include <barry/barry.h>
39 using namespace std;
41 // begin wxGlade: ::extracode
42 // end wxGlade
45 ModemDlg::ModemDlg(wxWindow* parent,
46 const std::vector<std::string> &peers,
47 const std::string &default_peer)
48 : wxDialog(parent, Dialog_Modem, _T("Modem Kickstart"))
50 bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL);
52 // begin wxGlade: ModemDlg::ModemDlg
53 sizer_5_staticbox = new wxStaticBox(this, -1, wxT("Device"));
54 sizer_1_staticbox = new wxStaticBox(this, -1, wxT("Providers"));
55 const wxString list_box_1_choices[] = {
56 wxT("barry-minimal"),
57 wxT("barry-rogers"),
58 wxT("barry-testing")
60 list_box_1 = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 3, list_box_1_choices, wxLB_SINGLE);
61 label_1 = new wxStaticText(this, wxID_ANY, wxT("Password:"));
62 text_ctrl_1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD);
64 set_properties();
65 do_layout();
66 // end wxGlade
68 // add all peers to the listbox
69 list_box_1->Clear();
70 int default_index = -1, index = 0;
71 for( std::vector<std::string>::const_iterator i = peers.begin();
72 i != peers.end(); ++i, ++index )
74 if( default_peer == *i )
75 default_index = index;
76 list_box_1->Append(wxString(i->c_str(), wxConvUTF8));
79 if( default_index >= 0 ) {
80 list_box_1->SetSelection(default_index);
82 else {
83 list_box_1->SetSelection(0);
87 void ModemDlg::set_properties()
89 // begin wxGlade: ModemDlg::set_properties
90 SetTitle(wxT("Modem Starter"));
91 list_box_1->SetMinSize(wxSize(-1, 150));
92 list_box_1->SetSelection(0);
93 text_ctrl_1->SetMinSize(wxSize(150, -1));
94 // end wxGlade
98 void ModemDlg::do_layout()
100 // begin wxGlade: ModemDlg::do_layout
101 wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
102 wxBoxSizer* sizer_3 = new wxBoxSizer(wxVERTICAL);
103 wxStaticBoxSizer* sizer_5 = new wxStaticBoxSizer(sizer_5_staticbox, wxHORIZONTAL);
104 wxStaticBoxSizer* sizer_1 = new wxStaticBoxSizer(sizer_1_staticbox, wxVERTICAL);
105 sizer_1->Add(list_box_1, 0, wxEXPAND, 0);
106 sizer_3->Add(sizer_1, 0, wxEXPAND, 0);
107 sizer_5->Add(label_1, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 2);
108 sizer_5->Add(text_ctrl_1, 0, 0, 0);
109 sizer_3->Add(sizer_5, 1, wxEXPAND, 0);
110 sizer_2->Add(sizer_3, 0, wxALL|wxEXPAND, 7);
111 // end wxGlade
113 sizer_3->Add(bottom_buttons, 0, wxTOP|wxEXPAND, 5);
115 SetSizer(sizer_2);
116 sizer_2->Fit(this);
117 Layout();
121 // ProgramDetect
123 /// Searches for the given program name, in various directories, and
124 /// stores the following info:
125 /// Exists() - file exists, and if true, then:
126 /// GetPath() - returns full path of file, and:
127 /// IsExecutable() - returns true if file is a runnable program
128 /// IsSuid() - returns true if file is suid
129 /// GetGroup() - returns the group name of the file
131 /// For pppd, for example, this may return on Debian:
132 /// exists? true
133 /// path? /usr/sbin/pppd
134 /// executable? true if user in group, false if not
135 /// suid? true, suid root on Debian
136 /// group? uses the 'dip' group on Debian
138 /// On Fedora:
139 /// exists? true
140 /// path? /usr/sbin/pppd
141 /// exec? true
142 /// suid? false
143 /// group? root
145 class ProgramDetect
147 std::string m_path;
148 std::string m_group;
149 bool m_executable;
150 bool m_suid;
152 public:
153 void Dump(std::ostream &os)
155 os << "Path: " << m_path << "\n";
156 os << "Group: " << m_group << "\n";
157 os << "Exec: " << (m_executable ? "true" : "false") << "\n";
158 os << "Suid: " << (m_suid ? "true" : "false") << "\n";
161 const std::string& GetPath() const { return m_path; }
162 const std::string& GetGroup() const { return m_group; }
163 bool Exists() const { return m_path.size() > 0; }
164 bool IsExecutable() const { return m_executable; }
165 bool IsSuid() const { return m_suid; }
167 bool CheckPath(const std::string &path)
169 if( access(path.c_str(), F_OK) == 0 ) {
170 m_path = path;
171 return true;
173 return false;
176 void CheckAll(const char *prog, const std::string &path)
178 istringstream iss(path);
179 string p;
181 while( getline(iss, p, ':') ) {
182 string f = p + "/" + prog;
183 if( CheckPath(f) )
184 return;
188 ProgramDetect(const char *prog, const std::string &path)
189 : m_executable(false)
190 , m_suid(false)
192 // find the program first
193 CheckAll(prog, path);
195 // does it exist?
196 if( !m_path.size() )
197 return; // nope
199 // executable?
200 if( access(m_path.c_str(), X_OK) == 0 ) {
201 m_executable = true;
204 // suid?
205 struct stat s;
206 if( stat(m_path.c_str(), &s) == 0 ) {
207 if( s.st_mode & S_ISUID ) {
208 m_suid = true;
212 struct group *g = getgrgid(s.st_gid);
213 if( g ) {
214 m_group = g->gr_name;
220 std::string ModemDlg::GetPeerName() const
222 return string(list_box_1->GetStringSelection().utf8_str());
225 std::string ModemDlg::GetPassword() const
227 return string(text_ctrl_1->GetValue().utf8_str());
230 void ModemDlg::DoModem(wxWindow *parent, const Barry::Pin &pin)
233 // Search for dependency programs: xterm, pppd, gksu, etc.
236 // test whether xterm is in the path
237 ProgramDetect xterm("xterm", getenv("PATH"));
238 if( !xterm.Exists() || !xterm.IsExecutable() ) {
239 wxMessageBox(_T("Cannot locate the xterm program. This is used to display modem connection output. Please install it and try again."), _T("Xterm Not Found"), wxOK | wxICON_ERROR, parent);
240 return;
243 // test whether we can run pppd, probably need to use full
244 // /usr/sbin/pppd path to reach it... check for return code
245 // of 0 or 2
246 ProgramDetect pppd("pppd", "/usr/sbin:/usr/bin");
247 if( !pppd.Exists() ) {
248 wxMessageBox(_T("Cannot find pppd. Please install it for modem use."), _T("pppd Not Found"), wxOK | wxICON_ERROR, parent);
249 return;
254 // Check if we need root access to run pppd
256 string need_sudo;
258 if( pppd.IsExecutable() && pppd.IsSuid() ) {
259 // all good!
261 else if( !pppd.IsExecutable() && pppd.IsSuid() && pppd.GetGroup() != "root" ) {
262 wxString gname(pppd.GetGroup().c_str(), wxConvUTF8);
263 wxString msg = wxString::Format(_T("Your system's PPP has the suid bit set, with a group of '%s'. You should add your account to the '%s' group, to avoid the need to enter the root password every time you use the modem.\n\nContinue anyway?"), gname.c_str(), gname.c_str());
264 int choice = wxMessageBox(msg, _T("System Group"), wxYES_NO,
265 parent);
266 if( choice != wxYES )
267 return;
269 need_sudo = BARRYDESKTOP_SYSTEM_GUI_SU + string(" ");
271 else if( pppd.IsExecutable() && !pppd.IsSuid() ) {
272 need_sudo = BARRYDESKTOP_SYSTEM_GUI_SU + string(" ");
276 // Check if we can run pppd, in the non-root case
278 if( need_sudo.size() == 0 ) {
279 ExecHelper eh(0);
280 wxString cmd((pppd.GetPath() + " permission_test").c_str(), wxConvUTF8);
281 if( !eh.Run(0, "", cmd) ) {
282 wxMessageBox(_T("Internal fork error. Should never happen."), _T("Cannot Run pppd"), wxOK | wxICON_ERROR, parent);
283 return;
286 eh.WaitForChild();
287 if( !(eh.GetChildExitCode() == 0 || eh.GetChildExitCode() == 2) ) {
288 wxString msg = wxString::Format(_T("Unable to run pppd correctly. Unexpected error code: %d, %s"), eh.GetChildExitCode(), cmd.c_str());
289 wxMessageBox(msg, _T("Error Code"), wxOK | wxICON_ERROR, parent);
290 return;
295 // Load all peer files.
297 // do a search in /etc/ppp/peers for all barry-* files and
298 // store in a vector
300 std::vector<std::string> peers;
301 wxDir dir(wxString("/etc/ppp/peers", wxConvUTF8));
302 if( !dir.IsOpened() ) {
303 wxMessageBox(_T("Unable to access files in /etc/ppp/peers. Do you have the correct permissions?"), _T("Cannot Open Peers"), wxOK | wxICON_ERROR, parent);
304 return;
306 wxString filename;
307 bool cont = dir.GetFirst(&filename, _T("barry-*"), wxDIR_FILES);
308 while( cont ) {
309 peers.push_back( string(filename.utf8_str()) );
310 cont = dir.GetNext(&filename);
313 // anything available?
314 if( !peers.size() ) {
315 wxMessageBox(_T("No providers found. Make sure Barry was properly installed, with peer files in /etc/ppp/peers."), _T("No Providers"), wxOK | wxICON_ERROR, parent);
316 return;
319 // sort the vector
320 sort(peers.begin(), peers.end());
324 // Double check that we can read the peer files
327 // do an access or file open test on the first barry-* file
328 // to make sure that we have access to peers/
329 string testfile = "/etc/ppp/peers/" + peers[0];
330 if( access(testfile.c_str(), R_OK) != 0 ) {
331 wxString msg = wxString::Format(_T("Cannot read provider files under /etc/ppp/peers. Please check your file permissions. (Access failed for %s)"), wxString(testfile.c_str(), wxConvUTF8).c_str());
332 wxMessageBox(msg, _T("Permissions Error"), wxOK | wxICON_ERROR, parent);
333 return;
338 // Fetch default peer choice
340 Barry::GlobalConfigFile &config = wxGetApp().GetGlobalConfig();
341 string key = pin.Str() + "-DefaultPeer";
342 string default_peer = config.GetKey(key);
346 // Show the dialog
348 ModemDlg dlg(parent, peers, default_peer);
349 if( dlg.ShowModal() == wxID_OK ) {
350 string peer = dlg.GetPeerName();
351 string peerfile = "/etc/ppp/peers/" + peer;
352 if( !peer.size() || access(peerfile.c_str(), R_OK) != 0 ) {
353 wxString msg = wxString::Format(_T("Unable to open peer file: %s"), wxString(peerfile.c_str(), wxConvUTF8).c_str());
354 wxMessageBox(msg, _T("Invalid Peer"), wxOK | wxICON_ERROR, parent);
355 return;
358 // save peer selection as default for this device
359 config.SetKey(key, peer);
361 // create shell script which calls pppd
362 TempDir tempdir("BarryDesktopModem");
363 string tmp_path = tempdir.GetNewFilename();
365 ofstream otmp(tmp_path.c_str());
366 otmp << "#!/bin/sh" << endl;
367 otmp << "echo Starting pppd for device PIN "
368 << pin.Str() << "... " << endl;
370 ostringstream cmdoss;
371 cmdoss << need_sudo << pppd.GetPath() << " call " << peer;
373 // show command with echo too
374 otmp << "echo" << endl;
375 otmp << "echo '" << cmdoss.str() << "'" << endl;
376 otmp << cmdoss.str() << endl;
378 otmp << "echo Press enter to close window..." << endl;
379 otmp << "read" << endl;
380 otmp.close();
382 chmod(tmp_path.c_str(), S_IRUSR | S_IRGRP | S_IROTH |
383 S_IXUSR | S_IXGRP | S_IXOTH);
385 // create command line using xterm as display
386 wxString xterm_cmd((xterm.GetPath() + " " + tmp_path).c_str(),
387 wxConvUTF8);
389 // setup argument fifo
390 Barry::FifoArgs args;
391 args.m_password = dlg.GetPassword();
392 args.m_pin = pin;
393 Barry::FifoServer fifo(args);
395 // run! and go back to main screen
396 ExecHelper run(0);
397 run.Run(parent, "modem", xterm_cmd);
399 fifo.Serve(5);