https://issues.shibboleth.net/jira/browse/SSPCPP-239
[shibboleth/cpp-sp.git] / shar / shibrpc-server.cpp
1 /*
2  *  Copyright 2001-2005 Internet2
3  * 
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
18  * shibrpc-server.cpp -- SHIBRPC Server implementation.  Originally created
19  *                       as shibrpc-server-stubs.c; make sure that the function
20  *                       prototypes here match those in shibrpc.x.
21  *
22  * Created by:  Derek Atkins <derek@ihtfp.com>
23  *
24  * $Id$
25  */
26
27 #include <saml/saml.h>
28 #include <shib-target/shibrpc.h>
29
30 // eventually we might be able to support autoconf via cygwin...
31 #if defined (_MSC_VER) || defined(__BORLANDC__)
32 # include "config_win32.h"
33 #else
34 # include "config.h"
35 #endif
36
37 #include <shib-target/shib-target.h>
38
39 #ifdef HAVE_LIBDMALLOCXX
40 #include <dmalloc.h>
41 #endif
42
43 #include <sstream>
44
45 #include "shar-utils.h"
46
47 using namespace std;
48 using namespace saml;
49 using namespace shibboleth;
50 using namespace shibtarget;
51 using namespace shibd::logging;
52
53 extern IListener* g_MemoryListener;
54
55 static string get_threadid (const char* proc)
56 {
57   static u_long counter = 0;
58   ostringstream buf;
59   buf << "[" << counter++ << "] " << proc;
60   return buf.str();
61 }
62
63 static Category& get_category (void)
64 {
65   return Category::getInstance("shibd.Listener");
66 }
67
68 extern "C" bool_t shibrpc_ping_2_svc(int *argp, int *result, struct svc_req *rqstp)
69 {
70     g_MemoryListener->ping(*argp);
71     *result=*argp;
72     return TRUE;
73 }
74
75 extern "C" bool_t shibrpc_get_session_2_svc(
76     shibrpc_get_session_args_2 *argp,
77     shibrpc_get_session_ret_2 *result,
78     struct svc_req *rqstp
79     )
80 {
81     Category& log = get_category();
82     string ctx = get_threadid("sessionGet");
83     saml::NDC ndc(ctx);
84
85     if (!argp || !result) {
86         log.error("RPC Argument Error");
87         return FALSE;
88     }
89
90     memset(result, 0, sizeof (*result));
91     result->provider_id = strdup("");
92     result->auth_statement = strdup("");
93     result->attr_response_pre = strdup("");
94     result->attr_response_post = strdup("");
95
96     IConfig* conf=ShibTargetConfig::getConfig().getINI();
97     Locker locker(conf);
98     const IApplication* app=conf->getApplication(argp->application_id);
99     if (!app) {
100         // Something's horribly wrong.
101         log.error("couldn't find application (%s) for session", argp->application_id);
102         SAMLException ex("Unable to locate application for session, deleted?");
103         ostringstream os;
104         os << ex;
105         result->status=strdup(os.str().c_str());
106         return TRUE;
107     }
108     
109     ISessionCacheEntry* entry=NULL;
110     try {
111         // Delegate...
112         g_MemoryListener->sessionGet(app,argp->cookie,argp->client_addr,&entry);
113
114         // Set profile and provider
115         result->profile = entry->getProfile();
116         free(result->provider_id);
117         result->provider_id = strdup(entry->getProviderId());
118      
119         // Now grab the serialized authentication statement and responses
120         ostringstream os;
121         os << *(entry->getAuthnStatement());
122         free(result->auth_statement);
123         result->auth_statement = strdup(os.str().c_str());
124       
125         ISessionCacheEntry::CachedResponse responses=entry->getResponse();
126         if (!responses.empty()) {
127             os.str("");
128             os << *responses.unfiltered;
129             free(result->attr_response_pre);
130             result->attr_response_pre = strdup(os.str().c_str());
131
132             os.str("");
133             os << *responses.filtered;
134             free(result->attr_response_post);
135             result->attr_response_post = strdup(os.str().c_str());
136         }
137
138         // Ok, just release it.
139         entry->unlock();
140         entry=NULL;
141         result->status=strdup("");
142     }
143     catch (SAMLException &e) {
144         log.error("caught exception while retrieving session: %s", e.what());
145
146         // If the entry is set, it happened after the call.
147         if (entry) {
148             entry->unlock();
149             conf->getSessionCache()->remove(argp->cookie);
150         }
151         ostringstream os;
152         os << e;
153         result->status = strdup(os.str().c_str());
154     }
155 #ifndef _DEBUG
156     catch (...) {
157         log.error("caught unexpected exception while retrieving session");
158
159         // If the entry is set, it happened after the call.
160         if (entry) {
161             entry->unlock();
162             conf->getSessionCache()->remove(argp->cookie);
163         }
164         InvalidSessionException ex("An unexpected error occurred while validating your session, and you must re-authenticate.");
165         ostringstream os;
166         os << ex;
167         result->status = strdup(os.str().c_str());
168     }
169 #endif
170
171     return TRUE;
172 }
173
174 extern "C" bool_t
175 shibrpc_new_session_2_svc(
176     shibrpc_new_session_args_2 *argp,
177     shibrpc_new_session_ret_2 *result,
178     struct svc_req *rqstp
179     )
180 {
181     Category& log = get_category();
182     string ctx=get_threadid("sessionNew");
183     saml::NDC ndc(ctx);
184
185     if (!argp || !result) {
186         log.error("Invalid RPC Arguments");
187         return FALSE;
188     }
189
190     // Initialize the result structure
191     memset (result, 0, sizeof(*result));
192     result->cookie = strdup ("");
193     result->target = strdup ("");
194     result->provider_id = strdup("");
195
196     // Access the application config.
197     IConfig* conf=ShibTargetConfig::getConfig().getINI();
198     Locker locker(conf);
199     const IApplication* app=conf->getApplication(argp->application_id);
200     if (!app) {
201         // Something's horribly wrong. Flush the session.
202         log.error("couldn't find application for session");
203         SAMLException ex("Unable to locate application for session, deleted?");
204         ostringstream os;
205         os << ex;
206         result->status=strdup(os.str().c_str());
207         return TRUE;
208     }
209
210     try {
211         // Delagate the work...
212         string target,cookie,provider_id;
213         g_MemoryListener->sessionNew(
214             app,
215             argp->supported_profiles,
216             argp->recipient,
217             argp->packet,
218             argp->client_addr,
219             target,
220             cookie,
221             provider_id
222             );
223
224         // And let the user know.
225         if (result->cookie) free(result->cookie);
226         if (result->target) free(result->target);
227         if (result->provider_id) free(result->provider_id);
228         result->cookie = strdup(cookie.c_str());
229         result->target = strdup(target.c_str());
230         result->provider_id = strdup(provider_id.c_str());
231         result->status = strdup("");
232     }
233     catch (SAMLException& e) {
234         log.error("caught exception while creating session: %s", e.what());
235         ostringstream os;
236         os << e;
237         result->status = strdup(os.str().c_str());
238     }
239 #ifndef _DEBUG
240     catch (...) {
241         log.error("caught unexpected exception while creating session");
242         SAMLException e("An unexpected error occurred while creating your session.");
243         ostringstream os;
244         os << e;
245         result->status = strdup(os.str().c_str());
246     }
247 #endif
248
249     return TRUE;
250 }
251
252 extern "C" bool_t
253 shibrpc_end_session_2_svc(
254     shibrpc_end_session_args_2 *argp,
255     shibrpc_end_session_ret_2 *result,
256     struct svc_req *rqstp
257     )
258 {
259     Category& log = get_category();
260     string ctx = get_threadid("sessionEnd");
261     saml::NDC ndc(ctx);
262
263     if (!argp || !result) {
264         log.error("RPC Argument Error");
265         return FALSE;
266     }
267
268     memset(result, 0, sizeof (*result));
269
270     IConfig* conf=ShibTargetConfig::getConfig().getINI();
271     Locker locker(conf);
272     
273     try {
274         g_MemoryListener->sessionEnd(NULL,argp->cookie);
275         result->status=strdup("");
276     }
277     catch (SAMLException& e) {
278         log.error("caught exception while ending session: %s", e.what());
279         ostringstream os;
280         os << e;
281         result->status = strdup(os.str().c_str());
282     }
283 #ifndef _DEBUG
284     catch (...) {
285         log.error("caught unexpected exception while ending session");
286         SAMLException ex("An unexpected error occurred while ending your session.");
287         ostringstream os;
288         os << ex;
289         result->status = strdup(os.str().c_str());
290     }
291 #endif
292   
293     return TRUE;
294 }
295
296 extern "C" int
297 shibrpc_prog_2_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
298 {
299         xdr_free (xdr_result, result);
300
301         /*
302          * Insert additional freeing code here, if needed
303          */
304
305         return 1;
306 }