File: gss_context.hh

package info (click to toggle)
pdns-recursor 5.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,108 kB
  • sloc: cpp: 109,513; javascript: 20,651; python: 5,657; sh: 5,069; makefile: 780; ansic: 582; xml: 37
file content (212 lines) | stat: -rw-r--r-- 6,629 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
 * This file is part of PowerDNS or dnsdist.
 * Copyright -- PowerDNS.COM B.V. and its contributors
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * In addition, for the avoidance of any doubt, permission is granted to
 * link this program with OpenSSL and to (re)distribute the binaries
 * produced as the result of such linking.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#pragma once

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "namespaces.hh"
#include "pdnsexception.hh"
#include "dns.hh"

#ifdef ENABLE_GSS_TSIG
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_krb5.h>
extern bool g_doGssTSIG;
#endif

//! Generic errors
enum GssContextError
{
  GSS_CONTEXT_NO_ERROR,
  GSS_CONTEXT_UNSUPPORTED,
  GSS_CONTEXT_NOT_FOUND,
  GSS_CONTEXT_NOT_INITIALIZED,
  GSS_CONTEXT_INVALID,
  GSS_CONTEXT_EXPIRED,
  GSS_CONTEXT_ALREADY_INITIALIZED
};

//! GSS context types
enum GssContextType
{
  GSS_CONTEXT_NONE,
  GSS_CONTEXT_INIT,
  GSS_CONTEXT_ACCEPT
};

class GssSecContext;

/*! Class for representing GSS names, such as host/host.domain.com@REALM.
 */
class GssName
{
public:
  //! Initialize to empty name
  GssName()
  {
    setName("");
  };

  //! Initialize using specific name
  GssName(const std::string& name)
  {
    setName(name);
  };

#ifdef ENABLE_GSS_TSIG
  //! Parse name into native representation
  bool setName(const std::string& name)
  {
    gss_buffer_desc buffer;
    d_name = GSS_C_NO_NAME;

    if (!name.empty()) {
      buffer.length = name.size();
      buffer.value = (void*)name.c_str();
      d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name);
      return d_maj == GSS_S_COMPLETE;
    }

    return true;
  }
#else
  bool setName(const std::string& /* name */)
  {
    return false;
  }
#endif

  ~GssName()
  {
#ifdef ENABLE_GSS_TSIG
    if (d_name != GSS_C_NO_NAME)
      gss_release_name(&d_min, &d_name);
#endif
  };

#ifdef ENABLE_GSS_TSIG
  //! Compare two Gss Names, if no gss support is compiled in, returns false always
  //! This is not necessarily same as string comparison between two non-parsed names
  bool operator==(const GssName& rhs)
  {
    OM_uint32 maj, min;
    int result;
    maj = gss_compare_name(&min, d_name, rhs.d_name, &result);
    return (maj == GSS_S_COMPLETE && result != 0);
  }
#else
  bool operator==(const GssName& /* rhs */)
  {
    return false;
  }
#endif

#ifdef ENABLE_GSS_TSIG
  //! Compare two Gss Names, if no gss support is compiled in, returns false always
  //! This is not necessarily same as string comparison between two non-parsed names
  bool match(const std::string& name)
  {
    OM_uint32 maj, min;
    int result;
    gss_name_t comp;
    gss_buffer_desc buffer;
    buffer.length = name.size();
    buffer.value = (void*)name.c_str();
    maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &comp);
    if (maj != GSS_S_COMPLETE)
      throw PDNSException("Could not import " + name + ": " + std::to_string(maj) + string(",") + std::to_string(min));
    // do comparison
    maj = gss_compare_name(&min, d_name, comp, &result);
    gss_release_name(&min, &comp);
    return (maj == GSS_S_COMPLETE && result != 0);
  }
#else
  bool match(const std::string& /* name */)
  {
    return false;
  }
#endif

  //! Check if GSS name was parsed successfully.
  bool valid()
  {
#ifdef ENABLE_GSS_TSIG
    return d_maj == GSS_S_COMPLETE;
#else
    return false;
#endif
  }

private:
#ifdef ENABLE_GSS_TSIG
  OM_uint32 d_maj{0}, d_min{0};
  gss_name_t d_name;
#endif
}; // GssName

class GssContext
{
public:
  static std::tuple<size_t, size_t, size_t> getCounts();
  static bool supported(); //<! Returns true if GSS is supported in the first place
  GssContext(); //<! Construct new GSS context with random name
  GssContext(const DNSName& label); //<! Create or open existing named context

  void setLocalPrincipal(const std::string& name); //<! Set our gss name
  bool getLocalPrincipal(std::string& name); //<! Get our name
  void setPeerPrincipal(const std::string& name); //<! Set remote name (do not use after negotiation)
  bool getPeerPrincipal(std::string& name); //<! Return remote name, returns actual name after negotiation

  void generateLabel(const std::string& suffix); //<! Generate random context name using suffix (such as mydomain.com)
  void setLabel(const DNSName& label); //<! Set context name to this label
  const DNSName& getLabel() { return d_label; } //<! Return context name

  bool init(const std::string& input, std::string& output); //<! Perform GSS Initiate Security Context handshake
  bool accept(const std::string& input, std::string& output); //<! Perform GSS Accept Security Context handshake
  bool destroy(); //<! Release the cached context
  bool expired(); //<! Check if context is expired
  bool valid(); //<! Check if context is valid

  bool sign(const std::string& input, std::string& output); //<! Sign something using gss
  bool verify(const std::string& input, const std::string& signature); //<! Validate gss signature with something

  GssContextError getError(); //<! Get error
  const std::vector<std::string> getErrorStrings() { return d_gss_errors; } //<! Get native error texts
private:
  void release(); //<! Release context
  void initialize(); //<! Initialize context
#ifdef ENABLE_GSS_TSIG
  void processError(const string& method, OM_uint32 maj, OM_uint32 min); //<! Process and fill error text vector
#endif
  DNSName d_label; //<! Context name
  std::string d_peerPrincipal; //<! Remote name
  std::string d_localPrincipal; //<! Our name
  GssContextError d_error; //<! Context error
  GssContextType d_type; //<! Context type
  std::vector<std::string> d_gss_errors; //<! Native error string(s)
  std::shared_ptr<GssSecContext> d_secctx; //<! Attached security context
}; // GssContext

bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac); //<! Create signature
bool gss_verify_signature(const DNSName& context, const std::string& message, const std::string& mac); //<! Validate signature