3 /// Class for passing command line arguments via fifo instead
8 Copyright (C) 2012, 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.
30 #include <sys/types.h>
40 //////////////////////////////////////////////////////////////////////////////
43 std::ostream
& FifoArgs::Write(std::ostream
&os
) const
46 os
<< "Pin " << m_pin
.Str() << endl
;
47 if( m_password
.size() )
48 os
<< "Password " << m_password
<< endl
;
49 if( m_log_filename
.size() )
50 os
<< "LogFilename " << m_log_filename
<< endl
;
51 if( m_use_serial_mode
)
52 os
<< "UseSerialMode" << endl
;
54 os
<< "Verbose" << endl
;
59 std::istream
& FifoArgs::Read(std::istream
&is
)
61 string line
, token
, arg
;
66 while( getline(is
, line
) ) {
67 istringstream
iss(line
);
72 else if( token
== "Password" )
73 getline(iss
, m_password
);
74 else if( token
== "LogFilename" )
75 getline(iss
, m_log_filename
);
76 else if( token
== "UseSerialMode" )
77 m_use_serial_mode
= true;
78 else if( token
== "Verbose" )
85 void FifoArgs::Clear()
89 m_log_filename
.clear();
90 m_use_serial_mode
= false;
95 //////////////////////////////////////////////////////////////////////////////
98 FifoServer::FifoServer(const FifoArgs
&args
)
102 int m_fifo
= mkfifo(BARRY_FIFO_NAME
, 0660);
104 throw ErrnoError("Cannot open Barry argument fifo", errno
);
108 FifoServer::~FifoServer()
113 bool FifoServer::Serve(int timeout_sec
)
118 // man fifo(7) says that opening write-only in non-blocking mode
119 // will fail until the other side opens for read. So continue
120 // to attempt opens until out of time.
122 while( timeout_sec
-- ) {
123 // attempt to open in non-blocking mode
127 // This should be safe from symlink attacks, since
128 // mkfifo(), in the constructor, will fail if any other
129 // file or symlink already exists, and therefore we will
130 // never get to this open() call if that fails. And if
131 // mkfifo() succeeds, then we are guaranteed (assuming /tmp
132 // permissions are correct) that only root or our own
133 // user can replace the fifo with something else, such
136 // The server side is not intended to run as root, yet
137 // if it is, then we are still safe, due to the above logic.
138 // The client side can run as root (depending on what pppd
139 // does with pppob), and has no control over creation of
140 // the fifo, but only opens it for reading, never for
141 // creation or writing. (See FifoClient() below.)
143 // Therefore, we can only be attacked, via symlink,
144 // by root or ourselves.
146 int fd
= open(BARRY_FIFO_NAME
, O_WRONLY
| O_NONBLOCK
);
154 int written
= write(fd
, oss
.str().data(), oss
.str().size());
157 // only success if we wrote all the data
158 return written
== (int)oss
.str().size();
165 void FifoServer::Cleanup()
168 unlink(BARRY_FIFO_NAME
);
174 //////////////////////////////////////////////////////////////////////////////
177 FifoClient::FifoClient()
181 /// Tries to open the fifo and read the arguments from it.
182 /// If it fails in any way, or timeout, returns false.
183 bool FifoClient::Fetch(int timeout_sec
)
185 // See man fifo(7). Should always succeed, as long as
186 // the file exists and permissions allow.
187 int fd
= open(BARRY_FIFO_NAME
, O_RDONLY
| O_NONBLOCK
);
193 while( timeout_sec
-- ) {
195 int r
= read(fd
, buf
, sizeof(buf
));
198 // only consider this the end of file if
199 // we've already read something, otherwise we close
200 // before the server has a chance to speak up
218 istringstream
iss(sbuf
);