1 // Copyright (c) 1999-2018 David Muse
2 // See the COPYING file for more information.
3
4 #include <rudiments/charstring.h>
5 #include <rudiments/character.h>
6 #include <rudiments/environment.h>
7 #include <rudiments/filedescriptor.h>
8 #include <rudiments/bytestring.h>
9 #include <rudiments/stringbuffer.h>
10 #include <rudiments/linkedlist.h>
11 #include <rudiments/stdio.h>
12 #include <rudiments/bytebuffer.h>
13 #include <rudiments/error.h>
14 #include <rudiments/gss.h>
15
16 //#define DEBUG_GSS 1
17 //#define DEBUG_GSS_WRAP 1
18 //#define DEBUG_GSS_SEND 1
19 //#define DEBUG_GSS_RECEIVE 1
20
21 #if defined(RUDIMENTS_HAS_GSS)
22
23 #ifdef RUDIMENTS_HAS_GSSAPI_GSSAPI_EXT_H
24 // for gss_str_to_oid
25 #include <gssapi/gssapi_ext.h>
26 #endif
27
28 #ifndef RUDIMENTS_HAS_GSS_STR_TO_OID
29 // for local gss_str_to_oid implementation
30 #include "gssoid.cpp"
31 #endif
32
33 #ifndef RUDIMENTS_HAS_GSS_OID_TO_STR
34 // for local gss_oid_to_str implementation
35 // FIXME: ...
36 #endif
37
38 #ifndef RUDIMENTS_HAS_GSS_RELEASE_OID
39 // for local gss_release_oid implementation
40 // FIXME: ...
41 #endif
42
43 #ifndef RUDIMENTS_HAS_GSS_NAME_TYPES
44 #ifdef RUDIMENTS_HAS_GSSAPI_GSSAPI_GENERIC_H
45 // for gss_nt_* identifiers
46 #include <gssapi/gssapi_generic.h>
47 #endif
48 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
49 #define GSS_C_NT_USER_NAME gss_nt_user_name
50 #endif
51
52 #define GSS_SIZE_MAX 65536
53
54 #elif defined(RUDIMENTS_HAS_SSPI)
55
56 #include <schannel.h>
57 #define SSPI_ERROR(sstatus) ((sstatus)<0)
58
59 enum gss_mech_t {
60 GSS_MECH_KRB=0,
61 GSS_MECH_SCHANNEL,
62 GSS_MECH_OTHER
63 };
64
65 #else
66 // for UINT_MAX
67 #ifdef RUDIMENTS_HAVE_LIMITS_H
68 #include <limits.h>
69 #endif
70 #endif
71
72 #define TOKEN_FLAGS_TYPE_INITIATE (1<<0)
73 #define TOKEN_FLAGS_TYPE_ACCEPT (1<<1)
74 #define TOKEN_FLAGS_TYPE_DATA (1<<2)
75
76 // FIXME: do something with these...
77 #define TOKEN_FLAGS_TYPE_MIC (1<<3)
78 #define TOKEN_FLAGS_VERIFY (1<<4)
79 #define TOKEN_FLAGS_ENCRYPTED (1<<5)
80
81 class gssprivate {
82 friend class gss;
83 char **_mechs;
84 };
85
gss()86 gss::gss() {
87 pvt=new gssprivate;
88 pvt->_mechs=NULL;
89 }
90
~gss()91 gss::~gss() {
92 clear();
93 }
94
getAvailableMechanisms()95 const char * const *gss::getAvailableMechanisms() {
96
97 clear();
98
99 #ifdef DEBUG_GSS
100 stdoutput.printf("Available Mechanisms {\n");
101 #endif
102
103 #if defined(RUDIMENTS_HAS_GSS)
104
105 OM_uint32 major;
106 OM_uint32 minor;
107 gss_OID_set mechs;
108 major=gss_indicate_mechs(&minor,&mechs);
109 if (major==GSS_S_COMPLETE && mechs->count) {
110
111 pvt->_mechs=new char *[mechs->count+1];
112
113 gssmechanism scratch;
114
115 for (size_t i=0; i<mechs->count; i++) {
116 scratch.initialize(&mechs->elements[i]);
117 pvt->_mechs[i]=charstring::duplicate(
118 scratch.getString());
119 #ifdef DEBUG_GSS
120 stdoutput.printf(" %s\n",
121 scratch.getString());
122 #endif
123 }
124
125 pvt->_mechs[mechs->count]=NULL;
126
127 gss_release_oid_set(&minor,&mechs);
128 }
129
130 #elif defined(RUDIMENTS_HAS_SSPI)
131
132 ULONG packagecount;
133 PSecPkgInfo packages;
134 EnumerateSecurityPackages(&packagecount,&packages);
135 pvt->_mechs=new char *[packagecount+1];
136 for (ULONG i=0; i<packagecount; i++) {
137 pvt->_mechs[i]=charstring::duplicate(packages[i].Name);
138 #ifdef DEBUG_GSS
139 stdoutput.printf(" %s\n",pvt->_mechs[i]);
140 #endif
141 }
142 pvt->_mechs[packagecount]=NULL;
143
144 #endif
145
146 #ifdef DEBUG_GSS
147 stdoutput.printf("}\n");
148 #endif
149
150 return pvt->_mechs;
151 }
152
clear()153 void gss::clear() {
154 if (pvt->_mechs) {
155 for (char **m=pvt->_mechs; *m; m++) {
156 delete[] *m;
157 }
158 delete[] pvt->_mechs;
159 pvt->_mechs=NULL;
160 }
161 }
162
getSspiStatusString(uint32_t status)163 const char *gss::getSspiStatusString(uint32_t status) {
164 #if defined(RUDIMENTS_HAS_SSPI)
165 switch (status) {
166 case SEC_E_INSUFFICIENT_MEMORY:
167 return "SEC_E_INSUFFICIENT_MEMORY";
168 break;
169 case SEC_E_INVALID_HANDLE:
170 return "SEC_E_INVALID_HANDLE";
171 break;
172 case SEC_E_UNSUPPORTED_FUNCTION:
173 return "SEC_E_UNSUPPORTED_FUNCTION";
174 break;
175 case SEC_E_TARGET_UNKNOWN:
176 return "SEC_E_TARGET_UNKNOWN";
177 break;
178 case SEC_E_INTERNAL_ERROR:
179 return "SEC_E_INTERNAL_ERROR";
180 break;
181 case SEC_E_SECPKG_NOT_FOUND:
182 return "SEC_E_SECPKG_NOT_FOUND";
183 break;
184 case SEC_E_NOT_OWNER:
185 return "SEC_E_NOT_OWNER";
186 break;
187 case SEC_E_CANNOT_INSTALL:
188 return "SEC_E_CANNOT_INSTALL";
189 break;
190 case SEC_E_INVALID_TOKEN:
191 return "SEC_E_INVALID_TOKEN";
192 break;
193 case SEC_E_CANNOT_PACK:
194 return "SEC_E_CANNOT_PACK";
195 break;
196 case SEC_E_QOP_NOT_SUPPORTED:
197 return "SEC_E_QOP_NOT_SUPPORTED";
198 break;
199 case SEC_E_NO_IMPERSONATION:
200 return "SEC_E_NO_IMPERSONATION";
201 break;
202 case SEC_E_LOGON_DENIED:
203 return "SEC_E_LOGON_DENIED";
204 break;
205 case SEC_E_UNKNOWN_CREDENTIALS:
206 return "SEC_E_UNKNOWN_CREDENTIALS";
207 break;
208 case SEC_E_NO_CREDENTIALS:
209 return "SEC_E_NO_CREDENTIALS";
210 break;
211 case SEC_E_MESSAGE_ALTERED:
212 return "SEC_E_MESSAGE_ALTERED";
213 break;
214 case SEC_E_OUT_OF_SEQUENCE:
215 return "SEC_E_OUT_OF_SEQUENCE";
216 break;
217 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
218 return "SEC_E_NO_AUTHENTICATING_AUTHORITY";
219 break;
220 case SEC_I_CONTINUE_NEEDED:
221 return "SEC_I_CONTINUE_NEEDED";
222 break;
223 case SEC_I_COMPLETE_NEEDED:
224 return "SEC_I_COMPLETE_NEEDED";
225 break;
226 case SEC_I_COMPLETE_AND_CONTINUE:
227 return "SEC_I_COMPLETE_AND_CONTINUE";
228 break;
229 case SEC_I_LOCAL_LOGON:
230 return "SEC_I_LOCAL_LOGON";
231 break;
232 case SEC_E_BAD_PKGID:
233 return "SEC_E_BAD_PKGID";
234 break;
235 case SEC_E_CONTEXT_EXPIRED:
236 return "SEC_E_CONTEXT_EXPIRED";
237 break;
238 case SEC_I_CONTEXT_EXPIRED:
239 return "SEC_I_CONTEXT_EXPIRED";
240 break;
241 case SEC_E_INCOMPLETE_MESSAGE:
242 return "SEC_E_INCOMPLETE_MESSAGE";
243 break;
244 case SEC_E_INCOMPLETE_CREDENTIALS:
245 return "SEC_E_INCOMPLETE_CREDENTIALS";
246 break;
247 case SEC_E_BUFFER_TOO_SMALL:
248 return "SEC_E_BUFFER_TOO_SMALL";
249 break;
250 case SEC_I_INCOMPLETE_CREDENTIALS:
251 return "SEC_I_INCOMPLETE_CREDENTIALS";
252 break;
253 case SEC_I_RENEGOTIATE:
254 return "SEC_I_RENEGOTIATE";
255 break;
256 case SEC_E_WRONG_PRINCIPAL:
257 return "SEC_E_WRONG_PRINCIPAL";
258 break;
259 case SEC_I_NO_LSA_CONTEXT:
260 return "SEC_I_NO_LSA_CONTEXT";
261 break;
262 case SEC_E_TIME_SKEW:
263 return "SEC_E_TIME_SKEW";
264 break;
265 case SEC_E_UNTRUSTED_ROOT:
266 return "SEC_E_UNTRUSTED_ROOT";
267 break;
268 case SEC_E_ILLEGAL_MESSAGE:
269 return "SEC_E_ILLEGAL_MESSAGE";
270 break;
271 case SEC_E_CERT_UNKNOWN:
272 return "SEC_E_CERT_UNKNOWN";
273 break;
274 case SEC_E_CERT_EXPIRED:
275 return "SEC_E_CERT_EXPIRED";
276 break;
277 case SEC_E_ENCRYPT_FAILURE:
278 return "SEC_E_ENCRYPT_FAILURE";
279 break;
280 case SEC_E_DECRYPT_FAILURE:
281 return "SEC_E_DECRYPT_FAILURE";
282 break;
283 case SEC_E_ALGORITHM_MISMATCH:
284 return "SEC_E_ALGORITHM_MISMATCH";
285 break;
286 case SEC_E_SECURITY_QOS_FAILED:
287 return "SEC_E_SECURITY_QOS_FAILED";
288 break;
289 case SEC_E_UNFINISHED_CONTEXT_DELETED:
290 return "SEC_E_UNFINISHED_CONTEXT_DELETED";
291 break;
292 case SEC_E_NO_TGT_REPLY:
293 return "SEC_E_NO_TGT_REPLY";
294 break;
295 case SEC_E_NO_IP_ADDRESSES:
296 return "SEC_E_NO_IP_ADDRESSES";
297 break;
298 case SEC_E_WRONG_CREDENTIAL_HANDLE:
299 return "SEC_E_WRONG_CREDENTIAL_HANDLE";
300 break;
301 case SEC_E_CRYPTO_SYSTEM_INVALID:
302 return "SEC_E_CRYPTO_SYSTEM_INVALID";
303 break;
304 case SEC_E_MAX_REFERRALS_EXCEEDED:
305 return "SEC_E_MAX_REFERRALS_EXCEEDED";
306 break;
307 case SEC_E_MUST_BE_KDC:
308 return "SEC_E_MUST_BE_KDC";
309 break;
310 case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED:
311 return "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED";
312 break;
313 case SEC_E_TOO_MANY_PRINCIPALS:
314 return "SEC_E_TOO_MANY_PRINCIPALS";
315 break;
316 case SEC_E_NO_PA_DATA:
317 return "SEC_E_NO_PA_DATA";
318 break;
319 case SEC_E_PKINIT_NAME_MISMATCH:
320 return "SEC_E_PKINIT_NAME_MISMATCH";
321 break;
322 case SEC_E_SMARTCARD_LOGON_REQUIRED:
323 return "SEC_E_SMARTCARD_LOGON_REQUIRED";
324 break;
325 case SEC_E_SHUTDOWN_IN_PROGRESS:
326 return "SEC_E_SHUTDOWN_IN_PROGRESS";
327 break;
328 case SEC_E_KDC_INVALID_REQUEST:
329 return "SEC_E_KDC_INVALID_REQUEST";
330 break;
331 case SEC_E_KDC_UNABLE_TO_REFER:
332 return "SEC_E_KDC_UNABLE_TO_REFER";
333 break;
334 case SEC_E_KDC_UNKNOWN_ETYPE:
335 return "SEC_E_KDC_UNKNOWN_ETYPE";
336 break;
337 case SEC_E_UNSUPPORTED_PREAUTH:
338 return "SEC_E_UNSUPPORTED_PREAUTH";
339 break;
340 case SEC_E_DELEGATION_REQUIRED:
341 return "SEC_E_DELEGATION_REQUIRED";
342 break;
343 case SEC_E_BAD_BINDINGS:
344 return "SEC_E_BAD_BINDINGS";
345 break;
346 case SEC_E_MULTIPLE_ACCOUNTS:
347 return "SEC_E_MULTIPLE_ACCOUNTS";
348 break;
349 case SEC_E_NO_KERB_KEY:
350 return "SEC_E_NO_KERB_KEY";
351 break;
352 #ifdef SEC_E_CERT_WRONG_USAGE
353 case SEC_E_CERT_WRONG_USAGE:
354 return "SEC_E_CERT_WRONG_USAGE";
355 break;
356 #endif
357 #ifdef SEC_E_DOWNGRADE_DETECTED
358 case SEC_E_DOWNGRADE_DETECTED:
359 return "SEC_E_DOWNGRADE_DETECTED";
360 break;
361 #endif
362 case SEC_E_SMARTCARD_CERT_REVOKED:
363 return "SEC_E_SMARTCARD_CERT_REVOKED";
364 break;
365 case SEC_E_ISSUING_CA_UNTRUSTED:
366 return "SEC_E_ISSUING_CA_UNTRUSTED";
367 break;
368 case SEC_E_REVOCATION_OFFLINE_C:
369 return "SEC_E_REVOCATION_OFFLINE_C";
370 break;
371 case SEC_E_PKINIT_CLIENT_FAILURE:
372 return "SEC_E_PKINIT_CLIENT_FAILURE";
373 break;
374 case SEC_E_SMARTCARD_CERT_EXPIRED:
375 return "SEC_E_SMARTCARD_CERT_EXPIRED";
376 break;
377 #ifdef SEC_E_NO_S4U_PROT_SUPPORT
378 case SEC_E_NO_S4U_PROT_SUPPORT:
379 return "SEC_E_NO_S4U_PROT_SUPPORT";
380 break;
381 #endif
382 #ifdef SEC_E_CROSSREALM_DELEGATION_FAILURE
383 case SEC_E_CROSSREALM_DELEGATION_FAILURE:
384 return "SEC_E_CROSSREALM_DELEGATION_FAILURE";
385 break;
386 #endif
387 #ifdef SEC_E_REVOCATION_OFFLINE_KDC
388 case SEC_E_REVOCATION_OFFLINE_KDC:
389 return "SEC_E_REVOCATION_OFFLINE_KDC";
390 break;
391 #endif
392 #ifdef SEC_E_ISSUING_CA_UNTRUSTED_KDC
393 case SEC_E_ISSUING_CA_UNTRUSTED_KDC:
394 return "SEC_E_ISSUING_CA_UNTRUSTED_KDC";
395 break;
396 #endif
397 #ifdef SEC_E_KDC_CERT_EXPIRED
398 case SEC_E_KDC_CERT_EXPIRED:
399 return "SEC_E_KDC_CERT_EXPIRED";
400 break;
401 #endif
402 #ifdef SEC_E_KDC_CERT_REVOKED
403 case SEC_E_KDC_CERT_REVOKED:
404 return "SEC_E_KDC_CERT_REVOKED";
405 break;
406 #endif
407 #ifdef SEC_I_SIGNATURE_NEEDED
408 case SEC_I_SIGNATURE_NEEDED:
409 return "SEC_I_SIGNATURE_NEEDED";
410 break;
411 #endif
412 #ifdef SEC_E_INVALID_PARAMETER
413 case SEC_E_INVALID_PARAMETER:
414 return "SEC_E_INVALID_PARAMETER";
415 break;
416 #endif
417 #ifdef SEC_E_DELEGATION_POLICY
418 case SEC_E_DELEGATION_POLICY:
419 return "SEC_E_DELEGATION_POLICY";
420 break;
421 #endif
422 #ifdef SEC_E_POLICY_NLTM_ONLY
423 case SEC_E_POLICY_NLTM_ONLY:
424 return "SEC_E_POLICY_NLTM_ONLY";
425 break;
426 #endif
427 #ifdef SEC_I_NO_RENEGOTIATION
428 case SEC_I_NO_RENEGOTIATION:
429 return "SEC_I_NO_RENEGOTIATION";
430 break;
431 #endif
432 #ifdef SEC_E_NO_CONTEXT
433 case SEC_E_NO_CONTEXT:
434 return "SEC_E_NO_CONTEXT";
435 break;
436 #endif
437 #ifdef SEC_E_PKU2U_CERT_FAILURE
438 case SEC_E_PKU2U_CERT_FAILURE:
439 return "SEC_E_PKU2U_CERT_FAILURE";
440 break;
441 #endif
442 #ifdef SEC_E_MUTUAL_AUTH_FAILED
443 case SEC_E_MUTUAL_AUTH_FAILED:
444 return "SEC_E_MUTUAL_AUTH_FAILED";
445 break;
446 #endif
447 case SEC_E_OK:
448 return "SEC_E_OK";
449 break;
450 default:
451 return "";
452 }
453 #else
454 return NULL;
455 #endif
456 }
457
supported()458 bool gss::supported() {
459 #if defined(RUDIMENTS_HAS_GSS)
460 return true;
461 #elif defined(RUDIMENTS_HAS_SSPI)
462 return true;
463 #else
464 return false;
465 #endif
466 }
467
468
469 class gssmechanismprivate {
470 friend class gssmechanism;
471 private:
472 char *_str;
473
474 #if defined(RUDIMENTS_HAS_GSS)
475 gss_OID _oid;
476 #else
477 void *_oid;
478 #endif
479 };
480
gssmechanism()481 gssmechanism::gssmechanism() {
482 pvt=new gssmechanismprivate;
483 pvt->_str=NULL;
484 #if defined(RUDIMENTS_HAS_GSS)
485 pvt->_oid=GSS_C_NO_OID;
486 #else
487 pvt->_oid=NULL;
488 #endif
489 }
490
~gssmechanism()491 gssmechanism::~gssmechanism() {
492 clear();
493 delete pvt;
494 }
495
initialize(const char * str)496 bool gssmechanism::initialize(const char *str) {
497
498 clear();
499
500 if (charstring::isNullOrEmpty(str)) {
501 return true;
502 }
503
504 pvt->_str=charstring::duplicate(str);
505
506 #if defined(RUDIMENTS_HAS_GSS)
507 gss_buffer_desc mechbuffer;
508 mechbuffer.value=(void *)str;
509 mechbuffer.length=charstring::length(str);
510
511 OM_uint32 major;
512 OM_uint32 minor;
513 major=gss_str_to_oid(&minor,&mechbuffer,&pvt->_oid);
514 return (major==GSS_S_COMPLETE);
515 #elif defined(RUDIMENTS_HAS_SSPI)
516 pvt->_oid=(void *)charstring::duplicate(str);
517 return true;
518 #else
519 RUDIMENTS_SET_ENOSYS
520 return false;
521 #endif
522 }
523
initialize(const void * oid)524 bool gssmechanism::initialize(const void *oid) {
525
526 clear();
527
528 #if defined(RUDIMENTS_HAS_GSS)
529 if ((gss_OID)oid==GSS_C_NO_OID) {
530 return true;
531 }
532
533 OM_uint32 major;
534 OM_uint32 minor;
535
536 // create a string from the oid
537 gss_buffer_desc mechbuffer;
538 major=gss_oid_to_str(&minor,(gss_OID)oid,&mechbuffer);
539 if (major!=GSS_S_COMPLETE) {
540 return false;
541 }
542
543 pvt->_str=new char[mechbuffer.length+1];
544 charstring::copy(pvt->_str,
545 (char *)mechbuffer.value,mechbuffer.length);
546 pvt->_str[mechbuffer.length]='\0';
547
548 gss_release_buffer(&minor,&mechbuffer);
549
550 // create a new oid from the string
551 // (you'd think there'd be a clean way to just copy
552 // an oid, but there doesn't appear to be)
553 mechbuffer.value=(void *)pvt->_str;
554 mechbuffer.length=charstring::length(pvt->_str);
555
556 major=gss_str_to_oid(&minor,&mechbuffer,&pvt->_oid);
557 return (major==GSS_S_COMPLETE);
558
559 #elif defined(RUDIMENTS_HAS_SSPI)
560 if (charstring::isNullOrEmpty((const char *)oid)) {
561 return true;
562 }
563 pvt->_oid=(void *)charstring::duplicate((const char *)oid);
564 return true;
565 #else
566 RUDIMENTS_SET_ENOSYS
567 return false;
568 #endif
569 }
570
clear()571 void gssmechanism::clear() {
572 #if defined(RUDIMENTS_HAS_GSS)
573 if (pvt->_oid!=GSS_C_NO_OID) {
574 OM_uint32 minor;
575 gss_release_oid(&minor,&pvt->_oid);
576 }
577 pvt->_oid=GSS_C_NO_OID;
578 #elif defined(RUDIMENTS_HAS_SSPI)
579 delete[] pvt->_oid;
580 pvt->_oid=NULL;
581 #endif
582
583 delete[] pvt->_str;
584 pvt->_str=NULL;
585 }
586
getString()587 const char *gssmechanism::getString() {
588 return pvt->_str;
589 }
590
getObjectId()591 const void *gssmechanism::getObjectId() {
592 return pvt->_oid;
593 }
594
595
596 class gsscredentialsprivate {
597 friend class gsscredentials;
598 private:
599 #if defined(RUDIMENTS_HAS_GSS)
600 OM_uint32 _major;
601 OM_uint32 _minor;
602 #elif defined(RUDIMENTS_HAS_SSPI)
603 SECURITY_STATUS _sstatus;
604 #else
605 uint32_t _major;
606 uint32_t _minor;
607 #endif
608
609 stringbuffer _status;
610
611 const char *_name;
612
613 #if defined(RUDIMENTS_HAS_GSS)
614 OM_uint32 _desiredlifetime;
615 OM_uint32 _actuallifetime;
616 #elif defined(RUDIMENTS_HAS_SSPI)
617 TimeStamp _actuallifetime;
618 #else
619 uint32_t _desiredlifetime;
620 uint32_t _actuallifetime;
621 #endif
622
623 #if defined(RUDIMENTS_HAS_GSS)
624 gss_OID_set _desiredmechanisms;
625 gss_OID_set _actualmechanisms;
626
627 gss_cred_usage_t _credusage;
628 gss_cred_id_t _credentials;
629 #elif defined(RUDIMENTS_HAS_SSPI)
630 ULONG _credusage;
631 CredHandle _credentials;
632 #endif
633
634 bool _acquired;
635 void *_psd;
636
637 linkedlist< gssmechanism * > _dmlist;
638 linkedlist< gssmechanism * > _amlist;
639 };
640
gsscredentials()641 gsscredentials::gsscredentials() {
642 pvt=new gsscredentialsprivate;
643
644 #if defined(RUDIMENTS_HAS_SSPI)
645 pvt->_sstatus=0;
646 #else
647 pvt->_major=0;
648 pvt->_minor=0;
649 #endif
650
651 pvt->_name=NULL;
652
653 #if defined(RUDIMENTS_HAS_GSS)
654 pvt->_desiredlifetime=GSS_C_INDEFINITE;
655 pvt->_actuallifetime=0;
656 #elif defined(RUDIMENTS_HAS_SSPI)
657 pvt->_actuallifetime.u.LowPart=0;
658 pvt->_actuallifetime.u.HighPart=0;
659 #else
660 pvt->_desiredlifetime=UINT_MAX;
661 pvt->_actuallifetime=0;
662 #endif
663
664 #if defined(RUDIMENTS_HAS_GSS)
665 pvt->_desiredmechanisms=GSS_C_NO_OID_SET;
666 pvt->_actualmechanisms=GSS_C_NO_OID_SET;
667
668 pvt->_credusage=GSS_C_BOTH;
669 pvt->_credentials=GSS_C_NO_CREDENTIAL;
670 #elif defined(RUDIMENTS_HAS_SSPI)
671 pvt->_credusage=SECPKG_CRED_BOTH;
672 bytestring::zero(&pvt->_credentials,sizeof(pvt->_credentials));
673 #endif
674 pvt->_acquired=false;
675 pvt->_psd=NULL;
676 }
677
~gsscredentials()678 gsscredentials::~gsscredentials() {
679 close();
680 delete pvt;
681 }
682
setKeytab(const char * keytab)683 bool gsscredentials::setKeytab(const char *keytab) {
684 #if defined(RUDIMENTS_HAS_GSS)
685 return (keytab)?
686 environment::setValue("KRB5_KTNAME",keytab):
687 environment::remove("KRB5_KTNAME");
688 #elif defined(RUDIMENTS_HAS_SSPI)
689 return true;
690 #else
691 RUDIMENTS_SET_ENOSYS
692 return false;
693 #endif
694 }
695
getKeytab()696 const char *gsscredentials::getKeytab() {
697 #if defined(RUDIMENTS_HAS_GSS)
698 return environment::getValue("KRB5_KTNAME");
699 #elif defined(RUDIMENTS_HAS_SSPI)
700 return NULL;
701 #else
702 return NULL;
703 #endif
704 }
705
setDesiredLifetime(uint32_t desiredlifetime)706 void gsscredentials::setDesiredLifetime(uint32_t desiredlifetime) {
707 #if defined(RUDIMENTS_HAS_GSS)
708 pvt->_desiredlifetime=desiredlifetime;
709 #elif defined(RUDIMENTS_HAS_SSPI)
710 // do nothing...
711 #else
712 pvt->_desiredlifetime=desiredlifetime;
713 #endif
714 }
715
getDesiredLifetime()716 uint32_t gsscredentials::getDesiredLifetime() {
717 #if defined(RUDIMENTS_HAS_GSS)
718 return pvt->_desiredlifetime;
719 #elif defined(RUDIMENTS_HAS_SSPI)
720 return 0;
721 #else
722 return pvt->_desiredlifetime;
723 #endif
724 }
725
addDesiredMechanism(gssmechanism * mech)726 void gsscredentials::addDesiredMechanism(gssmechanism *mech) {
727 pvt->_dmlist.append(mech);
728 }
729
removeDesiredMechanism(gssmechanism * mech)730 void gsscredentials::removeDesiredMechanism(gssmechanism *mech) {
731 pvt->_dmlist.removeAll(mech);
732 }
733
inDesiredMechanisms(gssmechanism * mech)734 bool gsscredentials::inDesiredMechanisms(gssmechanism *mech) {
735
736 // just return false for degenerate mechs
737 #if defined(RUDIMENTS_HAS_GSS)
738 if (!mech || (gss_OID)mech->getObjectId()==GSS_C_NO_OID) {
739 return false;
740 }
741 #elif defined(RUDIMENTS_HAS_SSPI)
742 if (!mech || !mech->getObjectId()) {
743 return false;
744 }
745 #else
746 if (!mech || !mech->getObjectId()) {
747 return false;
748 }
749 #endif
750
751 // just return false for degenerate lists
752 if (!pvt->_dmlist.getLength()) {
753 return false;
754 }
755
756 // look for the mech in the list
757 for (linkedlistnode< gssmechanism * > *node=
758 pvt->_dmlist.getFirst();
759 node; node=node->getNext()) {
760 if (!charstring::compare(
761 node->getValue()->getString(),
762 mech->getString())) {
763 return true;
764 }
765 }
766 return false;
767 }
768
clearDesiredMechanisms()769 void gsscredentials::clearDesiredMechanisms() {
770 pvt->_dmlist.clear();
771 }
772
getDesiredMechanismCount()773 uint64_t gsscredentials::getDesiredMechanismCount() {
774 return pvt->_dmlist.getLength();
775 }
776
getDesiredMechanism(uint64_t index)777 gssmechanism *gsscredentials::getDesiredMechanism(uint64_t index) {
778 uint64_t i=0;
779 for (linkedlistnode< gssmechanism * > *node=
780 pvt->_dmlist.getFirst();
781 node; node=node->getNext()) {
782 if (i==index) {
783 return node->getValue();
784 }
785 i++;
786 }
787 return NULL;
788 }
789
acquireForService(const char * name)790 bool gsscredentials::acquireForService(const char *name) {
791 #if defined(RUDIMENTS_HAS_GSS)
792 pvt->_credusage=GSS_C_ACCEPT;
793 return acquire(name,charstring::length(name),
794 GSS_C_NT_HOSTBASED_SERVICE);
795 #elif defined(RUDIMENTS_HAS_SSPI)
796 pvt->_credusage=SECPKG_CRED_INBOUND;
797 return acquire(name,0,NULL);
798 #else
799 RUDIMENTS_SET_ENOSYS
800 return false;
801 #endif
802 }
803
acquireForUser(const char * name)804 bool gsscredentials::acquireForUser(const char *name) {
805 #if defined(RUDIMENTS_HAS_GSS)
806 pvt->_credusage=GSS_C_INITIATE;
807 return acquire(name,charstring::length(name),
808 GSS_C_NT_USER_NAME);
809 #elif defined(RUDIMENTS_HAS_SSPI)
810 pvt->_credusage=SECPKG_CRED_OUTBOUND;
811 return acquire(name,0,NULL);
812 #else
813 RUDIMENTS_SET_ENOSYS
814 return false;
815 #endif
816 }
817
setPackageSpecificData(void * psd)818 void gsscredentials::setPackageSpecificData(void *psd) {
819 pvt->_psd=psd;
820 }
821
acquire(const char * name,size_t namelen,const void * nametype)822 bool gsscredentials::acquire(const char *name,
823 size_t namelen,
824 const void *nametype) {
825
826 // release any previously acquired credentials
827 close();
828
829 bool retval=false;
830
831 #if defined(RUDIMENTS_HAS_GSS)
832
833 #ifdef DEBUG_GSS
834 stdoutput.printf("acquire credentials\n(%s/",name);
835 if ((gss_OID)nametype==
836 GSS_C_NT_HOSTBASED_SERVICE) {
837 stdoutput.write("GSS_C_NT_HOSTBASED_SERVICE");
838 }
839 if ((gss_OID)nametype==(gss_OID)GSS_C_NT_USER_NAME) {
840 stdoutput.write("GSS_C_NT_USER_NAME");
841 }
842 stdoutput.write(") - ");
843 #endif
844
845 OM_uint32 major;
846 OM_uint32 minor;
847
848 // keep track of the name for nametypes
849 // where the name is a string
850 if ((gss_OID)nametype==
851 GSS_C_NT_HOSTBASED_SERVICE ||
852 (gss_OID)nametype==
853 GSS_C_NT_USER_NAME) {
854 pvt->_name=name;
855 }
856
857 // Acquire credentials associated with "name"
858 // where "name" is type "nametype"...
859
860 // by default, we'll use "no name"
861 gss_name_t desiredname=GSS_C_NO_NAME;
862
863 if (!charstring::isNullOrEmpty(name)) {
864
865 // if a name was provided then use it...
866 gss_buffer_desc namebuffer;
867 namebuffer.value=(void *)name;
868 namebuffer.length=namelen+1;
869
870 // create an "internal form" struct from the name...
871 pvt->_major=gss_import_name(&pvt->_minor,
872 &namebuffer,
873 (gss_OID)nametype,
874 &desiredname);
875 if (pvt->_major!=GSS_S_COMPLETE) {
876 #ifdef DEBUG_GSS
877 stdoutput.write("failed "
878 "(import name)\n\n");
879 #endif
880 return false;
881 }
882 }
883
884 // assemble desired mechs...
885
886 // release the old set and mark it nonexistent
887 if (pvt->_desiredmechanisms!=GSS_C_NO_OID_SET) {
888 gss_release_oid_set(&minor,&pvt->_desiredmechanisms);
889 pvt->_desiredmechanisms=GSS_C_NO_OID_SET;
890 }
891
892 // populate the set from the list of mechs
893 for (linkedlistnode< gssmechanism * > *node=
894 pvt->_dmlist.getFirst();
895 node; node=node->getNext()) {
896
897 gss_OID mechoid=
898 (gss_OID)node->getValue()->getObjectId();
899
900 // skip degenerate mechs
901 if (mechoid==GSS_C_NO_OID) {
902 continue;
903 }
904
905 // if the set doesn't exist already, then create it
906 if (pvt->_desiredmechanisms==GSS_C_NO_OID_SET) {
907 major=gss_create_empty_oid_set(&minor,
908 &pvt->_desiredmechanisms);
909 if (major!=GSS_S_COMPLETE) {
910 pvt->_desiredmechanisms=
911 GSS_C_NO_OID_SET;
912 break;
913 }
914 }
915
916 // add the mech
917 gss_add_oid_set_member(&minor,mechoid,
918 &pvt->_desiredmechanisms);
919 // FIXME: what if this fails?
920 }
921
922 // acquire the credentials associated with the name...
923 pvt->_major=gss_acquire_cred(&pvt->_minor,
924 desiredname,
925 pvt->_desiredlifetime,
926 pvt->_desiredmechanisms,
927 pvt->_credusage,
928 &pvt->_credentials,
929 &pvt->_actualmechanisms,
930 &pvt->_actuallifetime);
931
932 // success/failure
933 retval=(pvt->_major==GSS_S_COMPLETE);
934
935 // save the actual mechanisms
936 if (retval &&
937 pvt->_actualmechanisms!=GSS_C_NO_OID_SET &&
938 pvt->_actualmechanisms->count) {
939
940 for (uint64_t i=0;
941 i<pvt->_actualmechanisms->count; i++) {
942
943 gssmechanism *mech=new gssmechanism;
944 mech->initialize(
945 &pvt->_actualmechanisms->elements[i]);
946 pvt->_amlist.append(mech);
947 }
948 }
949
950 // clean up
951 if (desiredname!=GSS_C_NO_NAME) {
952 gss_release_name(&minor,&desiredname);
953 }
954 if (pvt->_desiredmechanisms!=GSS_C_NO_OID_SET) {
955 gss_release_oid_set(&minor,&pvt->_desiredmechanisms);
956 pvt->_desiredmechanisms=GSS_C_NO_OID_SET;
957 }
958
959 #elif defined(RUDIMENTS_HAS_SSPI)
960
961 #ifdef DEBUG_GSS
962 stdoutput.printf("acquire credentials\n(%s/",name);
963 if (pvt->_credusage==SECPKG_CRED_INBOUND) {
964 stdoutput.write("inbound");
965 } else if (pvt->_credusage==SECPKG_CRED_OUTBOUND) {
966 stdoutput.write("outbound");
967 } else {
968 stdoutput.write("both");
969 }
970 stdoutput.write(") - ");
971 #endif
972
973 // keep track of the name
974 pvt->_name=name;
975
976 // try each desired mechanism...
977 bool first=true;
978 const char *mechname=NULL;
979 linkedlistnode< gssmechanism * > *node=pvt->_dmlist.getFirst();
980 for (;;) {
981
982 // break at the end of the list of desired mechanisms
983 //
984 // Although... We need to run through at least once,
985 // even if no desired mechanisms were specified. So,
986 // make an exception in that case.
987 if (!first && !node) {
988 break;
989 }
990
991 // skip degenerate mechs
992 //
993 // Although... We need to run through at least once,
994 // even if no desired mechanisms were specified. So,
995 // make an exception in that case.
996 if (!first && !charstring::isNullOrEmpty(
997 node->getValue()->getString())) {
998 continue;
999 }
1000
1001 // clean up to try again, if we're
1002 // not currenly on the first try
1003 if (!first) {
1004 FreeCredentialHandle(&pvt->_credentials);
1005 }
1006
1007 // attempt to use the specified mech...
1008 mechname=(node)?node->getValue()->getString():NULL;
1009
1010 // ...but fall back to the "Negotiate" mech
1011 // This will only happen if no mechs were specified,
1012 // or if only degenerate mechs were specified.
1013 if (!mechname) {
1014 mechname=TEXT("Negotiate");
1015 }
1016 #ifdef DEBUG_GSS
1017 stdoutput.printf("%s... ",mechname);
1018 #endif
1019
1020 // acquire the credentials associated with the name...
1021 pvt->_sstatus=AcquireCredentialsHandle(
1022 (LPSTR)name,
1023 (SEC_CHAR *)mechname,
1024 pvt->_credusage,
1025 NULL,
1026 pvt->_psd,
1027 NULL,
1028 NULL,
1029 &pvt->_credentials,
1030 &pvt->_actuallifetime);
1031
1032 // success/failure
1033 retval=!SSPI_ERROR(pvt->_sstatus);
1034 if (retval) {
1035 break;
1036 }
1037
1038 // if we made it here, then we're
1039 // not still on the first try...
1040 first=false;
1041
1042 // try the next mechanism
1043 if (node) {
1044 node=node->getNext();
1045 }
1046 }
1047
1048 // save the actual mechanism
1049 gssmechanism *mech=new gssmechanism;
1050 mech->initialize(mechname);
1051 pvt->_amlist.append(mech);
1052 #else
1053 retval=false;
1054 #endif
1055
1056 pvt->_acquired=retval;
1057
1058 #ifdef DEBUG_GSS
1059 if (retval) {
1060 stdoutput.write("success...\n\n");
1061 stdoutput.write("Credentials {\n");
1062 stdoutput.printf(" name: %s\n",pvt->_name);
1063 #if !defined(RUDIMENTS_HAS_SSPI)
1064 stdoutput.printf(" desired lifetime: %d\n",
1065 pvt->_desiredlifetime);
1066 stdoutput.printf(" actual lifetime: %d\n",
1067 pvt->_actuallifetime);
1068 #endif
1069 stdoutput.write(" desired mechanisms:\n");
1070 for (linkedlistnode< gssmechanism * > *node=
1071 pvt->_dmlist.getFirst();
1072 node; node=node->getNext()) {
1073 stdoutput.printf(" %s\n",
1074 node->getValue()->getString());
1075 }
1076 stdoutput.write(" actual mechanisms:\n");
1077 for (linkedlistnode< gssmechanism * > *node=
1078 pvt->_amlist.getFirst();
1079 node; node=node->getNext()) {
1080 stdoutput.printf(" %s\n",
1081 node->getValue()->getString());
1082 }
1083 stdoutput.write(" credentials usage: ");
1084 #if defined(RUDIMENTS_HAS_GSS)
1085 if (pvt->_credusage==GSS_C_BOTH) {
1086 stdoutput.write("both\n");
1087 } else if (pvt->_credusage==GSS_C_INITIATE) {
1088 stdoutput.write("initiate\n");
1089 } else if (pvt->_credusage==GSS_C_ACCEPT) {
1090 stdoutput.write("accept\n");
1091 }
1092 #elif defined(RUDIMENTS_HAS_SSPI)
1093 if (pvt->_credusage==SECPKG_CRED_BOTH) {
1094 stdoutput.write("both\n");
1095 } else if (pvt->_credusage==SECPKG_CRED_OUTBOUND) {
1096 stdoutput.write("initiate\n");
1097 } else if (pvt->_credusage==SECPKG_CRED_INBOUND) {
1098 stdoutput.write("accept\n");
1099 }
1100 #endif
1101 stdoutput.write("}\n");
1102 } else {
1103 stdoutput.write("failed\n\n");
1104 }
1105 #endif
1106
1107 return retval;
1108 }
1109
acquired()1110 bool gsscredentials::acquired() {
1111 return pvt->_acquired;
1112 }
1113
close()1114 void gsscredentials::close() {
1115
1116 // release the credentials
1117 #if defined(RUDIMENTS_HAS_GSS)
1118 OM_uint32 minor;
1119 gss_release_cred(&minor,&pvt->_credentials);
1120 #elif defined(RUDIMENTS_HAS_SSPI)
1121 FreeCredentialHandle(&pvt->_credentials);
1122 #endif
1123
1124 // reset the name
1125 pvt->_name=NULL;
1126
1127 // reset the "actuals"
1128 #if defined(RUDIMENTS_HAS_GSS)
1129 if (pvt->_actualmechanisms!=GSS_C_NO_OID_SET) {
1130 OM_uint32 minor;
1131 gss_release_oid_set(&minor,&pvt->_actualmechanisms);
1132 pvt->_actualmechanisms=GSS_C_NO_OID_SET;
1133 }
1134 #endif
1135 pvt->_amlist.clearAndDelete();
1136 #if defined(RUDIMENTS_HAS_GSS)
1137 pvt->_actuallifetime=0;
1138 #elif defined(RUDIMENTS_HAS_SSPI)
1139 pvt->_actuallifetime.u.LowPart=0;
1140 pvt->_actuallifetime.u.HighPart=0;
1141 #else
1142 pvt->_actuallifetime=UINT_MAX;
1143 #endif
1144 pvt->_acquired=false;
1145 }
1146
getName()1147 const char *gsscredentials::getName() {
1148 return pvt->_name;
1149 }
1150
getActualLifetime()1151 uint32_t gsscredentials::getActualLifetime() {
1152 #if defined(RUDIMENTS_HAS_GSS)
1153 return pvt->_actuallifetime;
1154 #elif defined(RUDIMENTS_HAS_SSPI)
1155 // this loses precision...
1156 return (uint32_t)pvt->_actuallifetime.QuadPart;
1157 #else
1158 return pvt->_actuallifetime;
1159 #endif
1160 }
1161
inActualMechanisms(gssmechanism * mech)1162 bool gsscredentials::inActualMechanisms(gssmechanism *mech) {
1163
1164 // just return false for degenerate mechs
1165 #if defined(RUDIMENTS_HAS_GSS)
1166 if (!mech || (gss_OID)mech->getObjectId()==GSS_C_NO_OID) {
1167 return false;
1168 }
1169 #elif defined(RUDIMENTS_HAS_SSPI)
1170 if (!mech || !mech->getObjectId()) {
1171 return false;
1172 }
1173 #else
1174 if (!mech || !mech->getObjectId()) {
1175 return false;
1176 }
1177 #endif
1178
1179 // just return false for degenerate lists
1180 if (!pvt->_amlist.getLength()) {
1181 return false;
1182 }
1183
1184 // look for the mech in the list
1185 for (linkedlistnode< gssmechanism * > *node=
1186 pvt->_amlist.getFirst();
1187 node; node=node->getNext()) {
1188 if (!charstring::compare(
1189 node->getValue()->getString(),
1190 mech->getString())) {
1191 return true;
1192 }
1193 }
1194 return false;
1195 }
1196
getActualMechanismCount()1197 uint64_t gsscredentials::getActualMechanismCount() {
1198 return pvt->_amlist.getLength();
1199 }
1200
getActualMechanism(uint64_t index)1201 gssmechanism *gsscredentials::getActualMechanism(uint64_t index) {
1202 uint64_t i=0;
1203 for (linkedlistnode< gssmechanism * > *node=
1204 pvt->_amlist.getFirst();
1205 node; node=node->getNext()) {
1206 if (i==index) {
1207 return node->getValue();
1208 }
1209 i++;
1210 }
1211 return NULL;
1212 }
1213
getCredentials()1214 const void *gsscredentials::getCredentials() {
1215 #if defined(RUDIMENTS_HAS_GSS)
1216 return pvt->_credentials;
1217 #elif defined(RUDIMENTS_HAS_SSPI)
1218 return (pvt->_acquired)?&pvt->_credentials:NULL;
1219 #else
1220 RUDIMENTS_SET_ENOSYS
1221 return NULL;
1222 #endif
1223 }
1224
getMajorStatus()1225 uint32_t gsscredentials::getMajorStatus() {
1226 #if defined(RUDIMENTS_HAS_GSS)
1227 return pvt->_major;
1228 #elif defined(RUDIMENTS_HAS_SSPI)
1229 return pvt->_sstatus;
1230 #else
1231 return 0;
1232 #endif
1233 }
1234
getMinorStatus()1235 uint32_t gsscredentials::getMinorStatus() {
1236 #if defined(RUDIMENTS_HAS_GSS)
1237 return pvt->_minor;
1238 #elif defined(RUDIMENTS_HAS_SSPI)
1239 return 0;
1240 #else
1241 return 0;
1242 #endif
1243 }
1244
getStatus()1245 const char *gsscredentials::getStatus() {
1246 pvt->_status.clear();
1247 #if defined(RUDIMENTS_HAS_GSS)
1248 pvt->_status.append("GSS - major:\n");
1249 setStatus(pvt->_major,GSS_C_GSS_CODE);
1250 pvt->_status.append("GSS - minor:\n");
1251 setStatus(pvt->_minor,GSS_C_GSS_CODE);
1252 pvt->_status.append("MECH - major:\n");
1253 setStatus(pvt->_major,GSS_C_MECH_CODE);
1254 pvt->_status.append("MECH - minor:\n");
1255 setStatus(pvt->_minor,GSS_C_MECH_CODE);
1256 #elif defined(RUDIMENTS_HAS_SSPI)
1257 pvt->_status.append("SSPI - status:\n");
1258 setStatus(pvt->_sstatus,0);
1259 #endif
1260 return pvt->_status.getString();
1261 }
1262
getGSSMajorStatus()1263 const char *gsscredentials::getGSSMajorStatus() {
1264 pvt->_status.clear();
1265 #if defined(RUDIMENTS_HAS_GSS)
1266 setStatus(pvt->_major,GSS_C_GSS_CODE);
1267 #elif defined(RUDIMENTS_HAS_SSPI)
1268 setStatus(pvt->_sstatus,0);
1269 #endif
1270 return pvt->_status.getString();
1271 }
1272
getGSSMinorStatus()1273 const char *gsscredentials::getGSSMinorStatus() {
1274 pvt->_status.clear();
1275 #if defined(RUDIMENTS_HAS_GSS)
1276 setStatus(pvt->_minor,GSS_C_GSS_CODE);
1277 #elif defined(RUDIMENTS_HAS_SSPI)
1278 setStatus(pvt->_sstatus,0);
1279 #endif
1280 return pvt->_status.getString();
1281 }
1282
getMechanismMajorStatus()1283 const char *gsscredentials::getMechanismMajorStatus() {
1284 pvt->_status.clear();
1285 #if defined(RUDIMENTS_HAS_GSS)
1286 setStatus(pvt->_major,GSS_C_MECH_CODE);
1287 #elif defined(RUDIMENTS_HAS_SSPI)
1288 setStatus(pvt->_sstatus,0);
1289 #endif
1290 return pvt->_status.getString();
1291 }
1292
getMechanismMinorStatus()1293 const char *gsscredentials::getMechanismMinorStatus() {
1294 pvt->_status.clear();
1295 #if defined(RUDIMENTS_HAS_GSS)
1296 setStatus(pvt->_minor,GSS_C_MECH_CODE);
1297 #elif defined(RUDIMENTS_HAS_SSPI)
1298 setStatus(pvt->_sstatus,0);
1299 #endif
1300 return pvt->_status.getString();
1301 }
1302
setStatus(uint32_t status,int32_t type)1303 void gsscredentials::setStatus(uint32_t status, int32_t type) {
1304
1305 #if defined(RUDIMENTS_HAS_GSS)
1306 gss_buffer_desc statusbuffer;
1307
1308 OM_uint32 msgctx=0;
1309 do {
1310 OM_uint32 major;
1311 OM_uint32 minor;
1312 major=gss_display_status(&minor,
1313 status,
1314 type,
1315 GSS_C_NO_OID,
1316 &msgctx,
1317 &statusbuffer);
1318 if (major!=GSS_S_COMPLETE) {
1319 break;
1320 }
1321
1322 pvt->_status.append((unsigned char *)
1323 statusbuffer.value,
1324 statusbuffer.length);
1325 pvt->_status.append('\n');
1326
1327 gss_release_buffer(&minor,&statusbuffer);
1328 } while (msgctx);
1329
1330 #elif defined(RUDIMENTS_HAS_SSPI)
1331
1332 const char *str=gss::getSspiStatusString(status);
1333 pvt->_status.append(str)->append("\n");
1334 if (error::getNativeErrorNumber()) {
1335 char *errstr=error::getNativeErrorString();
1336 pvt->_status.append(errstr)->append("\n");
1337 delete[] errstr;
1338 }
1339 #endif
1340 }
1341
1342 class gsscontextprivate {
1343 friend class gsscontext;
1344 private:
1345 #if defined(RUDIMENTS_HAS_GSS)
1346 OM_uint32 _major;
1347 OM_uint32 _minor;
1348 #elif defined(RUDIMENTS_HAS_SSPI)
1349 SECURITY_STATUS _sstatus;
1350 #else
1351 uint32_t _major;
1352 uint32_t _minor;
1353 #endif
1354
1355 stringbuffer _status;
1356
1357 gsscredentials *_credentials;
1358
1359 filedescriptor *_fd;
1360
1361 #if defined(RUDIMENTS_HAS_GSS)
1362 OM_uint32 _desiredlifetime;
1363 OM_uint32 _actuallifetime;
1364 #elif defined(RUDIMENTS_HAS_SSPI)
1365 TimeStamp _actuallifetime;
1366 DWORD _maxmsgsize;
1367 DWORD _streamheadersize;
1368 DWORD _streamtrailersize;
1369 DWORD _trailersize;
1370 DWORD _blksize;
1371 bool _freecredentials;
1372 gss_mech_t _mech;
1373 #else
1374 uint32_t _desiredlifetime;
1375 uint32_t _actuallifetime;
1376 #endif
1377
1378 gssmechanism *_desiredmechanism;
1379 gssmechanism _actualmechanism;
1380
1381 #if defined(RUDIMENTS_HAS_GSS)
1382 OM_uint32 _desiredflags;
1383 OM_uint32 _actualflags;
1384 #elif defined(RUDIMENTS_HAS_SSPI)
1385 ULONG _desiredflags;
1386 ULONG _actualflags;
1387 #else
1388 uint32_t _desiredflags;
1389 uint32_t _actualflags;
1390 #endif
1391
1392 const char *_service;
1393 size_t _servicelength;
1394
1395 #if defined(RUDIMENTS_HAS_GSS)
1396 gss_ctx_id_t _context;
1397 #elif defined(RUDIMENTS_HAS_SSPI)
1398 _SecHandle _context;
1399 #else
1400 void *_context;
1401 #endif
1402
1403 char *_initiator;
1404
1405 char *_acceptor;
1406
1407 bool _isinitiator;
1408 bool _isopen;
1409
1410 bytebuffer _readbuffer;
1411 uint64_t _readbufferpos;
1412
1413 gsstokenformat_t _tokenformat;
1414 };
1415
gsscontext()1416 gsscontext::gsscontext() : securitycontext() {
1417 pvt=new gsscontextprivate;
1418 pvt->_credentials=NULL;
1419 pvt->_fd=NULL;
1420 #if defined(RUDIMENTS_HAS_GSS)
1421 pvt->_desiredlifetime=GSS_C_INDEFINITE;
1422 pvt->_actuallifetime=0;
1423 #elif defined(RUDIMENTS_HAS_SSPI)
1424 pvt->_maxmsgsize=0;
1425 pvt->_streamheadersize=0;
1426 pvt->_streamtrailersize=0;
1427 pvt->_trailersize=0;
1428 pvt->_blksize=0;
1429 pvt->_mech=GSS_MECH_OTHER;
1430 pvt->_actuallifetime.u.LowPart=0;
1431 pvt->_actuallifetime.u.HighPart=0;
1432 pvt->_freecredentials=false;
1433 #else
1434 pvt->_desiredlifetime=UINT_MAX;
1435 pvt->_actuallifetime=0;
1436 #endif
1437 pvt->_desiredmechanism=NULL;
1438 pvt->_desiredflags=0;
1439 pvt->_actualflags=0;
1440 pvt->_service=NULL;
1441 pvt->_servicelength=0;
1442 #if defined(RUDIMENTS_HAS_GSS)
1443 pvt->_context=GSS_C_NO_CONTEXT;
1444 #elif defined(RUDIMENTS_HAS_SSPI)
1445 bytestring::zero(&pvt->_context,sizeof(pvt->_context));
1446 #endif
1447 pvt->_initiator=NULL;
1448 pvt->_acceptor=NULL;
1449 pvt->_isinitiator=false;
1450 pvt->_isopen=false;
1451 pvt->_readbufferpos=0;
1452 pvt->_tokenformat=GSSTOKENFORMAT_KRB;
1453 }
1454
~gsscontext()1455 gsscontext::~gsscontext() {
1456 close();
1457 delete pvt;
1458 }
1459
setCredentials(gsscredentials * credentials)1460 void gsscontext::setCredentials(gsscredentials *credentials) {
1461 #if defined(RUDIMENTS_HAS_SSPI)
1462 if (pvt->_freecredentials) {
1463 delete pvt->_credentials;
1464 }
1465 pvt->_freecredentials=false;
1466 #endif
1467 pvt->_credentials=credentials;
1468 }
1469
getCredentials()1470 gsscredentials *gsscontext::getCredentials() {
1471 #if defined(RUDIMENTS_HAS_SSPI)
1472 if (pvt->_freecredentials) {
1473 return NULL;
1474 }
1475 #endif
1476 return pvt->_credentials;
1477 }
1478
setFileDescriptor(filedescriptor * fd)1479 void gsscontext::setFileDescriptor(filedescriptor *fd) {
1480 pvt->_fd=fd;
1481 }
1482
getFileDescriptor()1483 filedescriptor *gsscontext::getFileDescriptor() {
1484 return pvt->_fd;
1485 }
1486
setDesiredLifetime(uint32_t desiredlifetime)1487 void gsscontext::setDesiredLifetime(uint32_t desiredlifetime) {
1488 #if defined(RUDIMENTS_HAS_GSS)
1489 pvt->_desiredlifetime=desiredlifetime;
1490 #elif defined(RUDIMENTS_HAS_SSPI)
1491 // do nothing...
1492 #else
1493 pvt->_desiredlifetime=desiredlifetime;
1494 #endif
1495 }
1496
getDesiredLifetime()1497 uint32_t gsscontext::getDesiredLifetime() {
1498 #if defined(RUDIMENTS_HAS_GSS)
1499 return pvt->_desiredlifetime;
1500 #elif defined(RUDIMENTS_HAS_SSPI)
1501 return 0;
1502 #else
1503 return pvt->_desiredlifetime;
1504 #endif
1505 }
1506
setDesiredMechanism(gssmechanism * desiredmechanism)1507 void gsscontext::setDesiredMechanism(gssmechanism *desiredmechanism) {
1508 pvt->_desiredmechanism=desiredmechanism;
1509 }
1510
getDesiredMechanism()1511 gssmechanism *gsscontext::getDesiredMechanism() {
1512 return pvt->_desiredmechanism;
1513 }
1514
setDesiredFlags(uint32_t desiredflags)1515 void gsscontext::setDesiredFlags(uint32_t desiredflags) {
1516 pvt->_desiredflags=desiredflags;
1517 }
1518
setDesiredFlags(const char * desiredflags)1519 void gsscontext::setDesiredFlags(const char *desiredflags) {
1520
1521 char **df;
1522 uint64_t dfcount;
1523 charstring::split(desiredflags,",",true,&df,&dfcount);
1524
1525 pvt->_desiredflags=0;
1526 for (uint64_t i=0; i<dfcount; i++) {
1527 #ifdef GSS_C_DELEG_FLAG
1528 if (!charstring::compare(df[i],"GSS_C_DELEG_FLAG")) {
1529 pvt->_desiredflags|=GSS_C_DELEG_FLAG;
1530 }
1531 #endif
1532 #ifdef GSS_C_MUTUAL_FLAG
1533 if (!charstring::compare(df[i],"GSS_C_MUTUAL_FLAG")) {
1534 pvt->_desiredflags|=GSS_C_MUTUAL_FLAG;
1535 }
1536 #endif
1537 #ifdef GSS_C_REPLAY_FLAG
1538 if (!charstring::compare(df[i],"GSS_C_REPLAY_FLAG")) {
1539 pvt->_desiredflags|=GSS_C_REPLAY_FLAG;
1540 }
1541 #endif
1542 #ifdef GSS_C_SEQUENCE_FLAG
1543 if (!charstring::compare(df[i],"GSS_C_SEQUENCE_FLAG")) {
1544 pvt->_desiredflags|=GSS_C_SEQUENCE_FLAG;
1545 }
1546 #endif
1547 #ifdef GSS_C_CONF_FLAG
1548 if (!charstring::compare(df[i],"GSS_C_CONF_FLAG")) {
1549 pvt->_desiredflags|=GSS_C_CONF_FLAG;
1550 }
1551 #endif
1552 #if !defined(RUDIMENTS_HAS_SSPI)
1553 #ifdef GSS_C_INTEG_FLAG
1554 if (!charstring::compare(df[i],
1555 "GSS_C_INTEG_FLAG")) {
1556 pvt->_desiredflags|=GSS_C_INTEG_FLAG;
1557 }
1558 #endif
1559 #ifdef GSS_C_ANON_FLAG
1560 if (!charstring::compare(df[i],
1561 "GSS_C_ANON_FLAG")) {
1562 pvt->_desiredflags|=GSS_C_ANON_FLAG;
1563 }
1564 #endif
1565 #ifdef GSS_C_PROT_READY_FLAG
1566 if (!charstring::compare(df[i],
1567 "GSS_C_PROT_READY_FLAG")) {
1568 pvt->_desiredflags|=GSS_C_PROT_READY_FLAG;
1569 }
1570 #endif
1571 #ifdef GSS_C_TRANS_FLAG
1572 if (!charstring::compare(df[i],
1573 "GSS_C_TRANS_FLAG")) {
1574 pvt->_desiredflags|=GSS_C_TRANS_FLAG;
1575 }
1576 #endif
1577 #ifdef GSS_C_DELEG_POLICY_FLAG
1578 if (!charstring::compare(df[i],
1579 "GSS_C_DELEG_POLICY_FLAG")) {
1580 pvt->_desiredflags|=GSS_C_DELEG_POLICY_FLAG;
1581 }
1582 #endif
1583 #endif
1584 delete[] df[i];
1585 }
1586 delete[] df;
1587 }
1588
getDesiredFlags()1589 uint32_t gsscontext::getDesiredFlags() {
1590 return pvt->_desiredflags;
1591 }
1592
setService(const char * service)1593 void gsscontext::setService(const char *service) {
1594 pvt->_service=service;
1595 pvt->_servicelength=charstring::length(service);
1596 }
1597
getService()1598 const char *gsscontext::getService() {
1599 return pvt->_service;
1600 }
1601
connect()1602 bool gsscontext::connect() {
1603 #if defined(RUDIMENTS_HAS_GSS)
1604 return initiate(pvt->_service,pvt->_servicelength,
1605 GSS_C_NT_HOSTBASED_SERVICE);
1606 #elif defined(RUDIMENTS_HAS_SSPI)
1607 return initiate(pvt->_service,0,NULL);
1608 #else
1609 RUDIMENTS_SET_ENOSYS
1610 return false;
1611 #endif
1612 }
1613
getContext()1614 void *gsscontext::getContext() {
1615 #if defined(RUDIMENTS_HAS_SSPI)
1616 return (void *)&pvt->_context;
1617 #else
1618 return NULL;
1619 #endif
1620 }
1621
setTokenFormat(gsstokenformat_t tokenformat)1622 void gsscontext::setTokenFormat(gsstokenformat_t tokenformat) {
1623 pvt->_tokenformat=tokenformat;
1624 }
1625
getMaxMessageSize(const char * mechname)1626 bool gsscontext::getMaxMessageSize(const char *mechname) {
1627
1628 #if defined(RUDIMENTS_HAS_SSPI)
1629 if (!pvt->_maxmsgsize) {
1630
1631 #ifdef DEBUG_GSS
1632 stdoutput.printf("get max message "
1633 "size for mech %s...\n",
1634 mechname);
1635 #endif
1636
1637 PSecPkgInfo pkginfo;
1638 pvt->_sstatus=QuerySecurityPackageInfo(
1639 (LPSTR)mechname,&pkginfo);
1640 if (SSPI_ERROR(pvt->_sstatus)) {
1641 #ifdef DEBUG_GSS
1642 stdoutput.printf(
1643 "failed "
1644 "(QuerySecurityPackageInfo)"
1645 "\n%s\n",
1646 getStatus());
1647 #endif
1648 return false;
1649 }
1650 pvt->_maxmsgsize=pkginfo->cbMaxToken;
1651 FreeContextBuffer(pkginfo);
1652
1653 #ifdef DEBUG_GSS
1654 stdoutput.printf("max message size: %d\n",
1655 pvt->_maxmsgsize);
1656 #endif
1657 }
1658 #endif
1659 return true;
1660 }
1661
initiate(const char * name,size_t namelen,const void * nametype)1662 bool gsscontext::initiate(const char *name,
1663 size_t namelen,
1664 const void *nametype) {
1665
1666 // release any previously initialized context
1667 close();
1668
1669 #ifdef DEBUG_GSS
1670 stdoutput.write("initiate context...\n");
1671 #endif
1672
1673 // There is currently no option to no wrap/encrypt or unwrap/decrypt
1674 // in this class, so confidentiality should always be requested.
1675 // If it's not, SSPI will return SEC_E_UNSUPPORTED_FUNCTION when
1676 // calling EncryptMessage/DecryptMessage. MIT GSSPI doesn't appear to
1677 // mind if you call gss_wrap/gss_unwrap, but who knows what other
1678 // implementations might do. Just to be safe, we'll force
1679 // confidentiality, whether it was requested or not.
1680 pvt->_desiredflags|=GSS_C_CONF_FLAG;
1681
1682 #if defined(RUDIMENTS_HAS_GSS)
1683
1684 bool error=false;
1685
1686 OM_uint32 minor;
1687
1688 // by default, we'll use "no name"
1689 gss_name_t desiredname=GSS_C_NO_NAME;
1690
1691 if (!charstring::isNullOrEmpty(name)) {
1692
1693 // if a name was provided then use it...
1694 gss_buffer_desc namebuffer;
1695 namebuffer.value=(void *)name;
1696 namebuffer.length=namelen+1;
1697
1698 // create an "internal form" struct from the name...
1699 pvt->_major=gss_import_name(&pvt->_minor,
1700 &namebuffer,
1701 (gss_OID)nametype,
1702 &desiredname);
1703 if (pvt->_major!=GSS_S_COMPLETE) {
1704 #ifdef DEBUG_GSS
1705 stdoutput.write("failed "
1706 "(import_name)\n\n");
1707 #endif
1708 return false;
1709 }
1710 }
1711
1712 // initialize the context...
1713 gss_buffer_desc inputtoken;
1714 inputtoken.length=0;
1715 gss_buffer_desc outputtoken;
1716
1717 gss_cred_id_t credentials=
1718 (pvt->_credentials)?
1719 (gss_cred_id_t)pvt->_credentials->getCredentials():
1720 GSS_C_NO_CREDENTIAL;
1721
1722 gss_OID desiredmechoid=
1723 (pvt->_desiredmechanism)?
1724 (gss_OID)pvt->_desiredmechanism->getObjectId():
1725 GSS_C_NO_OID;
1726 gss_OID actualmechoid=GSS_C_NO_OID;
1727
1728 for (;;) {
1729
1730 // attempt to init the context
1731 pvt->_major=gss_init_sec_context(
1732 &pvt->_minor,
1733 credentials,
1734 &pvt->_context,
1735 desiredname,
1736 desiredmechoid,
1737 pvt->_desiredflags,
1738 pvt->_desiredlifetime,
1739 GSS_C_NO_CHANNEL_BINDINGS,
1740 &inputtoken,
1741 &actualmechoid,
1742 &outputtoken,
1743 &pvt->_actualflags,
1744 &pvt->_actuallifetime);
1745
1746 // free inputtoken if necessary
1747 if (inputtoken.length) {
1748 delete[] (unsigned char *)inputtoken.value;
1749 }
1750
1751 // bail on error
1752 if (GSS_ERROR(pvt->_major)) {
1753 #ifdef DEBUG_GSS
1754 stdoutput.printf(
1755 "failed "
1756 "(init_sec_context)\n%s\n",
1757 getStatus());
1758 #endif
1759 close();
1760 error=true;
1761 break;
1762 }
1763
1764 // send token to peer, if necessary
1765 if (outputtoken.length) {
1766 if (sendToken(TOKEN_FLAGS_TYPE_INITIATE,
1767 outputtoken.value,
1768 outputtoken.length)!=
1769 (ssize_t)outputtoken.length) {
1770 #ifdef DEBUG_GSS
1771 stdoutput.write(
1772 "failed (send)\n\n");
1773 #endif
1774 gss_release_buffer(&minor,
1775 &outputtoken);
1776 close();
1777 error=true;
1778 break;
1779 }
1780 }
1781
1782 // clean up
1783 gss_release_buffer(&minor,&outputtoken);
1784
1785 // receive token from peer,
1786 // into inputtoken, if necessary
1787 if (pvt->_major==GSS_S_CONTINUE_NEEDED) {
1788
1789 uint32_t flags=0;
1790 inputtoken.value=NULL;
1791 inputtoken.length=0;
1792 if (receiveToken(&flags,
1793 &inputtoken.value,
1794 &inputtoken.length)<=0 ||
1795 !checkFlags(flags,
1796 TOKEN_FLAGS_TYPE_ACCEPT)) {
1797 #ifdef DEBUG_GSS
1798 stdoutput.write(
1799 "failed (receive)\n\n");
1800 #endif
1801 delete[] (unsigned char *)
1802 inputtoken.value;
1803 gss_release_buffer(&minor,&outputtoken);
1804 close();
1805 error=true;
1806 break;
1807 }
1808
1809 } else {
1810
1811 // populate actual mechanism
1812 pvt->_actualmechanism.initialize(actualmechoid);
1813
1814 // break out if we've completed the process
1815 break;
1816 }
1817 }
1818
1819 // clean up
1820 if (desiredname!=GSS_C_NO_NAME) {
1821 gss_release_name(&minor,&desiredname);
1822 }
1823
1824 // bail on error
1825 if (error || pvt->_major!=GSS_S_COMPLETE) {
1826 return false;
1827 }
1828
1829 #elif defined(RUDIMENTS_HAS_SSPI)
1830
1831 bool error=false;
1832
1833 // get maxiumum message size...
1834 // At this point, we don't definitively know what mech
1835 // (security package) we'll be using, so we'll get the
1836 // max message size from the Negotiate mech, which will
1837 // be the max message size for all mechs.
1838 if (!getMaxMessageSize("Negotiate")) {
1839 return false;
1840 }
1841
1842 // input buffer
1843 BYTE *inbuf=NULL;
1844 DWORD inbufsize=0;
1845
1846 SecBuffer inputtoken[2];
1847 inputtoken[0].BufferType=SECBUFFER_TOKEN;
1848
1849 inputtoken[1].BufferType=SECBUFFER_EMPTY;
1850 inputtoken[1].cbBuffer=0;
1851 inputtoken[1].pvBuffer=NULL;
1852
1853 SecBufferDesc inputtokendesc;
1854 inputtokendesc.ulVersion=SECBUFFER_VERSION;
1855 inputtokendesc.cBuffers=2;
1856 inputtokendesc.pBuffers=inputtoken;
1857
1858 // output buffer
1859 BYTE *outbuf=new BYTE[pvt->_maxmsgsize];
1860
1861 SecBuffer outputtoken;
1862 outputtoken.BufferType=SECBUFFER_TOKEN;
1863 outputtoken.pvBuffer=outbuf;
1864
1865 SecBufferDesc outputtokendesc;
1866 outputtokendesc.ulVersion=SECBUFFER_VERSION;
1867 outputtokendesc.cBuffers=1;
1868 outputtokendesc.pBuffers=&outputtoken;
1869
1870 // get credentials
1871 // GSSAPI acquires credentials implicitly if none are specified,
1872 // but SSPI does not. Fortunately, acquiring credentials for a
1873 // NULL user grabs the current user's credentials.
1874 if (!pvt->_credentials) {
1875 pvt->_credentials=new gsscredentials();
1876 pvt->_credentials->addDesiredMechanism(
1877 pvt->_desiredmechanism);
1878 pvt->_freecredentials=true;
1879 }
1880 if (!pvt->_credentials->acquired()) {
1881 pvt->_credentials->acquireForUser(NULL);
1882 }
1883 CredHandle *credentials=
1884 (CredHandle *)pvt->_credentials->getCredentials();
1885
1886 for (;;) {
1887
1888 outputtoken.cbBuffer=pvt->_maxmsgsize;
1889
1890 if (inbuf) {
1891 inputtoken[0].cbBuffer=inbufsize;
1892 inputtoken[0].pvBuffer=inbuf;
1893 }
1894
1895 // attempt to init the context
1896 pvt->_sstatus=InitializeSecurityContext(
1897 credentials,
1898 (inbuf)?&pvt->_context:NULL,
1899 (SEC_CHAR *)name,
1900 pvt->_desiredflags,
1901 0,
1902 SECURITY_NETWORK_DREP,
1903 (inbuf)?&inputtokendesc:NULL,
1904 0,
1905 &pvt->_context,
1906 &outputtokendesc,
1907 &pvt->_actualflags,
1908 &pvt->_actuallifetime);
1909
1910 // clean up
1911 delete[] inbuf;
1912
1913 // bail on error
1914 if (SSPI_ERROR(pvt->_sstatus)) {
1915 #ifdef DEBUG_GSS
1916 stdoutput.printf(
1917 "failed "
1918 "(InitializeSecurityContext)"
1919 "\n%s\n",
1920 getStatus());
1921 #endif
1922 close();
1923 error=true;
1924 break;
1925 }
1926
1927 // complete the token, if needed
1928 if (pvt->_sstatus==SEC_I_COMPLETE_NEEDED ||
1929 pvt->_sstatus==SEC_I_COMPLETE_AND_CONTINUE) {
1930
1931 pvt->_sstatus=CompleteAuthToken(
1932 &pvt->_context,
1933 &outputtokendesc);
1934
1935 if (SSPI_ERROR(pvt->_sstatus)) {
1936 #ifdef DEBUG_GSS
1937 stdoutput.printf(
1938 "failed "
1939 "(CompleteAuthToken)"
1940 "\n%s\n",
1941 getStatus());
1942 #endif
1943 close();
1944 error=true;
1945 break;
1946 }
1947 }
1948
1949 // send token to peer, if necessary
1950 if (outputtoken.cbBuffer) {
1951 if (sendToken(TOKEN_FLAGS_TYPE_INITIATE,
1952 outbuf,
1953 outputtoken.cbBuffer)!=
1954 (ssize_t)outputtoken.cbBuffer) {
1955 #ifdef DEBUG_GSS
1956 stdoutput.write(
1957 "failed (send)\n\n");
1958 #endif
1959 close();
1960 error=true;
1961 break;
1962 }
1963 }
1964
1965 // receive token from peer,
1966 // into inputtoken, if necessary
1967 if (pvt->_sstatus==SEC_I_CONTINUE_NEEDED ||
1968 pvt->_sstatus==SEC_I_COMPLETE_AND_CONTINUE) {
1969
1970 void *inbuftemp=NULL;
1971 size_t inbufsizetemp=0;
1972 uint32_t flags=0;
1973 ssize_t result=
1974 receiveToken(&flags,
1975 &inbuftemp,
1976 &inbufsizetemp);
1977 inbuf=(BYTE *)inbuftemp;
1978 inbufsize=inbufsizetemp;
1979 if (result<=0 ||
1980 !checkFlags(flags,
1981 TOKEN_FLAGS_TYPE_ACCEPT)) {
1982 #ifdef DEBUG_GSS
1983 stdoutput.write(
1984 "failed (receive)\n\n");
1985 #endif
1986 delete[] inbuf;
1987 close();
1988 error=true;
1989 break;
1990 }
1991
1992 } else {
1993
1994 // FIXME: for Schannel (and maybe other
1995 // providers), it's possible for
1996 // InitializeSecurityContext to have returned
1997 // SEC_I_INCOMPLETE_CREDENTIALS.
1998 // Handle that...
1999
2000 // break out if we've completed the process
2001 break;
2002 }
2003 }
2004
2005 // handle "extra" data
2006 if (inputtoken[1].BufferType==SECBUFFER_EXTRA) {
2007 // FIXME: For Schannel (and maybe other providers),
2008 // some "extra" data may have been returned from this
2009 // process, usually (though not always) because a
2010 // renegotiation occurred. Handle that...
2011
2012 FreeContextBuffer(inputtoken[1].pvBuffer);
2013 }
2014
2015 // actual mechanism will be populated by inquire() below...
2016
2017 // clean up
2018 delete[] outbuf;
2019
2020 // bail on error
2021 if (error || pvt->_sstatus!=SEC_E_OK) {
2022 return false;
2023 }
2024
2025 // we are the initiator
2026 pvt->_isinitiator=true;
2027 #endif
2028
2029 #ifdef DEBUG_GSS
2030 stdoutput.write("success\n\n");
2031 #endif
2032
2033 // get additional info about the context
2034 return inquire();
2035 }
2036
2037 #ifdef DEBUG_GSS
printFlags(uint32_t flags)2038 static void printFlags(uint32_t flags) {
2039 #ifdef GSS_C_DELEG_FLAG
2040 if (flags&GSS_C_DELEG_FLAG) {
2041 stdoutput.printf(
2042 " GSS_C_DELEG_FLAG\n");
2043 }
2044 #endif
2045 #ifdef GSS_C_MUTUAL_FLAG
2046 if (flags&GSS_C_MUTUAL_FLAG) {
2047 stdoutput.printf(
2048 " GSS_C_MUTUAL_FLAG\n");
2049 }
2050 #endif
2051 #ifdef GSS_C_REPLAY_FLAG
2052 if (flags&GSS_C_REPLAY_FLAG) {
2053 stdoutput.printf(
2054 " GSS_C_REPLAY_FLAG\n");
2055 }
2056 #endif
2057 #ifdef GSS_C_SEQUENCE_FLAG
2058 if (flags&GSS_C_SEQUENCE_FLAG) {
2059 stdoutput.printf(
2060 " GSS_C_SEQUENCE_FLAG\n");
2061 }
2062 #endif
2063 #ifdef GSS_C_CONF_FLAG
2064 if (flags&GSS_C_CONF_FLAG) {
2065 stdoutput.printf(
2066 " GSS_C_CONF_FLAG\n");
2067 }
2068 #endif
2069 #if !defined(RUDIMENTS_HAS_SSPI)
2070 #ifdef GSS_C_INTEG_FLAG
2071 if (flags&GSS_C_INTEG_FLAG) {
2072 stdoutput.printf(
2073 " GSS_C_INTEG_FLAG\n");
2074 }
2075 #endif
2076 #ifdef GSS_C_ANON_FLAG
2077 if (flags&GSS_C_ANON_FLAG) {
2078 stdoutput.printf(
2079 " GSS_C_ANON_FLAG\n");
2080 }
2081 #endif
2082 #ifdef GSS_C_PROT_READY_FLAG
2083 if (flags&GSS_C_PROT_READY_FLAG) {
2084 stdoutput.printf(
2085 " GSS_C_PROT_READY_FLAG\n");
2086 }
2087 #endif
2088 #ifdef GSS_C_TRANS_FLAG
2089 if (flags&GSS_C_TRANS_FLAG) {
2090 stdoutput.printf(
2091 " GSS_C_TRANS_FLAG\n");
2092 }
2093 #endif
2094 #ifdef GSS_C_DELEG_POLICY_FLAG
2095 if (flags&GSS_C_DELEG_POLICY_FLAG) {
2096 stdoutput.printf(
2097 " GSS_C_DELEG_POLICY_FLAG\n");
2098 }
2099 #endif
2100 #endif
2101 }
2102 #endif
2103
2104 #ifdef RUDIMENTS_HAS_SSPI
2105 // FIXME: move to charstring class
unicodeToAscii(const WCHAR * in)2106 static CHAR *unicodeToAscii(const WCHAR *in) {
2107
2108 BOOL useddefaultchar;
2109 int32_t size=WideCharToMultiByte(CP_ACP,0,in,-1,NULL,0,NULL,NULL);
2110 if (!size) {
2111 return NULL;
2112 }
2113
2114 CHAR *out=new char[size];
2115 if (!WideCharToMultiByte(CP_ACP,0,in,-1,out,size,
2116 "?",&useddefaultchar)) {
2117 delete[] out;
2118 out=NULL;
2119 }
2120 return out;
2121 }
2122
2123 static const char *schannels[]={
2124 UNISP_NAME_A,
2125 SSL2SP_NAME_A,
2126 SSL3SP_NAME_A,
2127 TLS1SP_NAME_A,
2128 PCT1SP_NAME_A,
2129 SCHANNEL_NAME_A,
2130 NULL
2131 };
2132 #endif
2133
inquire()2134 bool gsscontext::inquire() {
2135
2136 bool retval=false;
2137
2138 #ifdef DEBUG_GSS
2139 stdoutput.write("inquire context - ");
2140 #endif
2141
2142 #if defined(RUDIMENTS_HAS_GSS)
2143
2144 // inquire...
2145 gss_name_t initiator;
2146 gss_name_t acceptor;
2147 int isinitiator;
2148 int isopen;
2149 pvt->_major=gss_inquire_context(&pvt->_minor,
2150 pvt->_context,
2151 &initiator,
2152 &acceptor,
2153 NULL,
2154 NULL,
2155 NULL,
2156 &isinitiator,
2157 &isopen);
2158 if (pvt->_major!=GSS_S_COMPLETE) {
2159 #ifdef DEBUG_GSS
2160 stdoutput.write("failed "
2161 "(gss_inquire_context)\n\n");
2162 #endif
2163 // FIXME: release initiator?
2164 // FIXME: release acceptor?
2165 return false;
2166 }
2167
2168
2169 OM_uint32 minor;
2170
2171 // expose initiator
2172 gss_buffer_desc initiatorbuffer;
2173 pvt->_major=gss_display_name(&pvt->_minor,
2174 initiator,
2175 &initiatorbuffer,
2176 NULL);
2177 if (pvt->_major!=GSS_S_COMPLETE) {
2178 #ifdef DEBUG_GSS
2179 stdoutput.write("failed "
2180 "(display_name(initiator))\n\n");
2181 #endif
2182 return false;
2183 }
2184
2185 delete[] pvt->_initiator;
2186 pvt->_initiator=new char[initiatorbuffer.length+1];
2187 charstring::copy(pvt->_initiator,
2188 (char *)initiatorbuffer.value,
2189 initiatorbuffer.length);
2190 pvt->_initiator[initiatorbuffer.length]='\0';
2191
2192 gss_release_name(&minor,&initiator);
2193 gss_release_buffer(&minor,&initiatorbuffer);
2194
2195
2196 // expose acceptor
2197 gss_buffer_desc acceptorbuffer;
2198 pvt->_major=gss_display_name(&pvt->_minor,
2199 acceptor,
2200 &acceptorbuffer,
2201 NULL);
2202 if (pvt->_major!=GSS_S_COMPLETE) {
2203 #ifdef DEBUG_GSS
2204 stdoutput.write("failed "
2205 "(display_name(acceptor))\n\n");
2206 #endif
2207 return false;
2208 }
2209
2210 delete[] pvt->_acceptor;
2211 pvt->_acceptor=new char[acceptorbuffer.length+1];
2212 charstring::copy(pvt->_acceptor,
2213 (char *)acceptorbuffer.value,
2214 acceptorbuffer.length);
2215 pvt->_acceptor[acceptorbuffer.length]='\0';
2216
2217 gss_release_name(&minor,&acceptor);
2218 gss_release_buffer(&minor,&acceptorbuffer);
2219
2220
2221 // expose isinitiator
2222 pvt->_isinitiator=isinitiator;
2223
2224
2225 // exposeisopen
2226 pvt->_isopen=isopen;
2227
2228
2229 // return success/failure
2230 retval=(pvt->_major==GSS_S_COMPLETE);
2231
2232 #elif defined(RUDIMENTS_HAS_SSPI)
2233
2234 // set initiator and acceptor
2235 if (pvt->_isinitiator) {
2236
2237 // try to get the native names
2238 char *clientname=NULL;
2239 char *servername=NULL;
2240 SecPkgContext_NativeNames nn;
2241 pvt->_sstatus=QueryContextAttributes(
2242 &pvt->_context,
2243 SECPKG_ATTR_NATIVE_NAMES,
2244 &nn);
2245 if (pvt->_sstatus!=SEC_E_UNSUPPORTED_FUNCTION) {
2246 if (SSPI_ERROR(pvt->_sstatus)) {
2247 #ifdef DEBUG_GSS
2248 stdoutput.write("failed "
2249 "(QueryContextAttributes("
2250 "SECPKG_ATTR_NATIVE_NAMES))\n\n");
2251 #endif
2252 return false;
2253 }
2254 clientname=charstring::duplicate(
2255 nn.sClientName);
2256 servername=charstring::duplicate(
2257 nn.sServerName);
2258 FreeContextBuffer(nn.sClientName);
2259 FreeContextBuffer(nn.sServerName);
2260 } else {
2261 // reset status
2262 pvt->_sstatus=SEC_E_OK;
2263 }
2264
2265 // set initiator
2266 delete[] pvt->_initiator;
2267 if (clientname) {
2268 pvt->_initiator=clientname;
2269 } else if (pvt->_credentials) {
2270 pvt->_initiator=charstring::duplicate(
2271 pvt->_credentials->getName());
2272 } else {
2273 pvt->_initiator=NULL;
2274 }
2275
2276 // set acceptor
2277 delete[] pvt->_acceptor;
2278 if (servername) {
2279 pvt->_acceptor=servername;
2280 } else {
2281 pvt->_acceptor=charstring::duplicate(
2282 pvt->_service);
2283 }
2284
2285 } else {
2286
2287 // get the user name
2288 char *username=NULL;
2289 SecPkgContext_Names n;
2290 pvt->_sstatus=QueryContextAttributes(
2291 &pvt->_context,
2292 SECPKG_ATTR_NAMES,
2293 &n);
2294 if (pvt->_sstatus!=SEC_E_UNSUPPORTED_FUNCTION) {
2295 if (SSPI_ERROR(pvt->_sstatus)) {
2296 #ifdef DEBUG_GSS
2297 stdoutput.write("failed "
2298 "(QueryContextAttributes("
2299 "SECPKG_ATTR_NAMES))\n\n");
2300 #endif
2301 return false;
2302 }
2303 username=charstring::duplicate(n.sUserName);
2304 } else {
2305 // FIXME: what to do???
2306 // reset status
2307 pvt->_sstatus=SEC_E_OK;
2308 }
2309
2310 // try to get the target
2311 char *target=NULL;
2312 #ifdef SECPKG_ATTR_CLIENT_SPECIFIED_TARGET
2313 SecPkgContext_ClientSpecifiedTarget csp;
2314 pvt->_sstatus=QueryContextAttributes(
2315 &pvt->_context,
2316 SECPKG_ATTR_CLIENT_SPECIFIED_TARGET,
2317 &csp);
2318 if (pvt->_sstatus!=SEC_E_UNSUPPORTED_FUNCTION &&
2319 pvt->_sstatus!=SEC_E_TARGET_UNKNOWN) {
2320 if (SSPI_ERROR(pvt->_sstatus)) {
2321 #ifdef DEBUG_GSS
2322 stdoutput.write("failed "
2323 "(QueryContextAttributes("
2324 "SECPKG_ATTR_CLIENT_"
2325 "SPECIFIED_TARGET))\n\n");
2326 #endif
2327 return false;
2328 }
2329 target=unicodeToAscii((WCHAR *)csp.sTargetName);
2330 } else {
2331 // FIXME: what to do???
2332 // reset status
2333 pvt->_sstatus=SEC_E_OK;
2334 }
2335 #else
2336 // FIXME: what to do???
2337 #endif
2338
2339 // set initiator
2340 delete[] pvt->_initiator;
2341 pvt->_initiator=username;
2342
2343 // set acceptor
2344 delete[] pvt->_acceptor;
2345 if (target) {
2346 pvt->_acceptor=target;
2347 } else if (pvt->_credentials) {
2348 pvt->_acceptor=charstring::duplicate(
2349 pvt->_credentials->getName());
2350 } else {
2351 pvt->_acceptor=NULL;
2352 }
2353 }
2354
2355
2356 // get actual mechanism...
2357 // If we specified the Negotiate mechanism, then we need to get
2358 // the actual mechanism that was eventually agreed upon. We'll
2359 // also get whether the process was complete or not and use that
2360 // for our "isopen" status.
2361 // If we specified a mechanism other than Negotiate then the
2362 // query will fail. To handle that case, we'll default to
2363 // the requested mech and isopen=true.
2364 const char *mech=(pvt->_desiredmechanism)?
2365 pvt->_desiredmechanism->getString():
2366 "Negotiate";
2367 bool isopen=true;
2368 SecPkgContext_NegotiationInfo neginfo;
2369 pvt->_sstatus=QueryContextAttributes(
2370 &pvt->_context,
2371 SECPKG_ATTR_NEGOTIATION_INFO,
2372 &neginfo);
2373 if (pvt->_sstatus!=SEC_E_UNSUPPORTED_FUNCTION) {
2374 if (SSPI_ERROR(pvt->_sstatus)) {
2375 #ifdef DEBUG_GSS
2376 stdoutput.write("failed "
2377 "(QueryContextAttributes("
2378 "SECPKG_ATTR_NEGOTIATION_INFO))\n\n");
2379 #endif
2380 return false;
2381 }
2382 mech=neginfo.PackageInfo->Name;
2383 isopen=(neginfo.NegotiationState==
2384 SECPKG_NEGOTIATION_COMPLETE);
2385 }
2386
2387 // set actual mechanism
2388 pvt->_actualmechanism.initialize(mech);
2389
2390 // are we using kerberos or schannel?
2391 if (!charstring::compareIgnoringCase(mech,"Kerberos")) {
2392 pvt->_mech=GSS_MECH_KRB;
2393 } else if (charstring::inSetIgnoringCase(mech,schannels)) {
2394 pvt->_mech=GSS_MECH_SCHANNEL;
2395 }
2396
2397 // set isopen
2398 pvt->_isopen=isopen;
2399
2400 // clean up
2401 if (pvt->_sstatus==SEC_E_UNSUPPORTED_FUNCTION) {
2402 // reset status
2403 pvt->_sstatus=SEC_E_OK;
2404 } else {
2405 FreeContextBuffer(neginfo.PackageInfo);
2406 }
2407
2408
2409 // get trailer and block sizes
2410 SecPkgContext_Sizes sizes;
2411 pvt->_sstatus=QueryContextAttributes(
2412 &pvt->_context,
2413 SECPKG_ATTR_SIZES,
2414 &sizes);
2415 if (SSPI_ERROR(pvt->_sstatus)) {
2416 #ifdef DEBUG_GSS
2417 stdoutput.write("failed "
2418 "(QueryContextAttributes("
2419 "SECPKG_ATTR_SIZES))\n\n");
2420 #endif
2421 return false;
2422 }
2423 pvt->_trailersize=sizes.cbSecurityTrailer;
2424 pvt->_blksize=sizes.cbBlockSize;
2425
2426 // get stream header and trailer sizes (Schannel only)
2427 if (pvt->_mech==GSS_MECH_SCHANNEL) {
2428 SecPkgContext_StreamSizes streamsizes;
2429 pvt->_sstatus=QueryContextAttributes(
2430 &pvt->_context,
2431 SECPKG_ATTR_STREAM_SIZES,
2432 &streamsizes);
2433 if (SSPI_ERROR(pvt->_sstatus)) {
2434 #ifdef DEBUG_GSS
2435 stdoutput.write("failed "
2436 "(QueryContextAttributes("
2437 "SECPKG_ATTR_STREAM_SIZES))\n\n");
2438 #endif
2439 return false;
2440 }
2441 pvt->_streamheadersize=streamsizes.cbHeader;
2442 pvt->_streamtrailersize=streamsizes.cbTrailer;
2443 }
2444
2445 retval=true;
2446
2447 #endif
2448
2449 #ifdef DEBUG_GSS
2450 stdoutput.write("success...\n\n");
2451 stdoutput.write("Context {\n");
2452 stdoutput.printf(" file descriptor: %d\n",
2453 (pvt->_fd)?pvt->_fd->getFileDescriptor():-1);
2454 #if !defined(RUDIMENTS_HAS_SSPI)
2455 stdoutput.printf(" desired lifetime: %d\n",
2456 pvt->_desiredlifetime);
2457 stdoutput.printf(" actual lifetime: %d\n",
2458 pvt->_actuallifetime);
2459 #endif
2460 stdoutput.printf(" desired mechanism: %s\n",
2461 (pvt->_desiredmechanism &&
2462 pvt->_desiredmechanism->getString())?
2463 pvt->_desiredmechanism->getString():"(none)");
2464 stdoutput.printf(" actual mechanism: %s\n",
2465 pvt->_actualmechanism.getString());
2466 stdoutput.write(" desired flags:\n");
2467 printFlags(pvt->_desiredflags);
2468 stdoutput.write(" actual flags:\n");
2469 printFlags(pvt->_actualflags);
2470 stdoutput.printf(" service: %s\n",
2471 (pvt->_service)?pvt->_service:"(none)");
2472 stdoutput.printf(" initiator: %s\n",
2473 (pvt->_initiator)?pvt->_initiator:"(none)");
2474 stdoutput.printf(" acceptor: %s\n",
2475 (pvt->_acceptor)?pvt->_acceptor:"(none)");
2476 stdoutput.printf(" is initiator: %s\n",
2477 (pvt->_isinitiator)?"yes":"no");
2478 stdoutput.printf(" is open: %s\n",
2479 (pvt->_isopen)?"yes":"no");
2480 stdoutput.write("}\n");
2481 #endif
2482
2483 return retval;
2484 }
2485
accept()2486 bool gsscontext::accept() {
2487
2488 // release any previously accepted context
2489 close();
2490
2491 #ifdef DEBUG_GSS
2492 stdoutput.write("accept context...\n");
2493 #endif
2494
2495 #if defined(RUDIMENTS_HAS_GSS)
2496
2497 bool error=false;
2498
2499 OM_uint32 minor;
2500
2501 // accept the context...
2502 gss_buffer_desc inputtoken;
2503 gss_buffer_desc outputtoken;
2504
2505 gss_cred_id_t credentials=
2506 (pvt->_credentials)?
2507 (gss_cred_id_t)pvt->_credentials->getCredentials():
2508 GSS_C_NO_CREDENTIAL;
2509
2510 gss_OID actualmechoid=GSS_C_NO_OID;
2511
2512 do {
2513
2514 // receive token from peer, into inputtoken...
2515 uint32_t flags=0;
2516 inputtoken.value=NULL;
2517 inputtoken.length=0;
2518 if (receiveToken(&flags,
2519 &inputtoken.value,
2520 &inputtoken.length)<=0 ||
2521 !checkFlags(flags,TOKEN_FLAGS_TYPE_INITIATE)) {
2522 #ifdef DEBUG_GSS
2523 stdoutput.write("failed (receive)\n\n");
2524 #endif
2525 delete[] (unsigned char *)inputtoken.value;
2526 close();
2527 error=true;
2528 break;
2529 }
2530
2531 // attempt to accept the context
2532 pvt->_major=gss_accept_sec_context(
2533 &pvt->_minor,
2534 &pvt->_context,
2535 credentials,
2536 &inputtoken,
2537 GSS_C_NO_CHANNEL_BINDINGS,
2538 NULL,
2539 &actualmechoid,
2540 &outputtoken,
2541 &pvt->_actualflags,
2542 &pvt->_actuallifetime,
2543 NULL);
2544
2545 // clean up
2546 delete[] (unsigned char *)inputtoken.value;
2547
2548 // bail on error
2549 if (GSS_ERROR(pvt->_major)) {
2550 #ifdef DEBUG_GSS
2551 stdoutput.printf(
2552 "failed "
2553 "(accept_sec_context) %d\n%s\n",
2554 pvt->_major,getStatus());
2555 #endif
2556 close();
2557 error=true;
2558 break;
2559 }
2560
2561 // send token to peer, if necessary
2562 if (outputtoken.length) {
2563 if (sendToken(TOKEN_FLAGS_TYPE_ACCEPT,
2564 outputtoken.value,
2565 outputtoken.length)!=
2566 (ssize_t)outputtoken.length) {
2567 gss_release_buffer(&minor,&outputtoken);
2568 close();
2569 error=true;
2570 break;
2571 }
2572 }
2573
2574 // clean up
2575 gss_release_buffer(&minor,&outputtoken);
2576
2577 } while (pvt->_major==GSS_S_CONTINUE_NEEDED);
2578
2579 // bail on error
2580 if (error || pvt->_major!=GSS_S_COMPLETE) {
2581 return false;
2582 }
2583
2584 // populate actual mechanism
2585 pvt->_actualmechanism.initialize(actualmechoid);
2586
2587 #elif defined(RUDIMENTS_HAS_SSPI)
2588
2589 bool error=false;
2590
2591 // get maxiumum message size...
2592 // At this point, we don't definitively know what mech
2593 // (security package) we'll be using, so we'll get the
2594 // max message size from the Negotiate mech, which will
2595 // be the max message size for all mechs.
2596 if (!getMaxMessageSize("Negotiate")) {
2597 return false;
2598 }
2599
2600 // input buffer
2601 SecBuffer inputtoken;
2602 inputtoken.BufferType=SECBUFFER_TOKEN;
2603
2604 SecBufferDesc inputtokendesc;
2605 inputtokendesc.ulVersion=SECBUFFER_VERSION;
2606 inputtokendesc.cBuffers=1;
2607 inputtokendesc.pBuffers=&inputtoken;
2608
2609 // output buffer
2610 BYTE *outbuf=new BYTE[pvt->_maxmsgsize];
2611
2612 SecBuffer outputtoken;
2613 outputtoken.BufferType=SECBUFFER_TOKEN;
2614 outputtoken.pvBuffer=outbuf;
2615
2616 SecBufferDesc outputtokendesc;
2617 outputtokendesc.ulVersion=SECBUFFER_VERSION;
2618 outputtokendesc.cBuffers=1;
2619 outputtokendesc.pBuffers=&outputtoken;
2620
2621 // get credentials
2622 CredHandle *credentials=
2623 (pvt->_credentials)?
2624 (CredHandle *)(pvt->_credentials->getCredentials()):
2625 NULL;
2626
2627 bool first=true;
2628 do {
2629
2630 // receive token from peer, into inputtoken...
2631 uint32_t flags=0;
2632 void *inbuf=NULL;
2633 size_t inbufsize=0;
2634 ssize_t result=receiveToken(&flags,
2635 &inbuf,
2636 &inbufsize);
2637 if (result<=0 ||
2638 !checkFlags(flags,TOKEN_FLAGS_TYPE_INITIATE)) {
2639 #ifdef DEBUG_GSS
2640 stdoutput.write("failed (receive)\n\n");
2641 #endif
2642 delete[] inbuf;
2643 close();
2644 error=true;
2645 break;
2646 }
2647 inputtoken.pvBuffer=inbuf;
2648 inputtoken.cbBuffer=inbufsize;
2649
2650 // reset output buffer sizes
2651 outputtoken.cbBuffer=pvt->_maxmsgsize;
2652
2653 // attempt to accept the context
2654 pvt->_sstatus=AcceptSecurityContext(
2655 credentials,
2656 (first)?NULL:&pvt->_context,
2657 &inputtokendesc,
2658 pvt->_desiredflags,
2659 SECURITY_NETWORK_DREP,
2660 &pvt->_context,
2661 &outputtokendesc,
2662 &pvt->_actualflags,
2663 &pvt->_actuallifetime);
2664
2665 // clean up
2666 delete[] inbuf;
2667
2668 // bail on error
2669 if (SSPI_ERROR(pvt->_sstatus) &&
2670 pvt->_sstatus!=SEC_E_INCOMPLETE_MESSAGE) {
2671 #ifdef DEBUG_GSS
2672 stdoutput.printf(
2673 "failed "
2674 "(AcceptSecurityContext)"
2675 "\n%s\n",
2676 getStatus());
2677 #endif
2678 close();
2679 error=true;
2680 break;
2681 }
2682
2683 // complete the token, if needed
2684 if (pvt->_sstatus==SEC_I_COMPLETE_NEEDED ||
2685 pvt->_sstatus==SEC_I_COMPLETE_AND_CONTINUE) {
2686 pvt->_sstatus=CompleteAuthToken(
2687 &pvt->_context,
2688 &outputtokendesc);
2689 if (SSPI_ERROR(pvt->_sstatus)) {
2690 #ifdef DEBUG_GSS
2691 stdoutput.printf(
2692 "failed "
2693 "(CompleteAuthToken)"
2694 "\n%s\n",
2695 getStatus());
2696 #endif
2697 close();
2698 error=true;
2699 break;
2700 }
2701 }
2702
2703 first=false;
2704
2705 // send token to peer, if necessary
2706 if (outputtoken.cbBuffer &&
2707 pvt->_sstatus!=SEC_E_INCOMPLETE_MESSAGE) {
2708 if (sendToken(TOKEN_FLAGS_TYPE_ACCEPT,
2709 outbuf,
2710 outputtoken.cbBuffer)!=
2711 (ssize_t)outputtoken.cbBuffer) {
2712 #ifdef DEBUG_GSS
2713 stdoutput.write(
2714 "failed (send)\n\n");
2715 #endif
2716 close();
2717 error=true;
2718 break;
2719 }
2720 }
2721
2722 } while (pvt->_sstatus==SEC_I_CONTINUE_NEEDED ||
2723 pvt->_sstatus==SEC_I_COMPLETE_AND_CONTINUE ||
2724 pvt->_sstatus==SEC_E_INCOMPLETE_MESSAGE);
2725
2726 delete[] outbuf;
2727
2728 // actual mechanism will be populated by inquire() below...
2729
2730 // bail on error
2731 if (error || pvt->_sstatus!=SEC_E_OK) {
2732 return false;
2733 }
2734 #else
2735 #ifdef DEBUG_GSS
2736 stdoutput.write("failed (not supported)\n\n");
2737 #endif
2738 RUDIMENTS_SET_ENOSYS
2739 return false;
2740 #endif
2741
2742 #ifdef DEBUG_GSS
2743 stdoutput.printf("success\n\n");
2744 #endif
2745
2746 // get additional info about the context
2747 return inquire();
2748 }
2749
close()2750 bool gsscontext::close() {
2751
2752 #if defined(RUDIMENTS_HAS_GSS)
2753 // delete the context
2754 if (pvt->_context!=GSS_C_NO_CONTEXT) {
2755 gss_delete_sec_context(
2756 &pvt->_minor,&pvt->_context,GSS_C_NO_BUFFER);
2757 // automatically sets pvt->_context to GSS_C_NO_CONTEXT
2758 }
2759 #elif defined(RUDIMENTS_HAS_SSPI)
2760 DeleteSecurityContext(&pvt->_context);
2761 bytestring::zero(&pvt->_context,sizeof(pvt->_context));
2762 if (pvt->_freecredentials) {
2763 delete pvt->_credentials;
2764 pvt->_credentials=NULL;
2765 }
2766 pvt->_freecredentials=false;
2767 #endif
2768
2769 // reset initiator and acceptor names
2770 delete[] pvt->_initiator;
2771 pvt->_initiator=NULL;
2772
2773 delete[] pvt->_acceptor;
2774 pvt->_acceptor=NULL;
2775
2776 // reset the "actuals"
2777 #if defined(RUDIMENTS_HAS_GSS)
2778 pvt->_actuallifetime=0;
2779 #elif defined(RUDIMENTS_HAS_SSPI)
2780 pvt->_maxmsgsize=0;
2781 pvt->_streamheadersize=0;
2782 pvt->_streamtrailersize=0;
2783 pvt->_trailersize=0;
2784 pvt->_blksize=0;
2785 pvt->_mech=GSS_MECH_OTHER;
2786 pvt->_actuallifetime.u.LowPart=0;
2787 pvt->_actuallifetime.u.HighPart=0;
2788 #else
2789 pvt->_actuallifetime=0;
2790 #endif
2791 pvt->_actualmechanism.clear();
2792 pvt->_actualflags=0;
2793
2794 // reset states
2795 pvt->_isinitiator=false;
2796 pvt->_isopen=false;
2797 pvt->_readbuffer.clear();
2798 pvt->_readbufferpos=0;
2799
2800 return true;
2801 }
2802
getSizeMax()2803 ssize_t gsscontext::getSizeMax() {
2804 // FIXME: there's probably an intelligent
2805 // way of deciding what this should be
2806 return 65536;
2807 }
2808
getActualLifetime()2809 uint32_t gsscontext::getActualLifetime() {
2810 #if defined(RUDIMENTS_HAS_GSS)
2811 return pvt->_actuallifetime;
2812 #elif defined(RUDIMENTS_HAS_SSPI)
2813 // this loses precision...
2814 return (uint32_t)pvt->_actuallifetime.QuadPart;
2815 #else
2816 return pvt->_actuallifetime;
2817 #endif
2818 }
2819
getActualMechanism()2820 gssmechanism *gsscontext::getActualMechanism() {
2821 return &pvt->_actualmechanism;
2822 }
2823
getActualFlags()2824 uint32_t gsscontext::getActualFlags() {
2825 return pvt->_actualflags;
2826 }
2827
getRemainingLifetime()2828 uint32_t gsscontext::getRemainingLifetime() {
2829 #if defined(RUDIMENTS_HAS_GSS)
2830 OM_uint32 remainingtime;
2831 pvt->_major=gss_context_time(&pvt->_minor,
2832 pvt->_context,
2833 &remainingtime);
2834 return (pvt->_major==GSS_S_COMPLETE)?remainingtime:0;
2835 #elif defined(RUDIMENTS_HAS_SSPI)
2836 SecPkgContext_Lifespan l;
2837 pvt->_sstatus=QueryContextAttributes(
2838 &pvt->_context,
2839 SECPKG_ATTR_LIFESPAN,
2840 &l);
2841 if (SSPI_ERROR(pvt->_sstatus)) {
2842 #ifdef DEBUG_GSS
2843 stdoutput.write("failed "
2844 "(QueryContextAttributes("
2845 "SECPKG_ATTR_LIFESPAN))\n\n");
2846 #endif
2847 return 0;
2848 }
2849 // FIXME: get now and subtract from l.tsExpiry.QuadPart
2850 return 0;
2851 #else
2852 return 0;
2853 #endif
2854 }
2855
getInitiator()2856 const char *gsscontext::getInitiator() {
2857 return pvt->_initiator;
2858 }
2859
getAcceptor()2860 const char *gsscontext::getAcceptor() {
2861 return pvt->_acceptor;
2862 }
2863
getIsInitiator()2864 bool gsscontext::getIsInitiator() {
2865 return pvt->_isinitiator;
2866 }
2867
getIsOpen()2868 bool gsscontext::getIsOpen() {
2869 return pvt->_isopen;
2870 }
2871
wrap(const unsigned char * input,size_t inputsize,unsigned char ** output,size_t * outputsize)2872 bool gsscontext::wrap(const unsigned char *input,
2873 size_t inputsize,
2874 unsigned char **output,
2875 size_t *outputsize) {
2876 return wrap(input,inputsize,true,output,outputsize,NULL);
2877 }
2878
wrap(const unsigned char * input,size_t inputsize,bool useencryption,unsigned char ** output,size_t * outputsize,bool * encryptionused)2879 bool gsscontext::wrap(const unsigned char *input,
2880 size_t inputsize,
2881 bool useencryption,
2882 unsigned char **output,
2883 size_t *outputsize,
2884 bool *encryptionused) {
2885
2886 #ifdef DEBUG_GSS_WRAP
2887 stdoutput.printf("wrap(%d,",inputsize);
2888 stdoutput.safePrint(input,inputsize);
2889 stdoutput.write(")\n");
2890 #endif
2891
2892 #if defined(RUDIMENTS_HAS_GSS)
2893
2894 // configure input buffer
2895 gss_buffer_desc inputbuffer;
2896 inputbuffer.value=(void *)input;
2897 inputbuffer.length=inputsize;
2898
2899 // declare output buffer
2900 gss_buffer_desc outputbuffer;
2901
2902 // use encryption or not
2903 int useenc=useencryption;
2904 int encused=0;
2905
2906 // wrap the input
2907 pvt->_major=gss_wrap(&pvt->_minor,
2908 pvt->_context,
2909 useenc,
2910 GSS_C_QOP_DEFAULT,
2911 &inputbuffer,
2912 &encused,
2913 &outputbuffer);
2914
2915 // whether encryption was used or not
2916 if (encryptionused) {
2917 *encryptionused=encused;
2918 }
2919
2920 if (pvt->_major==GSS_S_COMPLETE) {
2921
2922 // copy-out the wrapped
2923 if (output) {
2924 *output=(unsigned char *)
2925 bytestring::duplicate(
2926 outputbuffer.value,
2927 outputbuffer.length);
2928 }
2929 if (outputsize) {
2930 *outputsize=outputbuffer.length;
2931 }
2932
2933 // clean up
2934 OM_uint32 minor;
2935 gss_release_buffer(&minor,&outputbuffer);
2936
2937 #ifdef DEBUG_GSS_WRAP
2938 stdoutput.write(" success\n\n");
2939 #endif
2940
2941 return true;
2942 }
2943
2944 // FIXME: are there cases where outputbuffer
2945 // should be cleaned up here too?
2946
2947 #ifdef DEBUG_GSS_WRAP
2948 stdoutput.printf(" failed\n%s\n\n",getStatus());
2949 #endif
2950
2951 #elif defined(RUDIMENTS_HAS_SSPI)
2952
2953 // EncryptMessage encrypts a set of buffers. Exactly what
2954 // buffers and how the encrypted data is formatted in them
2955 // depends on the encryption package...
2956
2957 if (pvt->_mech==GSS_MECH_KRB) {
2958
2959 // For kerberos, "trailer", "data", and "padding"
2960 // buffers are required, in that order.
2961
2962 // allocate a temp buffer, large enough to hold the
2963 // input, trailer, and padding
2964 size_t tempsize=pvt->_trailersize+
2965 inputsize+
2966 pvt->_blksize;
2967 BYTE *temp=new BYTE[tempsize];
2968 bytestring::zero(temp,tempsize);
2969
2970 // initialize the temp buffer with the input
2971 bytestring::copy(temp+pvt->_trailersize,
2972 input,inputsize);
2973
2974 // prepare security buffers
2975 SecBuffer secbuf[3];
2976 secbuf[0].BufferType=SECBUFFER_TOKEN;
2977 secbuf[0].cbBuffer=pvt->_trailersize;
2978 secbuf[0].pvBuffer=temp;
2979
2980 secbuf[1].BufferType=SECBUFFER_DATA;
2981 // FIXME: this can't be larger than pvt->_maxmsgsize
2982 secbuf[1].cbBuffer=inputsize;
2983 secbuf[1].pvBuffer=temp+pvt->_trailersize;
2984
2985 secbuf[2].BufferType=SECBUFFER_PADDING;
2986 secbuf[2].cbBuffer=pvt->_blksize;
2987 secbuf[2].pvBuffer=temp+pvt->_trailersize+inputsize;
2988
2989 SecBufferDesc secbufdesc;
2990 secbufdesc.ulVersion=SECBUFFER_VERSION;
2991 secbufdesc.cBuffers=3;
2992 secbufdesc.pBuffers=secbuf;
2993
2994 // encrypt the input
2995 pvt->_sstatus=EncryptMessage(
2996 &pvt->_context,0,&secbufdesc,0);
2997
2998 // copy out the parts of the buffers
2999 // that EncryptMessage ended up using
3000 *outputsize=secbuf[0].cbBuffer+
3001 secbuf[1].cbBuffer+
3002 secbuf[2].cbBuffer;
3003 *output=new BYTE[*outputsize];
3004 bytestring::copy(*output,secbuf[0].pvBuffer,
3005 secbuf[0].cbBuffer);
3006 bytestring::copy(*output+secbuf[0].cbBuffer,
3007 secbuf[1].pvBuffer,
3008 secbuf[1].cbBuffer);
3009 bytestring::copy(*output+secbuf[0].cbBuffer+
3010 secbuf[1].cbBuffer,
3011 secbuf[2].pvBuffer,
3012 secbuf[2].cbBuffer);
3013
3014 } else if (pvt->_mech==GSS_MECH_SCHANNEL) {
3015
3016 // For schannel, "stream header", "stream trailer",
3017 // and "empty" buffers are required, in that order.
3018
3019 // allocate the output buffer, large enough to hold the
3020 // input, trailer, and padding
3021 *outputsize=pvt->_streamheadersize+
3022 inputsize+pvt->_streamtrailersize;
3023 *output=new BYTE[*outputsize];
3024
3025 // initialize the output buffer with the input
3026 bytestring::copy(*output+pvt->_streamheadersize,
3027 input,inputsize);
3028
3029 // prepare security buffers
3030 SecBuffer secbuf[4];
3031 secbuf[0].BufferType=SECBUFFER_STREAM_HEADER;
3032 secbuf[0].cbBuffer=pvt->_streamheadersize;
3033 secbuf[0].pvBuffer=*output;
3034
3035 secbuf[1].BufferType=SECBUFFER_DATA;
3036 // FIXME: this can't be larger than pvt->_maxmsgsize
3037 secbuf[1].cbBuffer=inputsize;
3038 secbuf[1].pvBuffer=*output+pvt->_streamheadersize;
3039
3040 secbuf[2].BufferType=SECBUFFER_STREAM_TRAILER;
3041 secbuf[2].cbBuffer=pvt->_trailersize;
3042 secbuf[2].pvBuffer=*output+
3043 pvt->_streamheadersize+
3044 inputsize;
3045
3046 secbuf[3].BufferType=SECBUFFER_EMPTY;
3047 secbuf[3].cbBuffer=0;
3048 secbuf[3].pvBuffer=NULL;
3049
3050 SecBufferDesc secbufdesc;
3051 secbufdesc.ulVersion=SECBUFFER_VERSION;
3052 secbufdesc.cBuffers=4;
3053 secbufdesc.pBuffers=secbuf;
3054
3055 // encrypt the input
3056 pvt->_sstatus=EncryptMessage(
3057 &pvt->_context,0,&secbufdesc,0);
3058
3059 } else {
3060
3061 // In the general case, a "data" and "trailer" buffer
3062 // are required and the data buffer must hold the
3063 // unencrypted data. This data will be overwritten and
3064 // any overflow will be placed in the trailer.
3065
3066 // allocate a buffer to hold the input size,
3067 // input, trailer size, and trailer
3068 *outputsize=sizeof(DWORD)+inputsize+
3069 sizeof(DWORD)+pvt->_trailersize;
3070 *output=new BYTE[*outputsize];
3071
3072 // store that data, in that order
3073 bytestring::copy(*output,&inputsize,sizeof(DWORD));
3074 bytestring::copy(*output+sizeof(DWORD),input,inputsize);
3075 bytestring::copy(*output+sizeof(DWORD)+inputsize,
3076 &pvt->_trailersize,sizeof(DWORD));
3077
3078 // prepare security buffers
3079 SecBuffer secbuf[2];
3080 secbuf[0].BufferType=SECBUFFER_DATA;
3081 // FIXME: this can't be larger than pvt->_maxmsgsize
3082 secbuf[0].cbBuffer=inputsize;
3083 secbuf[0].pvBuffer=*output+sizeof(DWORD);
3084
3085 secbuf[1].BufferType=SECBUFFER_TOKEN;
3086 secbuf[1].cbBuffer=pvt->_trailersize;
3087 secbuf[1].pvBuffer=*output+sizeof(DWORD)+
3088 inputsize+sizeof(DWORD);
3089
3090 SecBufferDesc secbufdesc;
3091 secbufdesc.ulVersion=SECBUFFER_VERSION;
3092 secbufdesc.cBuffers=2;
3093 secbufdesc.pBuffers=secbuf;
3094
3095 // encrypt the input
3096 pvt->_sstatus=EncryptMessage(
3097 &pvt->_context,0,&secbufdesc,0);
3098 }
3099
3100 if (!SSPI_ERROR(pvt->_sstatus)) {
3101 #ifdef DEBUG_GSS_WRAP
3102 stdoutput.write(" success\n\n");
3103 #endif
3104 return true;
3105 }
3106
3107 #ifdef DEBUG_GSS_WRAP
3108 stdoutput.printf(" failed\n%s\n\n",getStatus());
3109 #endif
3110 #else
3111 #ifdef DEBUG_GSS_WRAP
3112 stdoutput.printf(" failed (not supported)\n\n");
3113 #endif
3114 RUDIMENTS_SET_ENOSYS
3115 #endif
3116
3117 return false;
3118 }
3119
unwrap(const unsigned char * input,size_t inputsize,unsigned char ** output,size_t * outputsize)3120 bool gsscontext::unwrap(const unsigned char *input,
3121 size_t inputsize,
3122 unsigned char **output,
3123 size_t *outputsize) {
3124 return unwrap(input,inputsize,output,outputsize,NULL);
3125 }
3126
unwrap(const unsigned char * input,size_t inputsize,unsigned char ** output,size_t * outputsize,bool * decryptionused)3127 bool gsscontext::unwrap(const unsigned char *input,
3128 size_t inputsize,
3129 unsigned char **output,
3130 size_t *outputsize,
3131 bool *decryptionused) {
3132
3133 bool retval=false;
3134
3135 #if defined(RUDIMENTS_HAS_GSS)
3136
3137 // configure input buffer
3138 gss_buffer_desc inputbuffer;
3139 inputbuffer.value=(void *)input;
3140 inputbuffer.length=inputsize;
3141
3142 // declare output buffer
3143 gss_buffer_desc outputbuffer;
3144
3145 // decryption used or not
3146 int decused=0;
3147
3148 // unwrap the input
3149 pvt->_major=gss_unwrap(&pvt->_minor,
3150 pvt->_context,
3151 &inputbuffer,
3152 &outputbuffer,
3153 &decused,
3154 NULL);
3155
3156 // whether decryption was used or not
3157 if (decryptionused) {
3158 *decryptionused=decused;
3159 }
3160
3161 if (pvt->_major==GSS_S_COMPLETE) {
3162
3163 // copy-out the unwrapped
3164 if (output) {
3165 *output=(unsigned char *)
3166 bytestring::duplicate(
3167 outputbuffer.value,
3168 outputbuffer.length);
3169 }
3170 if (outputsize) {
3171 *outputsize=outputbuffer.length;
3172 }
3173
3174 // clean up
3175 OM_uint32 minor;
3176 gss_release_buffer(&minor,&outputbuffer);
3177 retval=true;
3178 }
3179
3180 // FIXME: are there cases where outputbuffer
3181 // should be cleaned up here too?
3182
3183 #ifdef DEBUG_GSS_WRAP
3184 if (retval) {
3185 stdoutput.printf("unwrap(%d,",*outputsize);
3186 stdoutput.safePrint(*output,*outputsize);
3187 stdoutput.write(") success\n\n");
3188 } else {
3189 stdoutput.printf("unwrap() failed\n%s\n\n",
3190 getStatus());
3191 }
3192 #endif
3193
3194 #elif defined(RUDIMENTS_HAS_SSPI)
3195
3196 ULONG qop=0;
3197
3198 // DecryptMessage decrypts a set of buffers. Exactly what
3199 // buffers and how the encrypted data is formatted in them
3200 // depends on the encryption package...
3201
3202 if (pvt->_mech==GSS_MECH_KRB) {
3203
3204 // For kerberos, "stream" and "data" buffers are
3205 // required, in that order. DecryptMessage will
3206 // allocate space to store the decrypted data and
3207 // update the "data" buffer to point to it and
3208 // store its size.
3209
3210 // prepare buffers
3211 SecBuffer secbuf[2];
3212 secbuf[0].BufferType=SECBUFFER_STREAM;
3213 secbuf[0].cbBuffer=inputsize;
3214 secbuf[0].pvBuffer=(void *)input;
3215
3216 secbuf[1].BufferType=SECBUFFER_DATA;
3217 secbuf[1].cbBuffer=0;
3218 secbuf[1].pvBuffer=NULL;
3219
3220 SecBufferDesc secbufdesc;
3221 secbufdesc.ulVersion=SECBUFFER_VERSION;
3222 secbufdesc.cBuffers=2;
3223 secbufdesc.pBuffers=secbuf;
3224
3225 // decrypt the input
3226 pvt->_sstatus=DecryptMessage(
3227 &pvt->_context,&secbufdesc,0,&qop);
3228
3229 // copy out the decrypted data
3230 *outputsize=secbuf[1].cbBuffer;
3231 *output=(unsigned char *)bytestring::duplicate(
3232 secbuf[1].pvBuffer,
3233 *outputsize);
3234 // FIXME: FreeContextBuffer(secbuf[1].pvBuffer) ???
3235
3236 } else if (pvt->_mech==GSS_MECH_SCHANNEL) {
3237
3238 // For schannel, 1 "data" buffer and 3 "empty" buffers
3239 // are required.
3240
3241 // prepare buffers
3242 SecBuffer secbuf[4];
3243 secbuf[0].BufferType=SECBUFFER_DATA;
3244 secbuf[0].cbBuffer=inputsize;
3245 secbuf[0].pvBuffer=(void *)input;
3246 secbuf[1].BufferType=SECBUFFER_EMPTY;
3247 secbuf[2].BufferType=SECBUFFER_EMPTY;
3248 secbuf[3].BufferType=SECBUFFER_EMPTY;
3249
3250 SecBufferDesc secbufdesc;
3251 secbufdesc.ulVersion=SECBUFFER_VERSION;
3252 secbufdesc.cBuffers=4;
3253 secbufdesc.pBuffers=secbuf;
3254
3255 // decrypt the input
3256 pvt->_sstatus=DecryptMessage(
3257 &pvt->_context,&secbufdesc,0,&qop);
3258
3259 // One of the buffers will contain the decrypted
3260 // data. Another may contain "extra" data.
3261 SecBuffer *extrabuf=NULL;
3262 for (uint8_t i=0; i<4; i++) {
3263 if (secbuf[i].BufferType==
3264 SECBUFFER_DATA) {
3265 // copy out the decrypted data
3266 *outputsize=secbuf[i].cbBuffer;
3267 *output=(unsigned char *)
3268 bytestring::duplicate(
3269 secbuf[i].pvBuffer,
3270 *outputsize);
3271 } else if (secbuf[i].BufferType==
3272 SECBUFFER_EXTRA) {
3273 extrabuf=secbuf;
3274 }
3275 }
3276
3277 // FIXME: The peer might want to renegotiate.
3278 // That extrabuf is necessary to do that...
3279 if (pvt->_sstatus==SEC_I_RENEGOTIATE) {
3280 stdoutput.printf("FIXME: peer wants "
3281 "to renegotiate\n");
3282 }
3283
3284 } else {
3285
3286 // In the general case, "data" and "trailer" buffers
3287 // were required to store the encrypted data.
3288 // DecryptMessage needs to know the location of each
3289 // and will ultimately store the decrypted data in the
3290 // "data" buffer.
3291
3292 // get output size, output, trailer size, and trailer
3293 bytestring::copy(outputsize,input,sizeof(DWORD));
3294
3295 // create a buffer to store the output and initialize
3296 // it with the contents of the "data" buffer
3297 *output=(unsigned char *)bytestring::duplicate(
3298 (input+sizeof(DWORD)),
3299 *outputsize);
3300
3301 // get the trailer size and location of the trailer
3302 DWORD trailersize;
3303 bytestring::copy(&trailersize,
3304 (DWORD *)(input+sizeof(DWORD)+*outputsize),
3305 sizeof(DWORD));
3306 BYTE *trailer=(BYTE *)
3307 (input+sizeof(DWORD)+*outputsize+sizeof(DWORD));
3308
3309 // prepare buffers
3310 SecBuffer secbuf[2];
3311 secbuf[0].BufferType=SECBUFFER_DATA;
3312 secbuf[0].cbBuffer=*outputsize;
3313 secbuf[0].pvBuffer=*output;
3314
3315 secbuf[1].BufferType=SECBUFFER_TOKEN;
3316 secbuf[1].cbBuffer=trailersize;
3317 secbuf[1].pvBuffer=trailer;
3318
3319 SecBufferDesc secbufdesc;
3320 secbufdesc.ulVersion=SECBUFFER_VERSION;
3321 secbufdesc.cBuffers=2;
3322 secbufdesc.pBuffers=secbuf;
3323
3324 // decrypt the input
3325 pvt->_sstatus=DecryptMessage(
3326 &pvt->_context,&secbufdesc,0,&qop);
3327 }
3328
3329 retval=!SSPI_ERROR(pvt->_sstatus);
3330
3331 #ifdef DEBUG_GSS_WRAP
3332 if (retval) {
3333 stdoutput.printf("unwrap(%d,",*outputsize);
3334 stdoutput.safePrint(*output,*outputsize);
3335 stdoutput.write(") success\n\n");
3336 } else {
3337 stdoutput.printf("unwrap() failed\n%s\n\n",
3338 getStatus());
3339 }
3340 #endif
3341 #else
3342 RUDIMENTS_SET_ENOSYS
3343 #ifdef DEBUG_GSS
3344 stdoutput.write("failed (not supported)\n\n");
3345 #endif
3346 RUDIMENTS_SET_ENOSYS
3347 #endif
3348
3349 return retval;
3350 }
3351
getMic(const unsigned char * message,size_t messagesize,unsigned char ** mic,size_t * micsize)3352 bool gsscontext::getMic(const unsigned char *message,
3353 size_t messagesize,
3354 unsigned char **mic,
3355 size_t *micsize) {
3356
3357 #if defined(RUDIMENTS_HAS_GSS)
3358
3359 // configure message buffer
3360 gss_buffer_desc messagebuffer;
3361 messagebuffer.value=(void *)message;
3362 messagebuffer.length=messagesize;
3363
3364 // declare mic buffer
3365 gss_buffer_desc micbuffer;
3366
3367 // get the mic
3368 pvt->_major=gss_get_mic(&pvt->_minor,
3369 pvt->_context,
3370 GSS_C_QOP_DEFAULT,
3371 &messagebuffer,
3372 &micbuffer);
3373
3374 if (pvt->_major==GSS_S_COMPLETE) {
3375
3376 // copy-out the mic
3377 if (mic) {
3378 *mic=(unsigned char *)
3379 bytestring::duplicate(
3380 micbuffer.value,
3381 micbuffer.length);
3382 }
3383 if (micsize) {
3384 *micsize=micbuffer.length;
3385 }
3386
3387 // clean up
3388 OM_uint32 minor;
3389 gss_release_buffer(&minor,&micbuffer);
3390
3391 return true;
3392 }
3393
3394 // FIXME: are there cases where micbuffer
3395 // should be cleaned up here too?
3396 #elif defined(RUDIMENTS_HAS_SSPI)
3397 // FIXME: implement this using MakeSignature
3398 RUDIMENTS_SET_ENOSYS
3399 #else
3400 RUDIMENTS_SET_ENOSYS
3401 #endif
3402
3403 return false;
3404 }
3405
verifyMic(const unsigned char * message,size_t messagesize,const unsigned char * mic,size_t micsize)3406 bool gsscontext::verifyMic(const unsigned char *message,
3407 size_t messagesize,
3408 const unsigned char *mic,
3409 size_t micsize) {
3410
3411 #if defined(RUDIMENTS_HAS_GSS)
3412
3413 // configure message buffer
3414 gss_buffer_desc messagebuffer;
3415 messagebuffer.value=(void *)message;
3416 messagebuffer.length=messagesize;
3417
3418 // configure mic buffer
3419 gss_buffer_desc micbuffer;
3420 micbuffer.value=(void *)mic;
3421 micbuffer.length=micsize;
3422
3423 // verify the mic
3424 pvt->_major=gss_verify_mic(&pvt->_minor,
3425 pvt->_context,
3426 &messagebuffer,
3427 &micbuffer,
3428 NULL);
3429
3430 // return success/failure
3431 return (pvt->_major==GSS_S_COMPLETE);
3432 #elif defined(RUDIMENTS_HAS_SSPI)
3433 // FIXME: implement this using VerifySignature
3434 RUDIMENTS_SET_ENOSYS
3435 #else
3436 RUDIMENTS_SET_ENOSYS
3437 #endif
3438
3439 return false;
3440 }
3441
read(void * buf,ssize_t count)3442 ssize_t gsscontext::read(void *buf, ssize_t count) {
3443
3444 // first, return any buffered data
3445 ssize_t bytestoread=count;
3446 ssize_t bytesread=0;
3447 size_t pendingbytes=pending();
3448 if (pendingbytes) {
3449
3450 // copy data out...
3451 if (pendingbytes<=(size_t)bytestoread) {
3452 bytestring::copy(
3453 buf,pvt->_readbuffer.getBuffer()+
3454 pvt->_readbufferpos,pendingbytes);
3455 pvt->_readbuffer.clear();
3456 pvt->_readbufferpos=0;
3457 bytesread=pendingbytes;
3458 buf=((unsigned char *)buf)+pendingbytes;
3459 bytestoread-=pendingbytes;
3460 } else {
3461 bytestring::copy(
3462 buf,pvt->_readbuffer.getBuffer()+
3463 pvt->_readbufferpos,bytestoread);
3464 pvt->_readbufferpos+=bytestoread;
3465 bytesread=bytestoread;
3466 buf=((unsigned char *)buf)+bytestoread;
3467 bytestoread=0;
3468 }
3469 }
3470
3471 // next, receive a token from the peer...
3472 //
3473 // This should be a low-level read, and it should allow short reads.
3474 // I.e. it should't try to receive multiple tokens until it's read
3475 // "count" bytes. It should just return "what's currently available",
3476 // and in this case that should come from whatever was already buffered,
3477 // and/or the next token. The filedescriptor class's read-buffering
3478 // depends on this method having short-read behavior. We'll leave it
3479 // up to the filedescriptor class to make multiple calls to satisfy
3480 // cases where short-reads aren't allowed.
3481
3482 // receive token
3483 uint32_t tokenflags=0;
3484 void *tokendata=NULL;
3485 size_t tokensize=0;
3486 ssize_t result=receiveToken(&tokenflags,&tokendata,&tokensize);
3487 if (result<=0 || !checkFlags(tokenflags,TOKEN_FLAGS_TYPE_DATA)) {
3488 delete[] (unsigned char *)tokendata;
3489 return result;
3490 }
3491
3492 // unwrap
3493 unsigned char *data=NULL;
3494 size_t datasize=0;
3495 if (!unwrap((unsigned char *)tokendata,tokensize,
3496 &data,&datasize)) {
3497 delete[] (unsigned char *)tokendata;
3498 delete[] data;
3499 return RESULT_ERROR;
3500 }
3501 delete[] (unsigned char *)tokendata;
3502
3503 // copy data out...
3504 if (datasize<=(size_t)bytestoread) {
3505 bytestring::copy(buf,data,datasize);
3506 bytesread+=datasize;
3507 } else {
3508 bytestring::copy(buf,data,bytestoread);
3509 bytesread+=bytestoread;
3510
3511 // buffer what wasn't copied out
3512 pvt->_readbuffer.append(data+bytesread,
3513 datasize-bytesread);
3514 }
3515 delete[] data;
3516
3517 return bytesread;
3518 }
3519
receiveToken(uint32_t * tokenflags,void ** tokendata,size_t * tokensize)3520 ssize_t gsscontext::receiveToken(uint32_t *tokenflags,
3521 void **tokendata,
3522 size_t *tokensize) {
3523 switch (pvt->_tokenformat) {
3524 case GSSTOKENFORMAT_KRB:
3525 return receiveKrbToken(tokenflags,tokendata,tokensize);
3526 case GSSTOKENFORMAT_TLS:
3527 return receiveTlsToken(tokenflags,tokendata,tokensize);
3528 default:
3529 return RESULT_ERROR;
3530 }
3531 }
3532
receiveKrbToken(uint32_t * tokenflags,void ** tokendata,size_t * tokensize)3533 ssize_t gsscontext::receiveKrbToken(uint32_t *tokenflags,
3534 void **tokendata,
3535 size_t *tokensize) {
3536
3537 #ifdef DEBUG_GSS_RECEIVE
3538 stdoutput.write("receiveKrbToken(");
3539 #endif
3540
3541 // read token flags
3542 ssize_t result=fullRead(tokenflags,sizeof(*tokenflags));
3543 if (result!=sizeof(*tokenflags)) {
3544 #ifdef DEBUG_GSS_RECEIVE
3545 stdoutput.write(") failed (flags)\n");
3546 #endif
3547 return (result<=0)?result:RESULT_ERROR;
3548 }
3549 *tokenflags=pvt->_fd->netToHost(*tokenflags);
3550
3551 #ifdef DEBUG_GSS_RECEIVE
3552 stdoutput.printf("%08x,",*tokenflags);
3553 #endif
3554
3555 // read token size
3556 uint32_t size;
3557 result=fullRead(&size,sizeof(size));
3558 if (result!=sizeof(size)) {
3559 #ifdef DEBUG_GSS_RECEIVE
3560 stdoutput.write(") failed (size)\n");
3561 #endif
3562 return (result<=0)?result:RESULT_ERROR;
3563 }
3564 size=pvt->_fd->netToHost(size);
3565
3566 #ifdef DEBUG_GSS_RECEIVE
3567 stdoutput.printf("%d,",size);
3568 #endif
3569
3570 // reject tokens that are too large
3571 // (use getSizeMax()*2 to allow for the expansion of the encryption)
3572 // FIXME: There's probably a more accurate way to decide what the
3573 // maximum size of the encrypted data could be.
3574 if (size>(uint32_t)getSizeMax()*2) {
3575 #ifdef DEBUG_GSS_RECEIVE
3576 stdoutput.write(") failed (size too large)\n");
3577 #endif
3578 #ifdef EMSGSIZE
3579 error::setErrorNumber(EMSGSIZE);
3580 #endif
3581 #ifdef WSAMSGSIZE
3582 error::setNativeErrorNumber(WSAMSGSIZE);
3583 #endif
3584 return RESULT_ERROR;
3585 }
3586
3587 // copy size out
3588 *tokensize=size;
3589
3590 // read data
3591 *tokendata=NULL;
3592 if (size) {
3593 *tokendata=new unsigned char[size];
3594
3595 // read token data
3596 result=fullRead(*tokendata,size);
3597 if (result!=(ssize_t)size) {
3598 #ifdef DEBUG_GSS_RECEIVE
3599 stdoutput.write(") failed (data)\n");
3600 #endif
3601 return (result<=0)?result:RESULT_ERROR;
3602 }
3603 }
3604
3605 #ifdef DEBUG_GSS_RECEIVE
3606 stdoutput.safePrint((unsigned char *)*tokendata,*tokensize);
3607 stdoutput.write(") success\n\n");
3608 #endif
3609 return result;
3610 }
3611
receiveTlsToken(uint32_t * tokenflags,void ** tokendata,size_t * tokensize)3612 ssize_t gsscontext::receiveTlsToken(uint32_t *tokenflags,
3613 void **tokendata,
3614 size_t *tokensize) {
3615
3616 #ifdef DEBUG_GSS_RECEIVE
3617 stdoutput.write("receiveTlsToken(");
3618 #endif
3619
3620 // read header
3621 // header format:
3622 // * record type - 1 byte
3623 // * tls/ssl version - 2 bytes (network byte order)
3624 // * data size - 2 bytes (network byte order)
3625 unsigned char header[5];
3626 ssize_t result=fullRead(header,sizeof(header));
3627 if (result!=sizeof(header)) {
3628 #ifdef DEBUG_GSS_RECEIVE
3629 stdoutput.write(") failed (header)\n");
3630 #endif
3631 return (result<=0)?result:RESULT_ERROR;
3632 }
3633
3634 // get record size
3635 uint16_t size=0;
3636 bytestring::copy(&size,&(header[3]),sizeof(uint16_t));
3637 size=pvt->_fd->netToHost(size);
3638 #ifdef DEBUG_GSS_RECEIVE
3639 stdoutput.printf("%d,",size);
3640 #endif
3641
3642 // reject records that are too large
3643 // (use getSizeMax()*2 to allow for the expansion of the encryption)
3644 // FIXME: There's probably a more accurate way to decide what the
3645 // maximum size of the encrypted data could be.
3646 if ((uint32_t)size>(uint32_t)getSizeMax()*2) {
3647 #ifdef DEBUG_GSS_RECEIVE
3648 stdoutput.write(") failed (size too large)\n");
3649 #endif
3650 #ifdef EMSGSIZE
3651 error::setErrorNumber(EMSGSIZE);
3652 #endif
3653 #ifdef WSAMSGSIZE
3654 error::setNativeErrorNumber(WSAMSGSIZE);
3655 #endif
3656 return RESULT_ERROR;
3657 }
3658
3659 // copy out flags and size
3660 *tokenflags=0;
3661 *tokensize=size+5;
3662
3663 // read data
3664 *tokendata=NULL;
3665 if (size) {
3666 *tokendata=new unsigned char[*tokensize];
3667
3668 // include the header in the data
3669 bytestring::copy(*tokendata,header,sizeof(header));
3670
3671 // read token data
3672 result=fullRead(((unsigned char *)(*tokendata))+5,size);
3673 if (result!=(ssize_t)size) {
3674 #ifdef DEBUG_GSS_RECEIVE
3675 stdoutput.write(") failed (data)\n");
3676 #endif
3677 return (result<=0)?result:RESULT_ERROR;
3678 }
3679 }
3680
3681 #ifdef DEBUG_GSS_RECEIVE
3682 stdoutput.safePrint((unsigned char *)*tokendata,*tokensize);
3683 stdoutput.printf(") success (%d bytes)\n\n",*tokensize);
3684 #endif
3685 return *tokensize;
3686 }
3687
write(const void * buf,ssize_t count)3688 ssize_t gsscontext::write(const void *buf, ssize_t count) {
3689
3690 // create token
3691 unsigned char *tokendata=NULL;
3692 size_t tokensize=0;
3693 if (!wrap((const unsigned char *)buf,count,&tokendata,&tokensize)) {
3694 delete[] tokendata;
3695 return RESULT_ERROR;
3696 }
3697
3698 // send token
3699 ssize_t result=sendToken(TOKEN_FLAGS_TYPE_DATA,tokendata,tokensize);
3700 delete[] tokendata;
3701 if (result!=(ssize_t)tokensize) {
3702 return (result<=0)?result:RESULT_ERROR;
3703 }
3704 return count;
3705 }
3706
sendToken(uint32_t tokenflags,const void * tokendata,size_t tokensize)3707 ssize_t gsscontext::sendToken(uint32_t tokenflags,
3708 const void *tokendata,
3709 size_t tokensize) {
3710 switch (pvt->_tokenformat) {
3711 case GSSTOKENFORMAT_KRB:
3712 return sendKrbToken(tokenflags,tokendata,tokensize);
3713 case GSSTOKENFORMAT_TLS:
3714 return sendTlsToken(tokenflags,tokendata,tokensize);
3715 default:
3716 return RESULT_ERROR;
3717 }
3718 }
3719
sendKrbToken(uint32_t tokenflags,const void * tokendata,size_t tokensize)3720 ssize_t gsscontext::sendKrbToken(uint32_t tokenflags,
3721 const void *tokendata,
3722 size_t tokensize) {
3723
3724 #ifdef DEBUG_GSS_SEND
3725 stdoutput.printf("sendKrbToken(%08x,%d,",tokenflags,tokensize);
3726 stdoutput.safePrint((const unsigned char *)tokendata,tokensize);
3727 stdoutput.write(") ");
3728 #endif
3729
3730 // write token flags
3731 uint32_t temptokenflags=pvt->_fd->netToHost(tokenflags);
3732 ssize_t result=fullWrite(&temptokenflags,sizeof(tokenflags));
3733 if (result!=sizeof(tokenflags)) {
3734 #ifdef DEBUG_GSS_SEND
3735 stdoutput.write("failed (flags)\n");
3736 #endif
3737 return (result<=0)?result:RESULT_ERROR;
3738 }
3739
3740 // write token size
3741 uint32_t size=pvt->_fd->netToHost((uint32_t)tokensize);
3742 result=fullWrite(&size,sizeof(size));
3743 if (result!=sizeof(size)) {
3744 #ifdef DEBUG_GSS_SEND
3745 stdoutput.write("failed (size)\n");
3746 #endif
3747 return (result<=0)?result:RESULT_ERROR;
3748 }
3749
3750 // write token data
3751 result=fullWrite(tokendata,tokensize);
3752 if (result!=(ssize_t)tokensize) {
3753 #ifdef DEBUG_GSS_SEND
3754 stdoutput.write("failed (data)\n");
3755 #endif
3756 return (result<=0)?result:RESULT_ERROR;
3757 }
3758
3759 #ifdef DEBUG_GSS_SEND
3760 stdoutput.write("success\n\n");
3761 #endif
3762 return result;
3763 }
3764
sendTlsToken(uint32_t tokenflags,const void * tokendata,size_t tokensize)3765 ssize_t gsscontext::sendTlsToken(uint32_t tokenflags,
3766 const void *tokendata,
3767 size_t tokensize) {
3768
3769 #ifdef DEBUG_GSS_SEND
3770 stdoutput.printf("sendTlsToken(%08x,%d,",tokenflags,tokensize);
3771 stdoutput.safePrint((const unsigned char *)tokendata,tokensize);
3772 stdoutput.write(") ");
3773 #endif
3774
3775 // write token data
3776 ssize_t result=fullWrite(tokendata,tokensize);
3777 if (result!=(ssize_t)tokensize) {
3778 #ifdef DEBUG_GSS_SEND
3779 stdoutput.write("failed (data)\n");
3780 #endif
3781 return (result<=0)?result:RESULT_ERROR;
3782 }
3783
3784 #ifdef DEBUG_GSS_SEND
3785 stdoutput.write("success\n\n");
3786 #endif
3787 return result;
3788 }
3789
fullRead(void * data,ssize_t size)3790 ssize_t gsscontext::fullRead(void *data, ssize_t size) {
3791
3792 if (!pvt->_fd) {
3793 return RESULT_ERROR;
3794 }
3795
3796 // read, retrying if we got a short read,
3797 // until we've read "size" bytes...
3798
3799 ssize_t bytesread=0;
3800 ssize_t bytestoread=size;
3801 while (bytestoread) {
3802 ssize_t result=pvt->_fd->lowLevelRead(
3803 ((unsigned char *)data)+bytesread,
3804 bytestoread);
3805 if (result<=0) {
3806 return result;
3807 }
3808 bytesread+=result;
3809 bytestoread-=result;
3810 }
3811 return bytesread;
3812 }
3813
fullWrite(const void * data,ssize_t size)3814 ssize_t gsscontext::fullWrite(const void *data, ssize_t size) {
3815
3816 if (!pvt->_fd) {
3817 return RESULT_ERROR;
3818 }
3819
3820 // write, retrying if we got a short write,
3821 // until we've written "size" bytes...
3822
3823 ssize_t byteswritten=0;
3824 ssize_t bytestowrite=size;
3825 while (bytestowrite) {
3826 ssize_t result=pvt->_fd->lowLevelWrite(
3827 ((const unsigned char *)data)+byteswritten,
3828 bytestowrite);
3829 if (result<=0) {
3830 return result;
3831 }
3832 byteswritten+=result;
3833 bytestowrite-=result;
3834 }
3835 return byteswritten;
3836 }
3837
checkFlags(uint32_t actualflags,uint32_t desiredflags)3838 bool gsscontext::checkFlags(uint32_t actualflags, uint32_t desiredflags) {
3839 switch (pvt->_tokenformat) {
3840 case GSSTOKENFORMAT_KRB:
3841 return (actualflags&desiredflags);
3842 default:
3843 return true;
3844 }
3845 }
3846
pending()3847 ssize_t gsscontext::pending() {
3848 return (pvt->_readbuffer.getSize()-pvt->_readbufferpos);
3849 }
3850
getMajorStatus()3851 uint32_t gsscontext::getMajorStatus() {
3852 #if defined(RUDIMENTS_HAS_GSS)
3853 return pvt->_major;
3854 #elif defined(RUDIMENTS_HAS_SSPI)
3855 return pvt->_sstatus;
3856 #else
3857 return 0;
3858 #endif
3859 }
3860
getMinorStatus()3861 uint32_t gsscontext::getMinorStatus() {
3862 #if defined(RUDIMENTS_HAS_GSS)
3863 return pvt->_minor;
3864 #elif defined(RUDIMENTS_HAS_SSPI)
3865 return 0;
3866 #else
3867 return 0;
3868 #endif
3869 }
3870
getStatus()3871 const char *gsscontext::getStatus() {
3872 pvt->_status.clear();
3873 #if defined(RUDIMENTS_HAS_GSS)
3874 pvt->_status.append("GSS - major:\n");
3875 setStatus(pvt->_major,GSS_C_GSS_CODE);
3876 pvt->_status.append("GSS - minor:\n");
3877 setStatus(pvt->_minor,GSS_C_GSS_CODE);
3878 pvt->_status.append("MECH - major:\n");
3879 setStatus(pvt->_major,GSS_C_MECH_CODE);
3880 pvt->_status.append("MECH - minor:\n");
3881 setStatus(pvt->_minor,GSS_C_MECH_CODE);
3882 #elif defined(RUDIMENTS_HAS_SSPI)
3883 pvt->_status.append("SSPI - status:\n");
3884 setStatus(pvt->_sstatus,0);
3885 #endif
3886 return pvt->_status.getString();
3887 }
3888
getGSSMajorStatus()3889 const char *gsscontext::getGSSMajorStatus() {
3890 pvt->_status.clear();
3891 #if defined(RUDIMENTS_HAS_GSS)
3892 setStatus(pvt->_major,GSS_C_GSS_CODE);
3893 #elif defined(RUDIMENTS_HAS_SSPI)
3894 setStatus(pvt->_sstatus,0);
3895 #endif
3896 return pvt->_status.getString();
3897 }
3898
getGSSMinorStatus()3899 const char *gsscontext::getGSSMinorStatus() {
3900 pvt->_status.clear();
3901 #if defined(RUDIMENTS_HAS_GSS)
3902 setStatus(pvt->_minor,GSS_C_GSS_CODE);
3903 #elif defined(RUDIMENTS_HAS_SSPI)
3904 setStatus(pvt->_sstatus,0);
3905 #endif
3906 return pvt->_status.getString();
3907 }
3908
getMechanismMajorStatus()3909 const char *gsscontext::getMechanismMajorStatus() {
3910 pvt->_status.clear();
3911 #if defined(RUDIMENTS_HAS_GSS)
3912 setStatus(pvt->_major,GSS_C_MECH_CODE);
3913 #elif defined(RUDIMENTS_HAS_SSPI)
3914 setStatus(pvt->_sstatus,0);
3915 #endif
3916 return pvt->_status.getString();
3917 }
3918
getMechanismMinorStatus()3919 const char *gsscontext::getMechanismMinorStatus() {
3920 pvt->_status.clear();
3921 #if defined(RUDIMENTS_HAS_GSS)
3922 setStatus(pvt->_minor,GSS_C_MECH_CODE);
3923 #elif defined(RUDIMENTS_HAS_SSPI)
3924 setStatus(pvt->_sstatus,0);
3925 #endif
3926 return pvt->_status.getString();
3927 }
3928
setStatus(uint32_t status,int32_t type)3929 void gsscontext::setStatus(uint32_t status, int32_t type) {
3930
3931 #if defined(RUDIMENTS_HAS_GSS)
3932
3933 gss_buffer_desc statusbuffer;
3934
3935 OM_uint32 msgctx=0;
3936 do {
3937 OM_uint32 major;
3938 OM_uint32 minor;
3939 major=gss_display_status(&minor,
3940 status,
3941 type,
3942 GSS_C_NO_OID,
3943 &msgctx,
3944 &statusbuffer);
3945 if (major!=GSS_S_COMPLETE) {
3946 break;
3947 }
3948
3949 pvt->_status.append((unsigned char *)
3950 statusbuffer.value,
3951 statusbuffer.length);
3952 pvt->_status.append('\n');
3953
3954 gss_release_buffer(&minor,&statusbuffer);
3955 } while (msgctx);
3956
3957 #elif defined(RUDIMENTS_HAS_SSPI)
3958
3959 const char *str=gss::getSspiStatusString(status);
3960 pvt->_status.append(str)->append("\n");
3961 if (error::getNativeErrorNumber()) {
3962 char *errstr=error::getNativeErrorString();
3963 pvt->_status.append(errstr)->append("\n");
3964 delete[] errstr;
3965 }
3966 #endif
3967 }
3968