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