1 /*
2 *----------------------------------------------------------------------------
3 *
4 * krb5wrap.cpp
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 #include "msktutil.h"
32
krb5_error_exit(const char * func,int err_code)33 void krb5_error_exit( const char *func, int err_code) {
34 v_error_exit("error_exit: krb func %s failed: (%s)", func, error_message(err_code));
35 }
36
krb5_warn(const char * func,int err_code)37 void krb5_warn( const char *func, int err_code) {
38 fprintf( stderr, "Warning: krb func %s failed: (%s)", func, error_message(err_code));
39 }
40
41 #ifdef HEIMDAL
krb5_free_keytab_entry_contents(krb5_context context,krb5_keytab_entry * entry)42 krb5_error_code krb5_free_keytab_entry_contents(krb5_context context,
43 krb5_keytab_entry *entry)
44 {
45 if (entry) {
46 krb5_free_principal(context, entry->principal);
47 if (entry->keyblock.keyvalue.data) {
48 memset(entry->keyblock.keyvalue.data,
49 0,
50 entry->keyblock.keyvalue.length);
51 free(entry->keyblock.keyvalue.data);
52 }
53 return 0;
54 }
55 return -1;
56 }
57 #endif
58
59 void
initialize_g_context()60 initialize_g_context() {
61 VERBOSE("Creating Kerberos Context");
62 krb5_error_code ret = krb5_init_context(&g_context);
63 if (ret) {
64 krb5_error_exit("krb5_init_context", ret);
65 }
66 }
67
68 void
destroy_g_context()69 destroy_g_context() {
70 VERBOSE("Destroying Kerberos Context");
71 krb5_free_context(g_context);
72 g_context = 0;
73 }
74
75
initialize(KRB5Principal & principal)76 void KRB5CCache::initialize(KRB5Principal &principal)
77 {
78 krb5_error_code ret = krb5_cc_initialize(g_context,
79 m_ccache,
80 principal.get());
81 if (ret) {
82 throw KRB5Exception("krb5_cc_initialize", ret);
83 }
84 }
85
86
store(KRB5Creds & creds)87 void KRB5CCache::store(KRB5Creds &creds)
88 {
89 krb5_error_code ret = krb5_cc_store_cred(g_context,
90 m_ccache,
91 creds.get());
92 if (ret) {
93 throw KRB5Exception("krb5_cc_store_cred", ret);
94 }
95 }
96
97
KRB5Creds(KRB5Principal & principal,KRB5Keytab & keytab,const char * tkt_service)98 KRB5Creds::KRB5Creds(KRB5Principal &principal,
99 KRB5Keytab &keytab,
100 const char *tkt_service) : m_creds()
101 {
102 krb5_error_code ret =
103 krb5_get_init_creds_keytab(g_context,
104 &m_creds,
105 principal.get(),
106 keytab.get(),
107 0,
108 const_cast<char*>(tkt_service), NULL);
109 if (ret) {
110 throw KRB5Exception("krb5_get_init_creds_keytab", ret);
111 }
112 }
113
114
KRB5Creds(KRB5Principal & principal,const std::string & password,const char * tkt_service)115 KRB5Creds::KRB5Creds(KRB5Principal &principal,
116 const std::string &password,
117 const char *tkt_service) : m_creds()
118 {
119 krb5_error_code ret =
120 krb5_get_init_creds_password(g_context,
121 &m_creds,
122 principal.get(),
123 const_cast<char*>(password.c_str()),
124 NULL,
125 NULL,
126 0,
127 const_cast<char*>(tkt_service),
128 NULL);
129 if (ret) {
130 throw KRB5Exception("krb5_get_init_creds_keytab", ret);
131 }
132 }
133
134
name()135 std::string KRB5Principal::name()
136 {
137 char *principal_string;
138 krb5_error_code ret = krb5_unparse_name(g_context,
139 m_princ,
140 &principal_string);
141 if (ret) {
142 throw KRB5Exception("krb5_unparse_name", ret);
143 }
144
145 std::string result(principal_string);
146
147 #ifdef HEIMDAL
148 krb5_xfree(principal_string);
149 #else
150 krb5_free_unparsed_name(g_context, principal_string);
151 #endif
152
153 return result;
154 }
155
156
addEntry(const KRB5Principal & princ,krb5_kvno kvno,krb5_keyblock & keyblock)157 void KRB5Keytab::addEntry(const KRB5Principal &princ,
158 krb5_kvno kvno,
159 krb5_keyblock &keyblock)
160 {
161 krb5_keytab_entry entry;
162
163 entry.principal = princ.get();
164 entry.vno = kvno;
165 #ifdef HEIMDAL
166 entry.keyblock = keyblock;
167 #else
168 entry.key = keyblock;
169 #endif
170 // avoid duplicate entries
171 (void) krb5_kt_remove_entry(g_context,
172 m_keytab,
173 &entry);
174 krb5_error_code ret = krb5_kt_add_entry(g_context,
175 m_keytab,
176 &entry);
177 if (ret) {
178 if (errno != 0) {
179 fprintf(stderr,"Error: Keytab write error: %s!\n", strerror(errno));
180 }
181 throw KRB5Exception("krb5_kt_add_entry failed", ret);
182 }
183 }
184
addEntry(const KRB5Principal & princ,krb5_kvno kvno,krb5_enctype enctype,const std::string & password,const std::string & salt)185 void KRB5Keytab::addEntry(const KRB5Principal &princ,
186 krb5_kvno kvno,
187 krb5_enctype enctype,
188 const std::string &password,
189 const std::string &salt)
190 {
191 krb5_keyblock keyblock;
192
193 #ifdef HEIMDAL
194 krb5_data pass_data;
195 krb5_salt salt_data;
196
197 salt_data.salttype = KRB5_PW_SALT;
198 salt_data.saltvalue.data = const_cast<char *>(salt.c_str());
199 salt_data.saltvalue.length = salt.length();
200
201 pass_data.data = const_cast<char *>(password.c_str());
202 pass_data.length = password.length();
203
204 krb5_error_code ret = krb5_string_to_key_data_salt(g_context,
205 enctype,
206 pass_data,
207 salt_data,
208 &keyblock);
209 if (ret) {
210 throw KRB5Exception("krb5_string_to_key_data_salt", ret);
211 }
212 #else
213 krb5_data salt_data, pass_data;
214 salt_data.data = const_cast<char *>(salt.c_str());
215 salt_data.length = salt.length();
216
217 pass_data.data = const_cast<char *>(password.c_str());
218 pass_data.length = password.length();
219
220 krb5_error_code ret = krb5_c_string_to_key(g_context,
221 enctype,
222 &pass_data,
223 &salt_data,
224 &keyblock);
225 if (ret) {
226 throw KRB5Exception("krb5_c_string_to_key", ret);
227 }
228 #endif
229
230 addEntry(princ, kvno, keyblock);
231 }
232
233
234
removeEntry(const KRB5Principal & princ,krb5_kvno kvno,krb5_enctype enctype)235 void KRB5Keytab::removeEntry(const KRB5Principal &princ,
236 krb5_kvno kvno,
237 krb5_enctype enctype)
238 {
239 krb5_keytab_entry entry;
240
241 entry.principal = princ.get();
242 entry.vno = kvno;
243 #ifdef HEIMDAL
244 entry.keyblock.keytype = enctype;
245 #else
246 entry.key.enctype = enctype;
247 #endif
248
249 krb5_error_code ret = krb5_kt_remove_entry(g_context,
250 m_keytab,
251 &entry);
252 if (ret) {
253 if (errno != 0) {
254 fprintf(stderr,"Error: Keytab write error: %s!\n", strerror(errno));
255 }
256 throw KRB5Exception("krb5_kt_remove_entry", ret);
257 }
258 }
259
260
cursor(KRB5Keytab & keytab)261 KRB5Keytab::cursor::cursor(KRB5Keytab &keytab) : m_keytab(keytab),
262 m_cursor(),
263 m_entry(),
264 m_princ(),
265 m_ok(true)
266 {
267 memset(&m_entry, 0, sizeof(m_entry));
268
269 krb5_error_code ret = krb5_kt_start_seq_get(g_context,
270 m_keytab.m_keytab,
271 &m_cursor);
272 if (ret) {
273 m_ok = false;
274 }
275 }
276
277
~cursor()278 KRB5Keytab::cursor::~cursor()
279 {
280 if (!m_ok) {
281 m_princ.reset_no_free(NULL);
282 return;
283 }
284 krb5_free_keytab_entry_contents(g_context, &m_entry);
285 memset(&m_entry, 0, sizeof(m_entry));
286 /* Tell m_princ to not free its contents! */
287 m_princ.reset_no_free(NULL);
288 krb5_error_code ret = krb5_kt_end_seq_get(g_context,
289 m_keytab.m_keytab,
290 &m_cursor);
291 if (ret) {
292 krb5_warn("krb5_kt_end_seq_get", ret);
293 }
294 }
295
reset()296 void KRB5Keytab::cursor::reset()
297 {
298 if (!m_ok) {
299 return;
300 }
301 krb5_error_code ret = krb5_kt_start_seq_get(g_context,
302 m_keytab.m_keytab,
303 &m_cursor);
304 if (ret) {
305 m_ok = false;
306 }
307 }
308
next()309 bool KRB5Keytab::cursor::next()
310 {
311 if (!m_ok) {
312 return false;
313 }
314 krb5_free_keytab_entry_contents(g_context, &m_entry);
315 memset(&m_entry, 0, sizeof(m_entry));
316 krb5_error_code ret = krb5_kt_next_entry(g_context,
317 m_keytab.m_keytab,
318 &m_entry,
319 &m_cursor);
320 m_princ.reset_no_free(m_entry.principal);
321 return ret == 0;
322 }
323
324 krb5_context g_context = NULL;
325