gloox  1.1-svn
tlsschannelserver.cpp
1 /*
2  * Copyright (c) 2007-2009 by Jakob Schroeter <js@camaya.net>
3  * This file is part of the gloox library. http://camaya.net/gloox
4  *
5  * This software is distributed under a license. The full license
6  * agreement can be found in the file LICENSE in this distribution.
7  * This software may not be copied, modified, sold or distributed
8  * other than expressed in the named license agreement.
9  *
10  * This software is distributed without any warranty.
11  */
12 
13 #include "tlsschannelserver.h"
14 
15 #ifdef HAVE_WINTLS
16 
17 // #include <stdio.h> // just for debugging output
18 // #include <iostream>
19 
20 namespace gloox
21 {
23  : SChannelBase( th, EmptyString )
24  {
25  //printf(">> SChannelServer::SChannelServer()\n");
26  }
27 
29  {
30  m_handler = 0;
31  cleanup();
32  //printf(">> SChannelServer::~SChannelServer()\n");
33  }
34 
36  {
37  if( !m_handler || !m_valid )
38  return false;
39 
40  if( m_haveCredentialsHandle )
41  {
42  handshakeStage();
43  return true;
44  }
45 
46 // printf(">> SChannelServer::handshake()\n");
47  SECURITY_STATUS error;
48  ULONG return_flags;
49  TimeStamp t;
50  SecBuffer ibuf[2], obuf[1];
51  SecBufferDesc ibufs, obufs;
52  ULONG request = ISC_REQ_ALLOCATE_MEMORY
53  | ISC_REQ_CONFIDENTIALITY
54  | ISC_REQ_EXTENDED_ERROR
55  | ISC_REQ_INTEGRITY
56  | ISC_REQ_REPLAY_DETECT
57  | ISC_REQ_SEQUENCE_DETECT
58  | ISC_REQ_STREAM;
59 
60 
61  /* acquire credentials */
62  error = AcquireCredentialsHandle( 0,
63  UNISP_NAME,
64  SECPKG_CRED_INBOUND,
65  0,
66  &m_tlsCred,
67  0,
68  0,
69  &m_credHandle,
70  &t );
71 // print_error(error, "SChannelServer::handshake() ~ AcquireCredentialsHandle()");
72  if( error != SEC_E_OK )
73  {
74  cleanup();
75  m_handler->handleHandshakeResult( this, false, m_certInfo );
76  return false;
77  }
78  else
79  {
80  /* initialize buffers */
81  ibuf[0].cbBuffer = static_cast<unsigned long>( m_buffer.size() );
82  ibuf[0].pvBuffer = static_cast<void*>( const_cast<char*>( m_buffer.c_str() ) );
83  //std::cout << "Size: " << m_buffer.size() << "\n";
84  ibuf[1].cbBuffer = 0;
85  ibuf[1].pvBuffer = 0;
86  obuf[0].cbBuffer = 0;
87  obuf[0].pvBuffer = 0;
88 
89  ibuf[0].BufferType = SECBUFFER_TOKEN;
90  ibuf[1].BufferType = SECBUFFER_EMPTY;
91  obuf[0].BufferType = SECBUFFER_EMPTY;
92  /* initialize buffer descriptors */
93  ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
94  ibufs.cBuffers = 2;
95  obufs.cBuffers = 1;
96  ibufs.pBuffers = ibuf;
97  obufs.pBuffers = obuf;
98 
99 // std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
100 // std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
101 // std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
102 
103  error = AcceptSecurityContext( &m_credHandle,
104  0,
105  &ibufs,
106  request,
107  0,
108  &m_context,
109  &obufs,
110  &return_flags,
111  &t );
112 // print_error(error, "SChannelServer::handshake() ~ AcceptSecurityContext()");
113 
114  if( error == SEC_I_CONTINUE_NEEDED )
115  {
116 // std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
117 // std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
118 // std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
119  m_cleanedup = false;
120  m_buffer = EmptyString;
121  //std::cout << "obuf[1].cbBuffer: " << obuf[0].cbBuffer << "\n";
122  std::string senddata( static_cast<char*>( obuf[0].pvBuffer ), obuf[0].cbBuffer );
123  FreeContextBuffer( obuf[0].pvBuffer );
124  m_haveCredentialsHandle = true;
125  m_handler->handleEncryptedData( this, senddata );
126  return true;
127  }
128  else
129  {
130  cleanup();
131  m_handler->handleHandshakeResult( this, false, m_certInfo );
132  return false;
133  }
134  }
135  }
136 
137  void SChannelServer::handshakeStage()
138  {
139 // printf(" >> SChannelServer::handshakeStage\n");
140 
141  SECURITY_STATUS error;
142  ULONG a;
143  TimeStamp t;
144  SecBuffer ibuf[2], obuf[1];
145  SecBufferDesc ibufs, obufs;
146  ULONG request = ISC_REQ_ALLOCATE_MEMORY
147  | ISC_REQ_CONFIDENTIALITY
148  | ISC_REQ_EXTENDED_ERROR
149  | ISC_REQ_INTEGRITY
150  | ISC_REQ_REPLAY_DETECT
151  | ISC_REQ_SEQUENCE_DETECT
152  | ISC_REQ_STREAM
153  | ISC_REQ_MANUAL_CRED_VALIDATION;
154 
155  do
156  {
157  /* initialize buffers */
158  ibuf[0].cbBuffer = static_cast<unsigned long>( m_buffer.size() );
159  ibuf[0].pvBuffer = static_cast<void*>( const_cast<char*>( m_buffer.c_str() ) );
160  //std::cout << "Size: " << m_buffer.size() << "\n";
161  ibuf[1].cbBuffer = 0;
162  ibuf[1].pvBuffer = 0;
163  obuf[0].cbBuffer = 0;
164  obuf[0].pvBuffer = 0;
165 
166  ibuf[0].BufferType = SECBUFFER_TOKEN;
167  ibuf[1].BufferType = SECBUFFER_EMPTY;
168  obuf[0].BufferType = SECBUFFER_EMPTY;
169  /* initialize buffer descriptors */
170  ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
171  ibufs.cBuffers = 2;
172  obufs.cBuffers = 1;
173  ibufs.pBuffers = ibuf;
174  obufs.pBuffers = obuf;
175 
176 
177 // std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
178 // std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
179 // std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
180 
181 
182  /* negotiate security */
183  error = AcceptSecurityContext( &m_credHandle,
184  &m_context,
185  &ibufs,
186  request,
187  0,
188  0,
189  &obufs,
190  &a,
191  &t );
192 // print_error(error, "SChannelServer::handshakeStage() ~ AcceptSecurityContext()");
193 
194 // std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
195 // std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
196 // std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
197 
198  if( error == SEC_E_OK )
199  {
200  // STUFF TO SEND??
201  if( obuf[0].cbBuffer != 0 && obuf[0].pvBuffer != 0 )
202  {
203  std::string senddata( static_cast<char*>(obuf[0].pvBuffer), obuf[0].cbBuffer );
204  FreeContextBuffer( obuf[0].pvBuffer );
205  m_handler->handleEncryptedData( this, senddata );
206  }
207  // EXTRA STUFF??
208  if( ibuf[1].BufferType == SECBUFFER_EXTRA )
209  {
210  m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer );
211  }
212  else
213  {
214  m_buffer = EmptyString;
215  }
216  setSizes();
217  setCertinfos();
218 
219  m_secure = true;
220  m_handler->handleHandshakeResult( this, true, m_certInfo );
221  break;
222  }
223  else if( error == SEC_I_CONTINUE_NEEDED )
224  {
225  m_buffer = EmptyString;
226 
227  // STUFF TO SEND??
228  if( obuf[0].cbBuffer != 0 && obuf[0].pvBuffer != 0 )
229  {
230  std::string senddata( static_cast<char*>(obuf[0].pvBuffer), obuf[0].cbBuffer );
231  FreeContextBuffer( obuf[0].pvBuffer );
232  m_handler->handleEncryptedData( this, senddata );
233  }
234  // EXTRA STUFF??
235  if( ibuf[1].BufferType == SECBUFFER_EXTRA )
236  {
237  m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer );
238  // Call again if we aren't sending anything (otherwise the server will not send anything back
239  // and this function won't get called again to finish the processing). This is needed for
240  // NT4.0 which does not seem to process the entire buffer the first time around
241  if( obuf[0].cbBuffer == 0 )
242  handshakeStage();
243  }
244  else
245  {
246  m_buffer = EmptyString;
247  }
248  return;
249  }
250  else if( error == SEC_I_INCOMPLETE_CREDENTIALS )
251  {
252  handshakeStage();
253  }
254  else if( error == SEC_E_INCOMPLETE_MESSAGE )
255  {
256 // print_error(error, "SChannelClient::handshakeStage() ~ InitializeSecurityContext()");
257  break;
258  }
259  else
260  {
261  cleanup();
262  m_handler->handleHandshakeResult( this, false, m_certInfo );
263  break;
264  }
265  }
266  while( true );
267  }
268 
269  void SChannelServer::privateCleanup()
270  {
271  if( m_cert )
272  CertFreeCertificateContext( m_cert );
273  if( m_store )
274  CertCloseStore( m_store, 0 );
275  }
276 
277 }
278 
279 #endif // HAVE_WINTLS