2 * Copyright 2001-2005 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * shib-sock.cpp -- Socket-based IListener implementations
20 * Created by: Derek Atkins <derek@ihtfp.com>, revised by Scott Cantor
23 #include "RPCListener.h"
26 # include <sys/socket.h>
29 # include <arpa/inet.h>
32 #include <sys/types.h>
33 #include <sys/stat.h> /* for chmod() */
40 using namespace shibboleth;
41 using namespace shibtarget;
42 using namespace log4cpp;
44 static const XMLCh address[] = { chLatin_a, chLatin_d, chLatin_d, chLatin_r, chLatin_e, chLatin_s, chLatin_s, chNull };
45 static const XMLCh port[] = { chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull };
47 class TCPListener : virtual public RPCListener
50 TCPListener(const DOMElement* e);
53 bool create(ShibSocket& s) const;
54 bool bind(ShibSocket& s, bool force=false) const;
55 bool connect(ShibSocket& s) const;
56 bool close(ShibSocket& s) const;
57 bool accept(ShibSocket& listener, ShibSocket& s) const;
58 CLIENT* getClientHandle(ShibSocket& s, u_long program, u_long version) const;
61 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
64 unsigned short m_port;
68 IPlugIn* TCPListenerFactory(const DOMElement* e)
70 return new TCPListener(e);
73 TCPListener::TCPListener(const DOMElement* e) : RPCListener(e), m_address("127.0.0.1"), m_port(12345)
75 // We're stateless, but we need to load the configuration.
76 const XMLCh* tag=e->getAttributeNS(NULL,address);
82 tag=e->getAttributeNS(NULL,port);
84 m_port=XMLString::parseInt(tag);
89 tag=e->getAttributeNS(NULL,SHIBT_L(acl));
91 auto_ptr_char temp(tag);
92 string sockacl=temp.get();
93 if (sockacl.length()) {
95 for (unsigned int i=0; i < sockacl.length(); i++) {
96 if (sockacl.at(i)==' ') {
97 m_acl.push_back(sockacl.substr(j, i-j));
101 m_acl.push_back(sockacl.substr(j, sockacl.length()-j));
105 m_acl.push_back("127.0.0.1");
108 void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
110 // Split on host:port boundary. Default to port only.
111 memset(addr,0,sizeof(struct sockaddr_in));
112 addr->sin_family=AF_INET;
113 addr->sin_port=htons(m_port);
114 addr->sin_addr.s_addr=inet_addr(m_address.c_str());
117 bool TCPListener::create(ShibSocket& s) const
119 s=socket(AF_INET,SOCK_STREAM,0);
121 if(s==INVALID_SOCKET)
129 bool TCPListener::bind(ShibSocket& s, bool force) const
131 struct sockaddr_in addr;
132 setup_tcp_sockaddr(&addr);
134 // XXX: Do we care about the return value from setsockopt?
136 ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
139 if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
145 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
155 bool TCPListener::connect(ShibSocket& s) const
157 struct sockaddr_in addr;
158 setup_tcp_sockaddr(&addr);
160 if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
163 if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
169 bool TCPListener::close(ShibSocket& s) const
179 bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
181 struct sockaddr_in addr;
184 int size=sizeof(addr);
185 s=::accept(listener,(struct sockaddr*)&addr,&size);
186 if(s==INVALID_SOCKET)
188 socklen_t size=sizeof(addr);
189 s=::accept(listener,(struct sockaddr*)&addr,&size);
193 char* client=inet_ntoa(addr.sin_addr);
194 for (vector<string>::const_iterator i=m_acl.begin(); i!=m_acl.end(); i++) {
200 log->error("accept() rejected client at %s\n",client);
204 CLIENT* TCPListener::getClientHandle(ShibSocket& s, u_long program, u_long version) const
206 struct sockaddr_in sin;
207 memset (&sin, 0, sizeof (sin));
209 return clnttcp_create(&sin, program, version, &s, 0, 0);
214 class UnixListener : virtual public RPCListener
217 UnixListener(const DOMElement* e);
218 ~UnixListener() {if (m_bound) unlink(m_address.c_str());}
220 bool create(ShibSocket& s) const;
221 bool bind(ShibSocket& s, bool force=false) const;
222 bool connect(ShibSocket& s) const;
223 bool close(ShibSocket& s) const;
224 bool accept(ShibSocket& listener, ShibSocket& s) const;
225 CLIENT* getClientHandle(ShibSocket& s, u_long program, u_long version) const;
229 mutable bool m_bound;
232 IPlugIn* UnixListenerFactory(const DOMElement* e)
234 return new UnixListener(e);
237 UnixListener::UnixListener(const DOMElement* e) : RPCListener(e), m_address("/var/run/shar-socket"), m_bound(false)
239 // We're stateless, but we need to load the configuration.
240 const XMLCh* tag=e->getAttributeNS(NULL,address);
242 auto_ptr_char a(tag);
247 #ifndef UNIX_PATH_MAX
248 #define UNIX_PATH_MAX 100
251 bool UnixListener::create(ShibSocket& sock) const
253 sock = socket(PF_UNIX, SOCK_STREAM, 0);
259 bool UnixListener::bind(ShibSocket& s, bool force) const
261 struct sockaddr_un addr;
262 memset(&addr, 0, sizeof (addr));
263 addr.sun_family = AF_UNIX;
264 strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);
267 unlink(m_address.c_str());
269 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
275 // Make sure that only the creator can read -- we don't want just
276 // anyone connecting, do we?
277 if (chmod(m_address.c_str(),0777) < 0) {
280 unlink(m_address.c_str());
288 bool UnixListener::connect(ShibSocket& s) const
290 struct sockaddr_un addr;
291 memset(&addr, 0, sizeof (addr));
292 addr.sun_family = AF_UNIX;
293 strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);
295 if (::connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)
300 bool UnixListener::close(ShibSocket& s) const
306 bool UnixListener::accept(ShibSocket& listener, ShibSocket& s) const
308 s=::accept(listener,NULL,NULL);
314 CLIENT* UnixListener::getClientHandle(ShibSocket& s, u_long program, u_long version) const
316 struct sockaddr_in sin;
317 memset (&sin, 0, sizeof (sin));
319 return clnttcp_create(&sin, program, version, &s, 0, 0);