3cab428f31561583bba66a119f3bf9ab32bb92b6
[gssweb.git] / json_gssapi / src / commands / GSSInitSecContext.cpp
1 /*
2  * Copyright (c) 2014, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 // MRW -- Add proper copyright boilerplate to all files
35
36 #include "GSSInitSecContext.h"
37 #include "GSSException.h"
38 #include <cache/GSSContextCache.h>
39 #include <cache/GSSNameCache.h>
40 #include <datamodel/GSSName.h>
41 #include <gssapi.h>
42 #include <stdexcept>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "utils/base64.h"
47
48 typedef OM_uint32 (*init_sec_context)(
49     OM_uint32 *,        /* minor_status */
50     gss_cred_id_t,      /* claimant_cred_handle */
51     gss_ctx_id_t *,     /* context_handle */
52     gss_name_t,         /* target_name */
53     gss_OID,            /* mech_type (used to be const) */
54     OM_uint32,          /* req_flags */
55     OM_uint32,          /* time_req */
56     gss_channel_bindings_t,     /* input_chan_bindings */
57     gss_buffer_t,       /* input_token */
58     gss_OID *,          /* actual_mech_type */
59     gss_buffer_t,       /* output_token */
60     OM_uint32 *,        /* ret_flags */
61     OM_uint32 *         /* time_req */
62 );
63
64 void
65 GSSInitSecContext::execute()
66 {
67   /* Variables */
68   init_sec_context fn = (init_sec_context)function;
69   gss_OID actual_mech_type;
70   
71   /* Error checking */
72   
73   /* Setup */
74   if (output_token.length > 0)
75     retVal = gss_release_buffer(&minor_status, &output_token);
76
77   /* Main */
78   // MRW -- fix so that this uses all of the vars from the object 
79   retVal = fn(
80     &minor_status,
81     GSS_C_NO_CREDENTIAL,
82     &context_handle,
83     targetName.toGss(),
84     mechType.toGss(),
85     req_flags,
86     time_req,
87     GSS_C_NO_CHANNEL_BINDINGS,
88     &input_token,
89     &actual_mech_type,
90     &output_token,
91     &ret_flags,
92     &time_rec);
93   
94   if ( GSS_ERROR(this->retVal) )
95   {
96     // MRW -- steal code from import name
97     std::string errMsg;
98     errMsg += "Cannot init_sec_context: ";
99     throw GSSException(errMsg.c_str(), this->retVal, this->minor_status, mechType.toGss());
100   }
101   
102   actualMechType.setValue(actual_mech_type);
103   
104   context.setContext(context_handle, true);
105   contextKey = GSSContextCache::instance()->store(context);
106   
107   /* Cleanup */
108   
109   /* Return */
110 }
111
112 const char* GSSInitSecContext::getTargetDisplayName()
113 {
114   /* Variables */
115   gss_buffer_desc output_name;
116   gss_OID output_type;
117   OM_uint32 major, minor;
118   const char *ret;
119   
120   /* error checking */
121   
122   /* Setup */
123   
124   /* Main */
125   major = gss_display_name(&minor, target_name, &output_name, &output_type);
126   if (major == GSS_S_COMPLETE)
127     ret = (const char *)output_name.value;
128   else
129     ret = NULL;
130   
131   /* cleanup */
132   
133   /* return */
134   return( ret );
135 }
136
137 bool GSSInitSecContext::loadParameters(JSONObject *params)
138 {
139   /* Variables */
140   std::string key;
141   std::string token;
142   size_t len;
143   
144   /* Error checking */
145   if ( params->isNull() )
146     return true;
147   
148   /* Setup */
149   
150   /* Main processing */
151   // MRW -- finish parsing all of the variables
152   // claimant_cred_handle
153
154   // context_handle
155   if (!(params->get("context_handle").isNull() ||
156         (params->get("context_handle").isString() &&
157          std::string("") == params->get("context_handle").string())))
158   {
159     this->context_handle = GSS_C_NO_CONTEXT;
160     if (params->get("context_handle").isString())
161     {
162       key = params->get("context_handle").string();
163       context = GSSContextCache::instance()->retrieve( key.c_str() );
164       this->context_handle = context.getContext();
165     }
166     if (GSS_C_NO_CONTEXT == this->context_handle)
167       throw std::invalid_argument( "Could not find the context_handle." );
168   }
169   
170   // target_name
171   if (! (  params->get("target_name").isNull() ||
172            (params->get("target_name").isString() &&
173             std::string("") == params->get("target_name").string())
174         )
175      )
176   {
177     this->target_name = GSS_C_NO_NAME;
178     if (params->get("target_name").isString())
179     {
180       key = params->get("target_name").string();
181       
182       targetName = GSSNameCache::instance()->retrieve(key);
183       
184       this->target_name = targetName.toGss();
185     }
186     if (GSS_C_NO_NAME == this->target_name)
187       throw std::invalid_argument( "Could not find the target_name" );
188   }
189   
190   // mech_type  
191   if (! ( params->get("mech_type").isNull() ||
192           (
193             params->get("mech_type").isString() &&
194             std::string("") == params->get("mech_type").string()
195           )
196         )
197      )
198   {
199     key.clear();
200     if (params->get("mech_type").isString())
201     {
202       key = params->get("mech_type").string();
203       mechType.setValue(key);
204     }
205     if (GSS_C_NO_OID == this->mechType.toGss() )
206       throw std::invalid_argument( std::string() + "Could not create a mech_type OID from '" + key + "'");
207   }
208   
209   // req_flags
210   if (!params->get("req_flags").isNull() )
211     this->req_flags = params->get("req_flags").integer();
212
213   // time_req
214   if (!params->get("time_req").isNull() )
215     this->time_req = params->get("time_req").integer();
216
217   // input_token
218   if (! (params->get("input_token").isNull() ||
219          (params->get("input_token").isString() &&
220           std::string("") == params->get("input_token").string())))
221   {
222     token = params->get("input_token").string();
223     token = (char *)base64_decode(token, &len);
224     this->input_token.value = (void *)token.c_str();
225     this->input_token.length = token.length();
226   }
227
228   /* Cleanup */
229   
230   /* Return */
231   return true;
232 }
233
234 bool GSSInitSecContext::zeroOut(bool initialized)
235 {
236   /* Error checking */
237   /* Variables */
238   OM_uint32 minor;
239   gss_buffer_desc output;
240   
241   /* Setup */
242   /* Main */
243
244   // Free up existing memory if it's been set.  
245   if (initialized)
246   {
247     if (this->context_handle != NULL)
248       gss_delete_sec_context(&minor, &(this->context_handle), &output);
249     
250     if (this->target_name != NULL)
251       gss_release_name(&minor, &(this->target_name));
252       
253     if (this->output_token.length > 0)
254       gss_release_buffer(&minor, &output_token);
255     
256     if (this->input_token.length > 0)
257       gss_release_buffer(&minor, &input_token);
258   }
259
260   // Now set things to reasonable defaults
261   this->retVal = 0;
262   this->minor_status = 0;
263   this->req_flags = 0;
264   this->time_req = 0;
265   this->ret_flags = 0;
266   this->time_rec = 0;
267
268   this->context_handle = GSS_C_NO_CONTEXT;
269   this->target_name = GSS_C_NO_NAME;
270   this->mechType.setValue( (char *)"{ 1 3 6 1 5 5 15 1 1 18 }" );
271   this->input_token.length = 0;
272   this->input_token.value = NULL;
273   this->output_token.length = 0;
274   this->output_token.value = NULL;
275
276   /* Cleanup */
277   /* Return */
278   return(true);
279 }
280
281 JSONObject *GSSInitSecContext::toJSON()
282 {
283   /* Variables */
284   // MRW -- values should be scoped to the class, so execute can set error values?
285   std::string output_str;
286   JSONObject *values = new JSONObject();
287   
288   /* Error checking */
289   
290   /* Setup */
291   
292   /* Main */
293   values->set("major_status", this->retVal);
294   values->set("minor_status", this->minor_status);
295   values->set("context_handle", this->contextKey.c_str());
296   values->set("actual_mech_type", this->getActualMechType().toString().c_str());
297   // MRW -- is output_token.value guaranteed to be null-terminated?
298   output_str = (char *)output_token.value;
299   values->set("output_token", base64_encode(output_str));
300   values->set("ret_flags", this->ret_flags);
301   values->set("time_rec", this->time_rec);
302   // MRW -- modify for new error handling
303
304   /* Cleanup */
305   
306   /* Return */
307   return(values);
308 }
309
310 GSSInitSecContext::GSSInitSecContext(
311   JSONObject *params, 
312   void *fn) : GSSCommand(params)
313 {
314   zeroOut(false);
315   loadParameters(params);
316   function = fn;
317 }
318
319 GSSInitSecContext::GSSInitSecContext(void *fn)
320 {
321   zeroOut(false);
322   function = fn;
323 }
324