-
Notifications
You must be signed in to change notification settings - Fork 22
/
gkauth.h
1265 lines (1098 loc) · 42 KB
/
gkauth.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//////////////////////////////////////////////////////////////////
//
// gkauth.h
//
// Copyright (c) 2001-2019, Jan Willamowius
//
// Gatekeeper authentication modules
//
// This work is published under the GNU Public License version 2 (GPLv2)
// see file COPYING for details.
// We also explicitly grant the right to link this code
// with the OpenH323/H323Plus and OpenSSL library.
//
//////////////////////////////////////////////////////////////////
#ifndef GKAUTH_H
#define GKAUTH_H "@(#) $Id$"
#include <map>
#include <list>
#include "name.h"
#include "rwlock.h"
#include <h235auth.h>
#include "Toolkit.h"
#include "snmp.h"
#include "h323util.h"
class H225_GatekeeperRequest;
class H225_GatekeeperConfirm;
class H225_RegistrationRequest;
class H225_UnregistrationRequest;
class H225_AdmissionRequest;
class H225_BandwidthRequest;
class H225_DisengageRequest;
class H225_LocationRequest;
class H225_InfoRequest;
class H225_ArrayOf_ClearToken;
class H225_ArrayOf_CryptoH323Token;
class H225_ArrayOf_AliasAddress;
class H225_ArrayOf_AuthenticationMechanism;
class H225_ArrayOf_PASN_ObjectId;
class H225_TransportAddress;
class H225_ArrayOf_TransportAddress;
class H235_AuthenticationMechanism;
class PASN_ObjectId;
class H235Authenticators;
class H235Authenticator;
class H225_Setup_UUIE;
class SignalingMsg;
template <class> class H225SignalingMsg;
typedef H225SignalingMsg<H225_Setup_UUIE> SetupMsg;
class EndpointRec;
class CallRec;
template<class> class SmartPtr;
typedef SmartPtr<EndpointRec> endptr;
typedef SmartPtr<CallRec> callptr;
template<class> class RasPDU;
template<class> struct RasInfo;
namespace Routing {
class Route;
}
#ifdef HAS_DES_ECB
////////////////////////////////////////////////////
#include <h235/h235crypto.h>
/** This class implements desECB authentication.
*/
class H235AuthDesECB : public H235Authenticator
{
PCLASSINFO(H235AuthDesECB, H235Authenticator);
public:
H235AuthDesECB();
PObject * Clone() const;
virtual const char * GetName() const;
static PStringArray GetAuthenticatorNames();
#if PTLIB_VER >= 2110
static PBoolean GetAuthenticationCapabilities(Capabilities * ids);
#endif
virtual PBoolean IsMatch(const PString & identifier) const;
virtual H225_CryptoH323Token * CreateCryptoToken();
virtual ValidationResult ValidateCryptoToken(
const H225_CryptoH323Token & cryptoToken,
const PBYTEArray & rawPDU
);
virtual PBoolean IsCapability(
const H235_AuthenticationMechanism & mechansim,
const PASN_ObjectId & algorithmOID
);
virtual PBoolean SetCapability(
H225_ArrayOf_AuthenticationMechanism & mechansim,
H225_ArrayOf_PASN_ObjectId & algorithmOIDs
);
virtual PBoolean IsSecuredPDU(
unsigned rasPDU,
PBoolean received
) const;
virtual PBoolean IsSecuredSignalPDU(
unsigned rasPDU,
PBoolean received
) const;
};
#endif
/// Data read/written during RRQ processing by all configured
/// authenticator modules
struct RRQAuthData
{
RRQAuthData() : m_rejectReason(-1), m_billingMode(-1), m_authenticator(NULL) { }
~RRQAuthData() { delete m_authenticator; }
/// -1 if not set, H225_RegistrationRejectReason enum otherwise
int m_rejectReason;
/// optional user's account balance amount string
PString m_amountString;
/// H225_CallCreditServiceControl_billingMode or -1, if not defined
int m_billingMode;
/// Authenticated Aliases
PStringArray m_authAliases;
GkH235Authenticators * m_authenticator;
};
/// Data read/written during ARQ processing by all configured
/// authenticator modules
struct ARQAuthData
{
ARQAuthData(const ARQAuthData & obj);
ARQAuthData(const endptr & ep, const callptr & call);
ARQAuthData& operator=(const ARQAuthData & obj);
void SetRouteToAlias(const H225_ArrayOf_AliasAddress & alias);
void SetRouteToAlias(const PString & alias, int tag = -1);
/// -1 if not set, H225_AdmissionRejectReason enum otherwise
int m_rejectReason;
/// -1 if not set, max allowed call duration in seconds otherwise
long m_callDurationLimit;
/// disabled codecs
PString m_disabledcodecs;
/// endpoint that sent the request
endptr m_requestingEP;
/// call associated with the request (if any, only for answering ARQ)
callptr m_call;
/// input/output - set or get Calling-Station-Id
PString m_callingStationId;
/// call party to be billed for the call (if other then Calling-Station-Id)
PString m_callLinkage;
/// input/output - set or get Called-Station-Id
PString m_calledStationId;
/// number dialed by the user (Called-Station-Id before rewrite)
PString m_dialedNumber;
/// optional user's account balance amount string
PString m_amountString;
/// H225_CallCreditServiceControl_billingMode or -1, if not defined
int m_billingMode;
/// if not NULL, route the call to the specified alias
H225_ArrayOf_AliasAddress m_routeToAlias;
/// if not empty, route the call to the specified destinations
std::list<Routing::Route> m_destinationRoutes;
/// override global proxy setting from the config (see #CallRec::ProxyMode enum#)
int m_proxyMode;
/// RADIUS Class attribute, if found in Access-Accept/Access-Reject
PBYTEArray m_radiusClass;
/// ID provided by client, to be passed out with accounting events
PUInt64 m_clientAuthId;
private:
ARQAuthData();
};
/// Data read/written during Q.931/H.225.0 Setup processing
/// by all authenticators
struct SetupAuthData
{
SetupAuthData(const SetupAuthData & obj);
SetupAuthData(
/// call associated with the message (if any)
const callptr & call,
/// is the Setup message from a registered endpoint
bool fromRegistered,
/// did the Setup come in over TLS
bool overTLS,
/// did the Setup come from a neighbor gatekeeper
bool fromNeighbor
);
~SetupAuthData();
SetupAuthData & operator=(const SetupAuthData & obj);
void SetRouteToAlias(const H225_ArrayOf_AliasAddress & alias);
void SetRouteToAlias(const PString & alias, int tag = -1);
/// -1 if not set, H225_ReleaseCompleteReason enum otherwise
int m_rejectReason;
/// -1 if not set, Q931 cause value otherwise
int m_rejectCause;
/// -1 if not set, max allowed call duration in seconds otherwise
long m_callDurationLimit;
/// disabled codecs
PString m_disabledcodecs;
/// call associated with the message (if any), only available for registered calls (created on ACF)
callptr m_call;
/// is the Setup message from a registered endpoint
bool m_fromRegistered;
/// input/output - set or get Calling-Station-Id
PString m_callingStationId;
/// input/output - set or get Called-Station-Id
PString m_calledStationId;
/// number dialed by the user (Called-Station-Id before rewrite)
PString m_dialedNumber;
/// if not NULL, route the call to the specified alias
H225_ArrayOf_AliasAddress m_routeToAlias;
/// if not empty, route the call to the specified destinations
std::list<Routing::Route> m_destinationRoutes;
/// override global proxy setting from the config (see #CallRec::ProxyMode enum#)
int m_proxyMode;
/// RADIUS Class attribute, if found in Access-Accept/Access-Reject
PBYTEArray m_radiusClass;
/// ID provided by client, to be passed out with accounting events
PUInt64 m_clientAuthId;
/// True if Setup came in over TLS
bool m_overTLS;
/// True if the Setup came from a neighbor gatekeeper
bool m_fromNeighbor;
private:
SetupAuthData();
};
/// Data read/written during Q.931/H.225.0 message processing (except Setup)
/// by all authenticators
struct Q931AuthData
{
Q931AuthData(const H225_ArrayOf_AliasAddress & aliases,
PIPSocket::Address peerAddr, WORD peerPort,
bool overTLS, GkH235Authenticators * auth)
: m_aliases(aliases), m_peerAddr(peerAddr), m_peerPort(peerPort),
m_overTLS(overTLS), m_allowAnySendersID(false), m_authenticator(auth) { }
~Q931AuthData() { }
// the aliases of the endpoint
const H225_ArrayOf_AliasAddress & m_aliases;
/// IP address the request comes from
PIPSocket::Address m_peerAddr;
/// port number the request comes from
WORD m_peerPort;
/// True if Setup came in over TLS
bool m_overTLS;
// in RRQs we have to accept any sendersID
bool m_allowAnySendersID;
/// password authenticator
GkH235Authenticators * m_authenticator;
private:
Q931AuthData();
Q931AuthData(const Q931AuthData & obj); // : m_rejectReason(obj.m_rejectReason), m_rejectCause(obj.m_rejectCause), m_call(obj.m_call) { }
Q931AuthData& operator=(const Q931AuthData & obj);
};
/** The base class for all authenticator modules. Authenticator modules
are used to authenticate/authorized RAS and Q.931 messages sent
by endpoints and to check if the endpoints are authorized to use
H.323 network resources.
The modules are stackable - each request can be checked by multiple
modules to get the final authentication result.
Derived classes usually override one or more Check virtual methods
to implement specific authentication mechanism.
*/
class GkAuthenticator : public NamedObject
{
public:
/// processing rule for the authenticator
enum Control {
/// if this module cannot determine authentication success or failure
/// (due to some missing info, for example), remaining modules will
/// decide about acceptation/rejection of the reqest,
/// if the request is accepted it is passed to a next rule
e_Optional,
/// the request has to be authenticated by this module
/// and processing is continued with remaining modules
e_Required,
/// if the request is authenticated by this module, authentication
/// is successful, otherwise the request is rejected
/// (no further modules are processed in both cases)
e_Sufficient,
/// if the request is accepted/rejected by this module, authentication
/// processing ends, otherwise the request is passed to a next rule
e_Alternative
};
/// authentication status returned from Check methods
enum Status {
e_ok = 1, /// the request is authenticated and accepted
e_fail = -1, /// the request is authenticated and rejected
e_next = 0 /// the module could not authenticate the request
};
/// bit masks for event types other than RAS - see miscCheckFlags variable
enum MiscCheckEvents {
e_Setup = 0x0001, /// Q.931/H.225 Setup message
e_SetupUnreg = 0x0002, /// Q.931/H.225 Setup message only from an unregistered endpoint
e_Connect = 0x0004, /// Q.931/H.225 Connect message
e_CallProceeding = 0x0008, /// Q.931/H.225 CallProceeding message
e_Alerting = 0x0010, /// Q.931/H.225 Alerting message
e_Information = 0x0020, /// Q.931/H.225 Information message
e_ReleaseComplete = 0x0040, /// Q.931/H.225 ReleaseComplete message
e_Facility = 0x0080, /// Q.931/H.225 Facility message
e_Progress = 0x0100, /// Q.931/H.225 Progress message
e_Empty = 0x0200, /// Q.931/H.225 empty message
e_Status = 0x0400, /// Q.931/H.225 Status message
e_StatusEnquiry = 0x0800, /// Q.931/H.225 StatusInquiry message
e_SetupAck = 0x1000, /// Q.931/H.225 SetupAck message
e_Notify = 0x2000 /// Q.931/H.225 Notify message
};
/** Build a new authenticator object with the given name.
It is important to pass proper check flags to signal, which checks
are supported/implemented by this authenticator.
*/
GkAuthenticator(
const char* name, /// a name for the module (to be used in the config file)
unsigned supportedRasChecks = ~0U, /// RAS checks supported by this module
unsigned supportedMiscChecks = ~0U /// non-RAS checks supported by this module
);
virtual ~GkAuthenticator();
/** @return
true if this authenticator provides H.235 compatible security.
It simply checks if m_h235Authenticators list is not empty.
*/
virtual bool IsH235Capable() const;
/** Check if this authenticator supports the given
H.235 capability (mechanism+algorithmOID) by scanning
the m_h235Authenticators list of H.235 capabilities.
@return
true if the capability is supported by this module.
*/
virtual bool IsH235Capability(
/// authentication mechanism
const H235_AuthenticationMechanism & mechanism,
/// algorithm OID for the given authentication mechanism
const PASN_ObjectId & algorithmOID
) const;
/** @return
Control flag determining authenticator behavior
(optional, sufficient, required).
*/
Control GetControlFlag() const { return m_controlFlag; }
/** @return
True if the check is supported (implemented) by this authenticator.
*/
bool IsRasCheckEnabled(unsigned rasCheck) const
{ return (m_enabledRasChecks & m_supportedRasChecks & rasCheck) == rasCheck; }
/** @return
True if the check is supported (implemented) by this authenticator.
*/
bool IsMiscCheckEnabled(unsigned miscCheck) const
{ return (m_enabledMiscChecks & m_supportedMiscChecks & miscCheck) == miscCheck; }
/** @return
Enum code for supported checks for this Q.931 message type
*/
int AuthEnum(unsigned msgCode) const;
/** Virtual methods overridden in derived classes to perform
the actual authentication. The first parameter is a request
to be checked, the second is a H225_XXXRejectReason that can
be set if the authentication rejects the request.
@return
e_fail - authentication rejected the request
e_ok - authentication accepted the request
e_next - authentication is not supported for this request
or cannot be determined (SQL failure, no cryptoTokens, ...)
*/
virtual int Check(RasPDU<H225_GatekeeperRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_UnregistrationRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_BandwidthRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_DisengageRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_LocationRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_InfoRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_ResourcesAvailableIndicate> & req, unsigned & rejectReason);
/** Authenticate/Authorize RAS or signaling message.
@return
e_fail - authentication rejected the request
e_ok - authentication accepted the request
e_next - authentication is not supported for this request
or cannot be determined (SQL failure, no cryptoTokens, ...)
*/
virtual int Check(
/// RRQ to be authenticated/authorized
RasPDU<H225_RegistrationRequest> & request,
/// authorization data (reject reason, ...)
RRQAuthData & authData
);
virtual int Check(
/// ARQ to be authenticated/authorized
RasPDU<H225_AdmissionRequest> & request,
/// authorization data (call duration limit, reject reason, ...)
ARQAuthData & authData
);
virtual int Check(
/// Q.931/H.225 Setup to be authenticated
SetupMsg & setup,
/// authorization data (call duration limit, reject reason, ...)
SetupAuthData & authData
);
virtual int Check(
/// Q.931/H.225 message to be authenticated
Q931 & msq,
/// authorization data
Q931AuthData & authData
);
/** Get human readable information about current module state
that can be displayed on the status port interface.
@return
A string (may contain multiple lines) with module information.
Each line (including the last one) has to be ended with \r\n.
*/
virtual PString GetInfo();
protected:
/** @return
Default authentication status, if not determined by Check... method.
*/
int GetDefaultStatus() const { return m_defaultStatus; }
PString StatusAsString(int status) const;
/** @return
Config that contains settings for this authenticator.
*/
PConfig* GetConfig() const { return m_config; }
/** Should be called only from derived constructor to add supported
H.235 capabilities (if any).
*/
void AppendH235Authenticator(
H235Authenticator * h235Auth /// H.235 authenticator to append
);
/** @return
A string that can be used to identify an account name
associated with the call.
*/
virtual PString GetUsername(
/// RRQ message with additional data
const RasPDU<H225_RegistrationRequest> & request
) const;
virtual PString GetUsername(
/// ARQ message with additional data
const RasPDU<H225_AdmissionRequest> & request,
/// additional data, like call record and requesting endpoint
ARQAuthData & authData
) const;
virtual PString GetUsername(
/// Q.931/H.225 Setup with additional data
const SetupMsg & setup,
/// additional data
SetupAuthData & authData
) const;
/** @return
A string that can be used to identify a calling number.
*/
virtual PString GetCallingStationId(
/// RRQ message with additional data
const RasPDU<H225_RegistrationRequest> & request,
/// additional data
RRQAuthData & authData
) const;
virtual PString GetCallingStationId(
/// ARQ message with additional data
const RasPDU<H225_AdmissionRequest> & request,
/// additional data, like call record and requesting endpoint
ARQAuthData & authData
) const;
virtual PString GetCallingStationId(
/// Q.931/H.225 Setup to be authenticated
const SetupMsg & setup,
/// additional data
SetupAuthData & authData
) const;
/** @return
A string that can be used to identify a calling number.
*/
virtual PString GetCalledStationId(
/// ARQ message with additional data
const RasPDU<H225_AdmissionRequest> & request,
/// additional data, like call record and requesting endpoint
ARQAuthData & authData
) const;
virtual PString GetCalledStationId(
/// Q.931/H.225 Setup to be authenticated
const SetupMsg & setup,
/// additional data
SetupAuthData & authData
) const;
/// @return Number actually dialed by the user (before rewrite)
PString GetDialedNumber(
/// ARQ message with additional data
const RasPDU<H225_AdmissionRequest> & request,
/// additional data
ARQAuthData & authData
) const;
/// @return Number actually dialed by the user (before rewrite)
virtual PString GetDialedNumber(
/// Q.931/H.225 Setup to be authenticated
const SetupMsg & setup,
/// additional data
SetupAuthData & authData
) const;
public:
/** Replace parameters placeholders (%a, %{Name}, ...) with actual values.
Similar to Acct and Query params, but without the escaping.
@return
New string with all parameters replaced.
*/
static PString ReplaceAuthParams(
/// parametrized accounting string
const PString & str,
/// parameter values
const std::map<PString, PString> & params
);
protected:
/// a list of H.235 capabilities supported by this module (if any)
H235Authenticators* m_h235Authenticators;
private:
GkAuthenticator();
GkAuthenticator(const GkAuthenticator &);
GkAuthenticator & operator=(const GkAuthenticator &);
protected:
/// default status to be returned, if not determined otherwise
Status m_defaultStatus;
/// processing rule for this authenticator
Control m_controlFlag;
/// bit flags for RAS messages to be authenticated (this enforces the limit
/// of first 32 RAS messages being supported)
unsigned m_enabledRasChecks;
/// bit flags with RAS checks supported by a given authenticator
unsigned m_supportedRasChecks;
/// bit flags for other event types to be authenticated (like Q.931 Setup)
unsigned m_enabledMiscChecks;
/// bit flags with non-RAS checks supported by a given authenticator
unsigned m_supportedMiscChecks;
/// authenticator config
PConfig* m_config;
};
/** Cache used by some authenticators to remember key-value associations,
like username-password. It increases performance, as backend
does not need to be queried each time.
*/
class CacheManager
{
public:
CacheManager(
long timeout = -1 /// cache timeout - expiry period (seconds)
);
~CacheManager();
/** Get a value associated with the key.
@return
true if association has been found and the value is valid,
false if the key-value pair is not cached or the cache expired
*/
bool Retrieve(
const PString & key, /// the key to look for
PString & value /// filled with the value on return
) const;
/// Store a key-value association in the cache
void Save(
const PString & key, /// a key to be stored
const PString & value /// a value to be associated with the key
);
void SetTimeout(
long newTimeout /// new cache expiration timeout
) { m_ttl = newTimeout; }
// delete expired entries (doesn't need to run often)
void Expire(GkTimer* timer);
private:
CacheManager(const CacheManager &);
CacheManager & operator=(const CacheManager &);
private:
/// cache timeout (seconds), 0 = do not cache, -1 = never expires
long m_ttl;
/// cached key-value pairs
std::map<PString, PString> m_cache;
/// timestamps for key-value pair expiration calculation
std::map<PString, time_t> m_ctime;
/// mutex for multiple read/mutual write access to the cache
mutable PReadWriteMutex m_rwmutex;
/// timer to expire entries every now and then to save memory
GkTimerManager::GkTimerHandle m_expireTimer;
};
/** A base class for all authenticators that only checks if username-password
pairs match. This authenticator checks H.235 tokens/cryptoTokens carried
inside RAS requests. Currently, only simple MD5 password hash and Cisco CAT
authentication token types are supported.
Derived authenticators usually override only GetPassword virtual method.
*/
class SimplePasswordAuth : public GkAuthenticator
{
public:
enum SupportedRasChecks {
/// bitmask of RAS checks implemented by this module
SimplePasswordAuthRasChecks = RasInfo<H225_RegistrationRequest>::flag
| RasInfo<H225_UnregistrationRequest>::flag
| RasInfo<H225_BandwidthRequest>::flag
| RasInfo<H225_DisengageRequest>::flag
| RasInfo<H225_LocationRequest>::flag
| RasInfo<H225_InfoRequest>::flag
| RasInfo<H225_AdmissionRequest>::flag
| RasInfo<H225_ResourcesAvailableIndicate>::flag
};
enum SupportedMiscChecks {
/// bitmask of Misc checks implemented by this module
SimplePasswordAuthMiscChecks = e_Setup
| e_SetupUnreg
| e_Connect
| e_CallProceeding
| e_Alerting
| e_Information
| e_ReleaseComplete
| e_Facility
| e_Progress
| e_Empty
| e_Status
| e_StatusEnquiry
| e_SetupAck
| e_Notify
};
SimplePasswordAuth(
const char* name, /// a name for this module (a config section name)
unsigned supportedRasChecks = SimplePasswordAuthRasChecks,
unsigned supportedMiscChecks = SimplePasswordAuthMiscChecks
);
virtual ~SimplePasswordAuth();
// overridden from class GkAuthenticator
virtual int Check(RasPDU<H225_UnregistrationRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_BandwidthRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_DisengageRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_LocationRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_InfoRequest> & req, unsigned & rejectReason);
virtual int Check(RasPDU<H225_ResourcesAvailableIndicate> & req, unsigned & rejectReason);
/** Authenticate/Authorize RAS message.
An override from GkAuthenticator.
@return
e_fail - authentication rejected the request
e_ok - authentication accepted the request
e_next - authentication is not supported for this request
or cannot be determined (SQL failure, no cryptoTokens, ...)
*/
virtual int Check(
/// RRQ to be authenticated/authorized
RasPDU<H225_RegistrationRequest> & request,
/// authorization data (reject reason, ...)
RRQAuthData & authData
);
virtual int Check(
/// ARQ to be authenticated/authorized
RasPDU<H225_AdmissionRequest> & request,
/// authorization data (call duration limit, reject reason, ...)
ARQAuthData & authData
);
/** Authenticate/Authorize a signaling message.
An override from GkAuthenticator.
@return
e_fail - authentication rejected the request
e_ok - authentication accepted the request
e_next - authentication is not supported for this request
or cannot be determined (SQL failure, no cryptoTokens, ...)
*/
virtual int Check(
/// Q931 message to be authenticated/authorized
Q931 & msg,
/// authorization data
Q931AuthData & authData
);
// for H.235.1 we use the generic Q931 Check() method
// at the point where this method is called all tokens are already gone
virtual int Check(SetupMsg & setup, SetupAuthData & authData) { return e_ok; }
protected:
/** Get a password associated with the identifier.
@return
true if the password is returned, false if the password
could not be found.
*/
virtual bool GetPassword(
const PString & id, /// get the password for this id
PString & passwd, /// filled with the password on return
std::map<PString, PString> & params /// map of authentication parameters
);
/** Validate username/password carried inside the tokens. This method
supports only CAT and clear text tokens.
@return
e_ok if the username/password carried inside the tokens is valid,
e_fail if the username/password carried inside the tokens is invalid,
e_next if no recognized tokens have been found
*/
virtual int CheckTokens(
/// authenticators to be used for token validation
GkH235Authenticators * & authenticators,
/// an array of tokens to be checked
const H225_ArrayOf_ClearToken & tokens,
/// aliases for the endpoint that generated the tokens
const H225_ArrayOf_AliasAddress * aliases,
/// map of authentication parameters
std::map<PString, PString> & params
);
/** Validate username/password carried inside the tokens.
@return
e_ok if the username/password carried inside the tokens is valid,
e_fail if the username/password carried inside the tokens is invalid,
e_next if no recognized tokens have been found
*/
virtual int CheckCryptoTokens(
/// authenticators to be used for token validation
GkH235Authenticators * & authenticators,
/// an array of cryptoTokens to be checked
const H225_ArrayOf_CryptoH323Token & cryptoTokens,
/// aliases for the endpoint that generated the tokens
const H225_ArrayOf_AliasAddress * aliases,
/// allow any sendersID (eg. in RRQ)
bool acceptAnySendersID,
/// map of authentication parameters
std::map<PString, PString> & params
);
int doCheck(const Q931 & msg, Q931AuthData & authData) {
GkH235Authenticators * auth = authData.m_authenticator;
bool authFound = auth != NULL;
H225_ArrayOf_ClearToken emptyTokens;
H225_ArrayOf_CryptoH323Token emptyCryptoTokens;
H225_ArrayOf_ClearToken * tokens = &emptyTokens;
H225_ArrayOf_CryptoH323Token * cryptoTokens = &emptyCryptoTokens;
H225_H323_UserInformation uuie;
if (!GetUUIE(msg, uuie)) {
return e_next; // without a UUIE, this message can't carry a token
}
GkH235Authenticators::GetQ931Tokens(msg.GetMessageType(), &uuie, &tokens, &cryptoTokens);
if (!authFound && ((msg.GetMessageType() == Q931::SetupMsg)
&& (uuie.m_h323_uu_pdu.m_h323_message_body.GetTag() == H225_H323_UU_PDU_h323_message_body::e_setup))) {
H225_Setup_UUIE & setup = uuie.m_h323_uu_pdu.m_h323_message_body;
callptr call;
if (setup.HasOptionalField(H225_Setup_UUIE::e_callIdentifier)) {
call = CallTable::Instance()->FindCallRec(setup.m_callIdentifier);
} else {
call = CallTable::Instance()->FindCallRec(msg.GetCallReference());
}
if (call && call->GetCallingParty()) {
auth = call->GetCallingParty()->GetH235Authenticators();
} else {
// TODO235: for calls with pregrantedARQ, we might not have a CallRec, yet
// try to find EP based on sendersID ?
}
}
if (!auth) {
return GetDefaultStatus();
}
std::map<PString, PString> params;
params["g"] = Toolkit::GKName();
params["caller-ip"] = AsString(authData.m_peerAddr);
params["called-ip"] = "unknown"; // TODO
params["message"] = Q931MessageName(msg.GetMessageType());
params["caller-product-name"] = "unknown";
params["caller-product-version"] = "unknown";
if (msg.GetMessageType() == Q931::SetupMsg) {
H225_Setup_UUIE & setupBody = uuie.m_h323_uu_pdu.m_h323_message_body;
if (setupBody.m_sourceInfo.HasOptionalField(H225_EndpointType::e_vendor)) {
if (setupBody.m_sourceInfo.m_vendor.HasOptionalField(H225_VendorIdentifier::e_productId)) {
params["caller-product-name"] = setupBody.m_sourceInfo.m_vendor.m_productId.AsString();
}
if (setupBody.m_sourceInfo.m_vendor.HasOptionalField(H225_VendorIdentifier::e_versionId)) {
params["caller-product-version"] = setupBody.m_sourceInfo.m_vendor.m_versionId.AsString();
}
}
}
params["caller-vendor"] = params["caller-product-name"] + " " + params["caller-product-version"];
if (CheckTokens(auth, *tokens, &authData.m_aliases, params) == e_fail
|| CheckCryptoTokens(auth, *cryptoTokens, &authData.m_aliases, false, params) == e_fail) {
return e_fail;
}
int result = auth->Validate(msg, *tokens, *cryptoTokens);
if (result == H235Authenticator::e_OK)
return e_ok;
else {
if (result == H235Authenticator::e_Absent || result == H235Authenticator::e_Disabled)
return GetDefaultStatus();
return e_fail;
}
}
/** A family of template functions that check tokens/cryptoTokens
inside RAS messages.
@return
e_ok if the username/password carried inside the tokens is valid,
e_fail if the username/password carried inside the tokens is invalid,
e_next if no recognized tokens have been found
*/
template<class RAS> int doCheck(
/// RAS request to be authenticated
const RasPDU<RAS> & request,
/// list of aliases for the endpoint sending the request
const H225_ArrayOf_AliasAddress * aliases,
/// Registration Auth data
GkH235Authenticators * & auth)
{
H225_ArrayOf_ClearToken emptyTokens;
H225_ArrayOf_CryptoH323Token emptyCryptoTokens;
const H225_ArrayOf_ClearToken * tokens = &emptyTokens;
const H225_ArrayOf_CryptoH323Token * cryptoTokens = &emptyCryptoTokens;
const RAS & req = request;
if (req.HasOptionalField(RAS::e_tokens))
tokens = &req.m_tokens;
if (req.HasOptionalField(RAS::e_cryptoTokens))
cryptoTokens = &req.m_cryptoTokens;
// can't check sendersID on some messages (eg. for RRQ we don't know the aliases or endpointID, yet)
bool acceptAnySendersID = (request.GetTag() == H225_RasMessage::e_registrationRequest)
|| (request.GetTag() == H225_RasMessage::e_locationRequest)
|| (request.GetTag() == H225_RasMessage::e_infoRequest);
std::map<PString, PString> params;
params["g"] = Toolkit::GKName();
PIPSocket::Address callerIP;
request.GetPeerAddr(callerIP);
params["caller-ip"] = AsString(callerIP);
params["message"] = request.GetTagName();
params["caller-product-name"] = "unknown";
params["caller-product-version"] = "unknown";
if (request.GetMsg() != NULL) {
params["called-ip"] = AsString(request.GetMsg()->m_localAddr);
if (request.GetTag() == H225_RasMessage::e_registrationRequest) {
RasPDU<H225_RegistrationRequest> ras_rrq(new GatekeeperMessage(*request.GetMsg()));
H225_RegistrationRequest & rrq = ras_rrq;
if (rrq.m_terminalType.HasOptionalField(H225_EndpointType::e_vendor)) {
if (rrq.m_terminalType.m_vendor.HasOptionalField(H225_VendorIdentifier::e_productId)) {
params["caller-product-name"] = rrq.m_terminalType.m_vendor.m_productId.AsString();
}
if (rrq.m_terminalType.m_vendor.HasOptionalField(H225_VendorIdentifier::e_versionId)) {
params["caller-product-version"] = rrq.m_terminalType.m_vendor.m_versionId.AsString();
}
}
}
}
params["caller-vendor"] = params["caller-product-name"] + " " + params["caller-product-version"];
if (CheckTokens(auth, *tokens, aliases, params) == e_fail
|| CheckCryptoTokens(auth, *cryptoTokens, aliases, acceptAnySendersID, params) == e_fail) {
return e_fail;
}
if (auth == NULL)
return GetDefaultStatus();
int result = auth->Validate((const H225_RasMessage&)req, *tokens, *cryptoTokens, request->m_rasPDU);
if (result == H235Authenticator::e_OK)
return e_ok;
else {
if (result == H235Authenticator::e_Absent || result == H235Authenticator::e_Disabled)
return GetDefaultStatus();
return e_fail;
}
}
/// Set new timeout for username/password pairs cache
void SetCacheTimeout(long newTimeout) { m_cache->SetTimeout(newTimeout); }
private:
/** Get password for the given user. Examine password cache first.
@return
true if the password has been found.
*/
bool InternalGetPassword(
const PString & id, /// get the password for this id
PString & passwd, /// filled with the password on return
std::map<PString, PString> & params /// map of authentication parameters
);
SimplePasswordAuth();
SimplePasswordAuth(const SimplePasswordAuth &);
SimplePasswordAuth & operator=(const SimplePasswordAuth &);
private:
/// an encryption key used to decrypt passwords from the config file
int m_encryptionKey;
/// if true, generalID has to be also in the endpoint alias list
bool m_checkID;
/// cache for username/password pairs
CacheManager* m_cache;
/// list of H.235 algorithms to disable
PStringArray m_disabledAlgorithms;
};
#ifdef H323_H350
/// H.350 authenticator for H.235 enabled endpoints
class H350PasswordAuth : public SimplePasswordAuth
{
public:
/// build authenticator reading settings from the config
H350PasswordAuth(
/// name for this authenticator and for the config section to read settings from
const char* authName
);
virtual ~H350PasswordAuth();
protected:
/** Override from SimplePasswordAuth.
@return
True if the password has been found for the given alias.
*/
virtual bool GetPassword(
/// alias to check the password for
const PString & alias,
/// password string, if the match is found
PString & password,
/// map of authentication parameters
std::map<PString, PString> & params
);
};