Path resolution for Unix socket.
[shibboleth/sp.git] / shibsp / remoting / impl / UnixListener.cpp
1 /*\r
2  *  Copyright 2001-2007 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * UnixListener.cpp\r
19  * \r
20  * Unix Domain-based SocketListener implementation\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "remoting/impl/SocketListener.h"\r
25 \r
26 #include <xercesc/util/XMLUniDefs.hpp>\r
27 #include <xmltooling/unicode.h>\r
28 #include <xmltooling/util/PathResolver.h>\r
29 \r
30 #ifdef HAVE_UNISTD_H\r
31 # include <sys/socket.h>\r
32 # include <sys/un.h>\r
33 # include <unistd.h>\r
34 # include <arpa/inet.h>\r
35 #endif\r
36 \r
37 #include <sys/types.h>\r
38 #include <sys/stat.h>           /* for chmod() */\r
39 #include <stdio.h>\r
40 #include <stdlib.h>\r
41 #include <errno.h>\r
42 \r
43 using namespace shibsp;\r
44 using namespace xmltooling;\r
45 using namespace xercesc;\r
46 using namespace std;\r
47 \r
48 \r
49 namespace shibsp {\r
50     static const XMLCh address[] = UNICODE_LITERAL_7(a,d,d,r,e,s,s);\r
51 \r
52     class UnixListener : virtual public SocketListener\r
53     {\r
54     public:\r
55         UnixListener(const DOMElement* e);\r
56         ~UnixListener() {if (m_bound) unlink(m_address.c_str());}\r
57 \r
58         bool create(ShibSocket& s) const;\r
59         bool bind(ShibSocket& s, bool force=false) const;\r
60         bool connect(ShibSocket& s) const;\r
61         bool close(ShibSocket& s) const;\r
62         bool accept(ShibSocket& listener, ShibSocket& s) const;\r
63 \r
64         int send(ShibSocket& s, const char* buf, int len) const {\r
65             return ::send(s, buf, len, 0);\r
66         }\r
67         \r
68         int recv(ShibSocket& s, char* buf, int buflen) const {\r
69             return ::recv(s, buf, buflen, 0);\r
70         }\r
71         \r
72     private:\r
73         string m_address;\r
74         mutable bool m_bound;\r
75     };\r
76 \r
77     ListenerService* SHIBSP_DLLLOCAL UnixListenerServiceFactory(const DOMElement* const & e)\r
78     {\r
79         return new UnixListener(e);\r
80     }\r
81 };\r
82 \r
83 UnixListener::UnixListener(const DOMElement* e) : SocketListener(e), m_address("/var/run/shar-socket"), m_bound(false)\r
84 {\r
85     const XMLCh* tag=e->getAttributeNS(NULL,address);\r
86     if (tag && *tag) {\r
87         auto_ptr_char a(tag);\r
88         m_address=a.get();\r
89         XMLToolingConfig::getConfig().getPathResolver()->resolve(m_address, PathResolver::XMLTOOLING_RUN_FILE);\r
90     }\r
91 }\r
92 \r
93 #ifndef UNIX_PATH_MAX\r
94 #define UNIX_PATH_MAX 100\r
95 #endif\r
96 \r
97 bool UnixListener::create(ShibSocket& sock) const\r
98 {\r
99     sock = socket(PF_UNIX, SOCK_STREAM, 0);\r
100     if (sock < 0)\r
101         return log_error();\r
102     return true;\r
103 }\r
104 \r
105 bool UnixListener::bind(ShibSocket& s, bool force) const\r
106 {\r
107     struct sockaddr_un addr;\r
108     memset(&addr, 0, sizeof (addr));\r
109     addr.sun_family = AF_UNIX;\r
110     strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);\r
111 \r
112     if (force)\r
113         unlink(m_address.c_str());\r
114 \r
115     if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {\r
116         log_error();\r
117         close(s);\r
118         return false;\r
119     }\r
120 \r
121     // Make sure that only the creator can read -- we don't want just\r
122     // anyone connecting, do we?\r
123     if (chmod(m_address.c_str(),0777) < 0) {\r
124         log_error();\r
125         close(s);\r
126         unlink(m_address.c_str());\r
127         return false;\r
128     }\r
129 \r
130     listen(s, 3);\r
131     return m_bound=true;\r
132 }\r
133 \r
134 bool UnixListener::connect(ShibSocket& s) const\r
135 {\r
136     struct sockaddr_un addr;\r
137     memset(&addr, 0, sizeof (addr));\r
138     addr.sun_family = AF_UNIX;\r
139     strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);\r
140 \r
141     if (::connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)\r
142         return log_error();\r
143     return true;\r
144 }\r
145 \r
146 bool UnixListener::close(ShibSocket& s) const\r
147 {\r
148     ::close(s);\r
149     return true;\r
150 }\r
151 \r
152 bool UnixListener::accept(ShibSocket& listener, ShibSocket& s) const\r
153 {\r
154     s=::accept(listener,NULL,NULL);\r
155     if (s < 0)\r
156         return log_error();\r
157     return true;\r
158 }\r