2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution, if any, must include
17 * the following acknowledgment: "This product includes software developed by
18 * the University Corporation for Advanced Internet Development
19 * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20 * may appear in the software itself, if and wherever such third-party
21 * acknowledgments normally appear.
23 * Neither the name of Shibboleth nor the names of its contributors, nor
24 * Internet2, nor the University Corporation for Advanced Internet Development,
25 * Inc., nor UCAID may be used to endorse or promote products derived from this
26 * software without specific prior written permission. For written permission,
27 * please contact shibboleth@shibboleth.org
29 * Products derived from this software may not be called Shibboleth, Internet2,
30 * UCAID, or the University Corporation for Advanced Internet Development, nor
31 * may Shibboleth appear in their name, without prior written permission of the
32 * University Corporation for Advanced Internet Development.
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36 * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39 * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40 * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41 * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 * shib-sock.cpp -- Socket-based IListener implementations
53 * Created by: Derek Atkins <derek@ihtfp.com>, revised by Scott Cantor
59 # include <sys/socket.h>
62 # include <arpa/inet.h>
67 #include <sys/types.h>
68 #include <sys/stat.h> /* for chmod() */
75 using namespace shibboleth;
76 using namespace shibtarget;
77 using namespace log4cpp;
79 static const XMLCh address[] = { chLatin_a, chLatin_d, chLatin_d, chLatin_r, chLatin_e, chLatin_s, chLatin_s, chNull };
80 static const XMLCh port[] = { chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull };
81 static const XMLCh acl[] = { chLatin_a, chLatin_c, chLatin_l, chNull };
83 class TCPListener : public IListener
86 TCPListener(const DOMElement* e);
89 bool create(ShibSocket& s) const;
90 bool bind(ShibSocket& s, bool force=false) const;
91 bool connect(ShibSocket& s) const;
92 bool close(ShibSocket& s) const;
93 bool accept(ShibSocket& listener, ShibSocket& s) const;
94 CLIENT* getClientHandle(ShibSocket& s, u_long program, u_long version) const;
97 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
98 bool log_error() const;
101 unsigned short m_port;
102 vector<string> m_acl;
106 IPlugIn* TCPListenerFactory(const DOMElement* e)
108 return new TCPListener(e);
111 TCPListener::TCPListener(const DOMElement* e) : m_address("127.0.0.1"), m_port(12345),
112 m_log(&Category::getInstance("shibtarget.TCPListener"))
114 // We're stateless, but we need to load the configuration.
115 const XMLCh* tag=e->getAttributeNS(NULL,address);
117 auto_ptr_char a(tag);
121 tag=e->getAttributeNS(NULL,port);
123 m_port=XMLString::parseInt(tag);
128 tag=e->getAttributeNS(NULL,acl);
130 auto_ptr_char temp(tag);
131 string sockacl=temp.get();
132 if (sockacl.length()) {
134 for (int i=0; i < sockacl.length(); i++) {
135 if (sockacl.at(i)==' ') {
136 m_acl.push_back(sockacl.substr(j, i-j));
140 m_acl.push_back(sockacl.substr(j, sockacl.length()-j));
144 m_acl.push_back("127.0.0.1");
147 void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
149 // Split on host:port boundary. Default to port only.
150 memset(addr,0,sizeof(struct sockaddr_in));
151 addr->sin_family=AF_INET;
152 addr->sin_port=htons(m_port);
153 addr->sin_addr.s_addr=inet_addr(m_address.c_str());
156 bool TCPListener::log_error() const
159 int rc=WSAGetLastError();
163 #ifdef HAVE_STRERROR_R
165 strerror_r(rc,buf,sizeof(buf));
167 m_log->error("socket call resulted in error (%d): %s",rc,buf);
169 m_log->error("socket call resulted in error (%d): %s",rc,strerror(rc));
174 bool TCPListener::create(ShibSocket& s) const
176 s=socket(AF_INET,SOCK_STREAM,0);
178 if(s==INVALID_SOCKET)
186 bool TCPListener::bind(ShibSocket& s, bool force) const
188 struct sockaddr_in addr;
189 setup_tcp_sockaddr(&addr);
191 if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
197 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
202 // XXX: Do we care about the return value from setsockopt?
204 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
210 bool TCPListener::connect(ShibSocket& s) const
212 struct sockaddr_in addr;
213 setup_tcp_sockaddr(&addr);
215 if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
218 if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
224 bool TCPListener::close(ShibSocket& s) const
234 bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
236 struct sockaddr_in addr;
239 int size=sizeof(addr);
240 s=::accept(listener,(struct sockaddr*)&addr,&size);
241 if(s==INVALID_SOCKET)
243 socklen_t size=sizeof(addr);
244 s=::accept(listener,(struct sockaddr*)&addr,&size);
248 char* client=inet_ntoa(addr.sin_addr);
249 for (vector<string>::const_iterator i=m_acl.begin(); i!=m_acl.end(); i++) {
255 m_log->error("accept() rejected client at %s\n",client);
259 CLIENT* TCPListener::getClientHandle(ShibSocket& s, u_long program, u_long version) const
261 struct sockaddr_in sin;
262 memset (&sin, 0, sizeof (sin));
264 return clnttcp_create(&sin, program, version, &s, 0, 0);
269 class UnixListener : public IListener
272 UnixListener(const DOMElement* e);
273 ~UnixListener() {if (m_bound) unlink(m_address.c_str());}
275 bool create(ShibSocket& s) const;
276 bool bind(ShibSocket& s, bool force=false) const;
277 bool connect(ShibSocket& s) const;
278 bool close(ShibSocket& s) const;
279 bool accept(ShibSocket& listener, ShibSocket& s) const;
280 CLIENT* getClientHandle(ShibSocket& s, u_long program, u_long version) const;
283 bool log_error() const;
286 mutable bool m_bound;
290 IPlugIn* UnixListenerFactory(const DOMElement* e)
292 return new UnixListener(e);
295 UnixListener::UnixListener(const DOMElement* e) : m_address("/tmp/shar-socket"), m_bound(false),
296 m_log(Category::getInstance("shibtarget.UnixListener"))
298 // We're stateless, but we need to load the configuration.
299 const XMLCh* tag=e->getAttributeNS(NULL,address);
301 auto_ptr_char a(tag);
306 bool UnixListener::log_error() const
309 #ifdef HAVE_STRERROR_R
311 strerror_r(rc,buf,sizeof(buf));
313 m_log.error("socket call resulted in error (%d): %s",rc,buf);
315 m_log.error("socket call resulted in error (%d): %s",rc,strerror(rc));
320 #ifndef UNIX_PATH_MAX
321 #define UNIX_PATH_MAX 100
324 bool UnixListener::create(ShibSocket& sock) const
326 sock = socket(PF_UNIX, SOCK_STREAM, 0);
332 bool UnixListener::bind(ShibSocket& s, bool force) const
334 struct sockaddr_un addr;
335 memset(&addr, 0, sizeof (addr));
336 addr.sun_family = AF_UNIX;
337 strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);
340 unlink(m_address.c_str());
342 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
348 /* Make sure that only the creator can read -- we don't want just
349 * anyone connecting, do we?
351 if (chmod(m_address.c_str(),0777) < 0) {
354 unlink(m_address.c_str());
362 bool UnixListener::connect(ShibSocket& s) const
364 struct sockaddr_un addr;
365 memset(&addr, 0, sizeof (addr));
366 addr.sun_family = AF_UNIX;
367 strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);
369 if (::connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)
374 bool UnixListener::close(ShibSocket& s) const
380 bool UnixListener::accept(ShibSocket& listener, ShibSocket& s) const
382 s=::accept(listener,NULL,NULL);
388 CLIENT* UnixListener::getClientHandle(ShibSocket& s, u_long program, u_long version) const
390 struct sockaddr_in sin;
391 memset (&sin, 0, sizeof (sin));
393 return clnttcp_create(&sin, program, version, &s, 0, 0);