1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// @file Contains utility classes that make it easier to use SecBuffers
29
30#ifndef TALK_BASE_SEC_BUFFER_H__
31#define TALK_BASE_SEC_BUFFER_H__
32
33namespace talk_base {
34
35// A base class for CSecBuffer<T>. Contains
36// all implementation that does not require
37// template arguments.
38class CSecBufferBase : public SecBuffer {
39 public:
40  CSecBufferBase() {
41    Clear();
42  }
43
44  // Uses the SSPI to free a pointer, must be
45  // used for buffers returned from SSPI APIs.
46  static void FreeSSPI(void *ptr) {
47    if ( ptr ) {
48      SECURITY_STATUS status;
49      status = ::FreeContextBuffer(ptr);
50      ASSERT(SEC_E_OK == status); // "Freeing context buffer"
51    }
52  }
53
54  // Deletes a buffer with operator delete
55  static void FreeDelete(void *ptr) {
56    delete [] reinterpret_cast<char*>(ptr);
57  }
58
59  // A noop delete, for buffers over other
60  // people's memory
61  static void FreeNone(void *ptr) {
62  }
63
64 protected:
65  // Clears the buffer to EMPTY & NULL
66  void Clear() {
67    this->BufferType = SECBUFFER_EMPTY;
68    this->cbBuffer = 0;
69    this->pvBuffer = NULL;
70  }
71};
72
73// Wrapper class for SecBuffer to take care
74// of initialization and destruction.
75template <void (*pfnFreeBuffer)(void *ptr)>
76class CSecBuffer: public CSecBufferBase {
77 public:
78  // Initializes buffer to empty & NULL
79  CSecBuffer() {
80  }
81
82  // Frees any allocated memory
83  ~CSecBuffer() {
84    Release();
85  }
86
87  // Frees the buffer appropriately, and re-nulls
88  void Release() {
89    pfnFreeBuffer(this->pvBuffer);
90    Clear();
91  }
92
93 private:
94  // A placeholder function for compile-time asserts on the class
95  void CompileAsserts() {
96    // never invoked...
97    assert(false); // _T("Notreached")
98
99    // This class must not extend the size of SecBuffer, since
100    // we use arrays of CSecBuffer in CSecBufferBundle below
101    cassert(sizeof(CSecBuffer<SSPIFree> == sizeof(SecBuffer)));
102  }
103};
104
105// Contains all generic implementation for the
106// SecBufferBundle class
107class SecBufferBundleBase {
108 public:
109};
110
111// A template class that bundles a SecBufferDesc with
112// one or more SecBuffers for convenience. Can take
113// care of deallocating buffers appropriately, as indicated
114// by pfnFreeBuffer function.
115// By default does no deallocation.
116template <int num_buffers,
117          void (*pfnFreeBuffer)(void *ptr) = CSecBufferBase::FreeNone>
118class CSecBufferBundle : public SecBufferBundleBase {
119 public:
120  // Constructs a security buffer bundle with num_buffers
121  // buffers, all of which are empty and nulled.
122  CSecBufferBundle() {
123    desc_.ulVersion = SECBUFFER_VERSION;
124    desc_.cBuffers = num_buffers;
125    desc_.pBuffers = buffers_;
126  }
127
128  // Frees all currently used buffers.
129  ~CSecBufferBundle() {
130    Release();
131  }
132
133  // Accessor for the descriptor
134  PSecBufferDesc desc() {
135    return &desc_;
136  }
137
138  // Accessor for the descriptor
139  const PSecBufferDesc desc() const {
140    return &desc_;
141  }
142
143  // returns the i-th security buffer
144  SecBuffer &operator[] (size_t num) {
145    ASSERT(num < num_buffers); // "Buffer index out of bounds"
146    return buffers_[num];
147  }
148
149  // returns the i-th security buffer
150  const SecBuffer &operator[] (size_t num) const {
151    ASSERT(num < num_buffers); // "Buffer index out of bounds"
152    return buffers_[num];
153  }
154
155  // Frees all non-NULL security buffers,
156  // using the deallocation function
157  void Release() {
158    for ( size_t i = 0; i < num_buffers; ++i ) {
159      buffers_[i].Release();
160    }
161  }
162
163 private:
164  // Our descriptor
165  SecBufferDesc               desc_;
166  // Our bundled buffers, each takes care of its own
167  // initialization and destruction
168  CSecBuffer<pfnFreeBuffer>   buffers_[num_buffers];
169};
170
171} // namespace talk_base
172
173#endif  // TALK_BASE_SEC_BUFFER_H__
174