3 /// Class for passing command line arguments via fifo instead
8 Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
31 #include <sys/types.h>
41 //////////////////////////////////////////////////////////////////////////////
44 std::ostream
& FifoArgs::Write(std::ostream
&os
) const
47 os
<< "Pin " << m_pin
.Str() << endl
;
48 if( m_password
.size() )
49 os
<< "Password " << m_password
<< endl
;
50 if( m_log_filename
.size() )
51 os
<< "LogFilename " << m_log_filename
<< endl
;
52 if( m_use_serial_mode
)
53 os
<< "UseSerialMode" << endl
;
55 os
<< "Verbose" << endl
;
60 std::istream
& FifoArgs::Read(std::istream
&is
)
62 string line
, token
, arg
;
67 while( getline(is
, line
) ) {
68 istringstream
iss(line
);
73 else if( token
== "Password" )
74 getline(iss
, m_password
);
75 else if( token
== "LogFilename" )
76 getline(iss
, m_log_filename
);
77 else if( token
== "UseSerialMode" )
78 m_use_serial_mode
= true;
79 else if( token
== "Verbose" )
86 void FifoArgs::Clear()
90 m_log_filename
.clear();
91 m_use_serial_mode
= false;
96 //////////////////////////////////////////////////////////////////////////////
99 FifoServer::FifoServer(const FifoArgs
&args
)
103 int m_fifo
= mkfifo(BARRY_FIFO_NAME
, 0660);
105 throw ErrnoError(_("Cannot open Barry argument fifo"), errno
);
109 FifoServer::~FifoServer()
114 bool FifoServer::Serve(int timeout_sec
)
119 // man fifo(7) says that opening write-only in non-blocking mode
120 // will fail until the other side opens for read. So continue
121 // to attempt opens until out of time.
123 while( timeout_sec
-- ) {
124 // attempt to open in non-blocking mode
128 // This should be safe from symlink attacks, since
129 // mkfifo(), in the constructor, will fail if any other
130 // file or symlink already exists, and therefore we will
131 // never get to this open() call if that fails. And if
132 // mkfifo() succeeds, then we are guaranteed (assuming /tmp
133 // permissions are correct) that only root or our own
134 // user can replace the fifo with something else, such
137 // The server side is not intended to run as root, yet
138 // if it is, then we are still safe, due to the above logic.
139 // The client side can run as root (depending on what pppd
140 // does with pppob), and has no control over creation of
141 // the fifo, but only opens it for reading, never for
142 // creation or writing. (See FifoClient() below.)
144 // Therefore, we can only be attacked, via symlink,
145 // by root or ourselves.
147 int fd
= open(BARRY_FIFO_NAME
, O_WRONLY
| O_NONBLOCK
);
155 int written
= write(fd
, oss
.str().data(), oss
.str().size());
158 // only success if we wrote all the data
159 return written
== (int)oss
.str().size();
166 void FifoServer::Cleanup()
169 unlink(BARRY_FIFO_NAME
);
175 //////////////////////////////////////////////////////////////////////////////
178 FifoClient::FifoClient()
182 /// Tries to open the fifo and read the arguments from it.
183 /// If it fails in any way, or timeout, returns false.
184 bool FifoClient::Fetch(int timeout_sec
)
186 // See man fifo(7). Should always succeed, as long as
187 // the file exists and permissions allow.
188 int fd
= open(BARRY_FIFO_NAME
, O_RDONLY
| O_NONBLOCK
);
194 while( timeout_sec
-- ) {
196 int r
= read(fd
, buf
, sizeof(buf
));
199 // only consider this the end of file if
200 // we've already read something, otherwise we close
201 // before the server has a chance to speak up
219 istringstream
iss(sbuf
);