1 /*
2  *----------------------------------------------------------------------------
3  *
4  * krb5wrap.h
5  *
6  * (C) 2004-2006 Dan Perry (dperry@pppl.gov)
7  * (C) 2006 Brian Elliott Finley (finley@anl.gov)
8  * (C) 2009-2010 Doug Engert (deengert@anl.gov)
9  * (C) 2010 James Y Knight (foom@fuhm.net)
10  * (C) 2010-2013 Ken Dreyer <ktdreyer at ktdreyer.com>
11  * (C) 2012-2017 Mark Proehl <mark at mproehl.net>
12  * (C) 2012-2017 Olaf Flebbe <of at oflebbe.de>
13  * (C) 2013-2017 Daniel Kobras <d.kobras at science-computing.de>
14  *
15     This program is free software; you can redistribute it and/or modify
16     it under the terms of the GNU General Public License as published by
17     the Free Software Foundation; either version 2 of the License, or
18     (at your option) any later version.
19 
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU General Public License for more details.
24 
25     You should have received a copy of the GNU General Public License
26     along with this program; if not, write to the Free Software
27     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
28  *
29  *-----------------------------------------------------------------------------
30  */
31 
32 extern krb5_context g_context;
33 
34 void krb5_error_exit( const char *func, int err_code);
35 void krb5_warn( const char *func, int err_code);
36 
37 void
38 initialize_g_context();
39 
40 void
41 destroy_g_context();
42 
43 class KRB5Principal;
44 
45 class KRB5Keytab {
46     krb5_keytab m_keytab;
47 
48     // make it non copyable
49     KRB5Keytab(const KRB5Keytab&);
50     const  KRB5Keytab& operator=(const KRB5Keytab&);
51 
52 public:
KRB5Keytab(const std::string & keytab_name)53     KRB5Keytab(const std::string &keytab_name) : m_keytab() {
54         krb5_error_code ret = krb5_kt_resolve(g_context, keytab_name.c_str(), &m_keytab);
55         if (ret) {
56             throw KRB5Exception("krb5_kt_resolve", ret);
57         }
58     }
59 
~KRB5Keytab()60     ~KRB5Keytab() {
61         krb5_error_code ret = krb5_kt_close(g_context, m_keytab);
62         if (ret) {
63             krb5_warn("krb5_kt_close", ret);
64         }
65     }
66 
67     void addEntry(const KRB5Principal &princ, krb5_kvno kvno, krb5_keyblock &keyblock);
68     void addEntry(const KRB5Principal &princ, krb5_kvno kvno, krb5_enctype enctype,
69                   const std::string &password, const std::string &salt);
70 
71     void removeEntry(const KRB5Principal &princ, krb5_kvno kvno, krb5_enctype enctype);
72 
get()73     krb5_keytab get() { return m_keytab; }
74 
75     /* Defined below... */
76     class cursor;
77 };
78 
79 class KRB5Creds {
80     krb5_creds m_creds;
81 
82     // make it non copyable
83     KRB5Creds(const KRB5Creds&);
84     const  KRB5Creds& operator=(const KRB5Creds&);
85 
86 public:
KRB5Creds()87     KRB5Creds() : m_creds() {}
88     KRB5Creds(KRB5Principal &principal, KRB5Keytab &keytab, const char *tkt_service=NULL);
89     KRB5Creds(KRB5Principal &principal, const std::string &password, const char *tkt_service=NULL);
~KRB5Creds()90     ~KRB5Creds() {
91         krb5_free_cred_contents(g_context, &m_creds);
92         memset(&m_creds, 0, sizeof(m_creds));
93     }
94 
get()95     krb5_creds *get() { return &m_creds; }
96 
move_from(KRB5Creds & other)97     void move_from(KRB5Creds &other) {
98         m_creds = other.m_creds;
99         memset(&other.m_creds, 0, sizeof(m_creds));
100     }
101 };
102 
103 class KRB5CCache {
104     krb5_ccache m_ccache;
105 
106     // make it non copyable
107     KRB5CCache(const KRB5CCache&);
108     const  KRB5CCache& operator=(const KRB5CCache&);
109 
110 public:
defaultName()111     static const char *defaultName() {
112         return krb5_cc_default_name(g_context);
113     }
114 
KRB5CCache(const char * cc_name)115     KRB5CCache(const char *cc_name) : m_ccache() {
116         krb5_error_code ret = krb5_cc_resolve(g_context, cc_name, &m_ccache);
117         if (ret)
118             throw KRB5Exception("krb5_cc_resolve", ret);
119     }
120 
~KRB5CCache()121     ~KRB5CCache() {
122         krb5_cc_close(g_context, m_ccache);
123     }
124 
get()125     krb5_ccache get() { return m_ccache; }
126 
127     void initialize(KRB5Principal &principal);
128     void store(KRB5Creds &creds);
129 };
130 
131 
132 class KRB5Principal {
133     friend class KRB5Keytab::cursor;
134 
135     krb5_principal m_princ;
136 
KRB5Principal()137     KRB5Principal() : m_princ() {}
138 
reset_no_free(krb5_principal princ)139     void reset_no_free(krb5_principal princ) {
140         m_princ = princ;
141     }
142 
143     // make it non copyable
144     KRB5Principal(const KRB5Principal&);
145     const KRB5Principal& operator=(const KRB5Principal&);
146 
147 public:
KRB5Principal(krb5_principal princ_raw)148     KRB5Principal(krb5_principal princ_raw) : m_princ(princ_raw) {}
149 
KRB5Principal(KRB5CCache & ccache)150     KRB5Principal(KRB5CCache &ccache) : m_princ() {
151         krb5_error_code ret = krb5_cc_get_principal(g_context, ccache.get(), &m_princ);
152         if (ret)
153             throw KRB5Exception("krb5_cc_get_principal", ret);
154     }
155 
KRB5Principal(std::string principal_name)156     KRB5Principal(std::string principal_name) : m_princ() {
157         krb5_error_code ret = krb5_parse_name(g_context, principal_name.c_str(), &m_princ);
158         if (ret)
159             throw KRB5Exception("krb5_parse_name", ret);
160     }
~KRB5Principal()161     ~KRB5Principal() {
162         if (m_princ)
163             krb5_free_principal(g_context, m_princ);
164     }
165 
get()166     krb5_principal get() const { return m_princ; }
167     std::string name();
168 };
169 
170 class KRB5Keytab::cursor {
171     KRB5Keytab &m_keytab;
172     krb5_kt_cursor m_cursor;
173     krb5_keytab_entry m_entry;
174 
175     /* Duplicates part of entry, but oh well. */
176     KRB5Principal m_princ;
177 
178     // make it non copyable
179     cursor(const cursor&);
180     const cursor& operator=(const cursor&);
181     bool m_ok;
182 public:
183     cursor(KRB5Keytab &keytab);
184     ~cursor();
185     bool next();
186     void reset();
187 
principal()188     KRB5Principal &principal() { return m_princ; }
kvno()189     krb5_kvno kvno() const { return m_entry.vno; }
enctype()190     krb5_enctype enctype() const {
191 #ifdef HEIMDAL
192         return static_cast<krb5_enctype>(m_entry.keyblock.keytype);
193 #else
194         return m_entry.key.enctype;
195 #endif
196     }
197 
timestamp()198     krb5_timestamp timestamp() const { return m_entry.timestamp; }
199 
key()200     krb5_keyblock key() const {
201 #ifdef HEIMDAL
202        return m_entry.keyblock;
203 #else
204        return m_entry.key;
205 #endif
206     }
207 };
208 
209 class KRB5KeytabEntry {
210 private:
211     std::string m_principal;
212     krb5_timestamp m_timestamp;
213     krb5_kvno m_kvno;
214     krb5_enctype m_enctype;
215     krb5_keyblock m_keyblock;
216 
217 public:
KRB5KeytabEntry(krb5_principal principal,krb5_timestamp timestamp,krb5_kvno kvno,krb5_enctype enctype,krb5_keyblock keyblock)218     KRB5KeytabEntry(krb5_principal principal,
219                     krb5_timestamp timestamp,
220                     krb5_kvno kvno,
221                     krb5_enctype enctype,
222                     krb5_keyblock keyblock) : m_principal(KRB5Principal(principal).name()),
223                                               m_timestamp(timestamp),
224                                               m_kvno(kvno),
225                                               m_enctype(enctype),
226                                               m_keyblock(keyblock) {
227         krb5_error_code ret = krb5_copy_keyblock_contents(g_context, &keyblock, &m_keyblock);
228         if (ret) {
229             throw KRB5Exception("krb5_copy_keyblock_contents", ret);
230         }
231     };
232 
KRB5KeytabEntry(KRB5Keytab::cursor & cursor)233     KRB5KeytabEntry(KRB5Keytab::cursor& cursor) : m_principal(cursor.principal().name()),
234                                                         m_timestamp(cursor.timestamp()),
235                                                         m_kvno(cursor.kvno()),
236                                                         m_enctype(cursor.enctype()),
237                                                         m_keyblock(cursor.key()) {
238         krb5_keyblock tmp = cursor.key();
239         krb5_error_code ret = krb5_copy_keyblock_contents(g_context, &tmp, &m_keyblock);
240         if (ret) {
241             throw KRB5Exception("krb5_copy_keyblock_contents", ret);
242         }
243     };
244 
245     const  KRB5KeytabEntry& operator=(const KRB5KeytabEntry& keytab_entry) {
246         m_principal = keytab_entry.m_principal;
247         m_timestamp = keytab_entry.m_timestamp;
248         m_kvno = keytab_entry.m_kvno;
249         m_enctype = keytab_entry.m_enctype;
250         m_keyblock = keytab_entry.m_keyblock;
251 
252         krb5_error_code ret = krb5_copy_keyblock_contents(g_context,
253                                                           &keytab_entry.m_keyblock,
254                                                           &m_keyblock);
255         if (ret) {
256             throw KRB5Exception("krb5_copy_keyblock_contents", ret);
257         }
258 
259 	return *this;
260     };
261 
KRB5KeytabEntry(const KRB5KeytabEntry & keytab_entry)262     KRB5KeytabEntry(const KRB5KeytabEntry &keytab_entry) {
263         (void) operator=(keytab_entry);
264     };
265 
266 
~KRB5KeytabEntry()267     ~KRB5KeytabEntry() { krb5_free_keyblock_contents(g_context, &m_keyblock); };
268 
principal()269     std::string principal() { return m_principal; };
timestamp()270     krb5_timestamp timestamp() { return m_timestamp; };
kvno()271     krb5_kvno kvno() { return m_kvno; };
enctype()272     krb5_enctype enctype() { return m_enctype; };
keyblock()273     krb5_keyblock keyblock() { return m_keyblock; };
274 
275     bool operator < (const KRB5KeytabEntry& other) const {
276         return m_timestamp < other.m_timestamp;
277     };
278 };
279