OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / gnugk / gkauth.cxx
1 //////////////////////////////////////////////////////////////////
2 //
3 // gkauth.cxx
4 //
5 // This work is published under the GNU Public License (GPL)
6 // see file COPYING for details.
7 // We also explicitely grant the right to link this code
8 // with the OpenH323 library.
9 //
10 //////////////////////////////////////////////////////////////////
11
12 #if defined(_WIN32) && (_MSC_VER <= 1200)
13 #pragma warning(disable:4786) // warning about too long debug symbol off
14 #pragma warning(disable:4284)
15 #endif
16
17 #include <ptlib.h>
18 #include <h235.h>
19 #include <h323pdu.h>
20 #include <h235auth.h>
21
22 #include "gk_const.h"
23 #include "h323util.h"
24 #include "stl_supp.h"
25 #include "Toolkit.h"
26 #include "RasTbl.h"
27 #include "RasPDU.h"
28 #include "sigmsg.h"
29 #include "Routing.h"
30 #include "gkauth.h"
31 #include "pwlib_compat.h"
32
33 namespace {
34 const char* const GkAuthSectionName = "Gatekeeper::Auth";
35 const char OID_CAT[] = "1.2.840.113548.10.1.2.1";
36 }
37
38 using std::stable_sort;
39 using std::for_each;
40 using std::find_if;
41 using std::greater;
42
43 ARQAuthData::ARQAuthData(
44         /// an endpoint requesting admission
45         const endptr& ep,
46         /// call record matching this ARQ (if any)
47         const callptr& call
48         ) : m_rejectReason(-1), m_callDurationLimit(-1), 
49         m_requestingEP(ep),     m_call(call), m_billingMode(-1),
50         m_routeToAlias(NULL), m_proxyMode(CallRec::ProxyDetect)
51 {
52 }
53
54 ARQAuthData::ARQAuthData(
55         const ARQAuthData& obj
56         ) : m_rejectReason(obj.m_rejectReason), 
57         m_callDurationLimit(obj.m_callDurationLimit), 
58         m_requestingEP(obj.m_requestingEP), m_call(obj.m_call), 
59         m_billingMode(obj.m_billingMode), m_routeToAlias(NULL),
60         m_destinationRoutes(obj.m_destinationRoutes), m_proxyMode(obj.m_proxyMode)
61 {
62         if (obj.m_routeToAlias)
63                 m_routeToAlias = new H225_AliasAddress(*obj.m_routeToAlias);
64 }
65
66 ARQAuthData& ARQAuthData::operator=(const ARQAuthData& obj)
67 {
68         m_callDurationLimit = obj.m_callDurationLimit; 
69         m_requestingEP = obj.m_requestingEP;
70         m_call = obj.m_call;
71         m_billingMode = obj.m_billingMode;
72         m_proxyMode = obj.m_proxyMode;
73         
74         delete m_routeToAlias;
75         m_routeToAlias = NULL;
76         if (obj.m_routeToAlias)
77                 m_routeToAlias = new H225_AliasAddress(*obj.m_routeToAlias);
78
79         m_destinationRoutes = obj.m_destinationRoutes;
80                         
81         return *this;
82 }
83
84 ARQAuthData::~ARQAuthData()
85 {
86         delete m_routeToAlias;
87         m_routeToAlias = NULL;
88 }
89
90 void ARQAuthData::SetRouteToAlias(H225_AliasAddress* alias)
91 {
92         delete m_routeToAlias;
93         m_routeToAlias = alias;
94 }
95
96 void ARQAuthData::SetRouteToAlias(const H225_AliasAddress& alias)
97 {
98         SetRouteToAlias(new H225_AliasAddress(alias));
99 }
100
101 void ARQAuthData::SetRouteToAlias(const PString& alias, int tag)
102 {
103         SetRouteToAlias(new H225_AliasAddress);
104         H323SetAliasAddress(alias, *m_routeToAlias, tag);
105 }
106
107 SetupAuthData::SetupAuthData(
108         /// call associated with the message (if any)
109         const callptr& call,
110         /// is the Setup message from a registered endpoint
111         bool fromRegistered
112         ) : m_rejectReason(-1), m_rejectCause(-1), m_callDurationLimit(-1),
113         m_call(call), m_fromRegistered(fromRegistered), 
114         m_routeToAlias(NULL), m_proxyMode(CallRec::ProxyDetect)
115 {
116 }
117
118 SetupAuthData::SetupAuthData(
119         const SetupAuthData& obj
120         ) : m_rejectReason(obj.m_rejectReason), m_rejectCause(obj.m_rejectCause), 
121         m_callDurationLimit(obj.m_callDurationLimit), m_call(obj.m_call), 
122         m_fromRegistered(obj.m_fromRegistered),
123         m_routeToAlias(NULL), m_destinationRoutes(obj.m_destinationRoutes),
124         m_proxyMode(obj.m_proxyMode)
125 {
126         if (obj.m_routeToAlias)
127                 m_routeToAlias = new H225_AliasAddress(*obj.m_routeToAlias);
128 }
129
130 SetupAuthData& SetupAuthData::operator=(const SetupAuthData& obj)
131 {
132         m_rejectReason = obj.m_rejectReason;
133         m_rejectCause = obj.m_rejectCause;
134         m_callDurationLimit = obj.m_callDurationLimit;
135         m_call = obj.m_call;
136         m_fromRegistered = obj.m_fromRegistered;
137         m_proxyMode = obj.m_proxyMode;
138         
139         delete m_routeToAlias;
140         m_routeToAlias = NULL;
141         if (obj.m_routeToAlias)
142                 m_routeToAlias = new H225_AliasAddress(*obj.m_routeToAlias);
143
144         m_destinationRoutes = obj.m_destinationRoutes;
145                 
146         return *this;
147 }
148
149 SetupAuthData::~SetupAuthData()
150 {
151         delete m_routeToAlias;
152         m_routeToAlias = NULL;
153 }
154
155 void SetupAuthData::SetRouteToAlias(H225_AliasAddress* alias)
156 {
157         delete m_routeToAlias;
158         m_routeToAlias = alias;
159 }
160
161 void SetupAuthData::SetRouteToAlias(const H225_AliasAddress& alias)
162 {
163         SetRouteToAlias(new H225_AliasAddress(alias));
164 }
165
166 void SetupAuthData::SetRouteToAlias(const PString& alias, int tag)
167 {
168         SetRouteToAlias(new H225_AliasAddress);
169         H323SetAliasAddress(alias, *m_routeToAlias, tag);
170 }
171
172
173 // class GkAuthenticator
174 GkAuthenticator::GkAuthenticator(
175         const char* name, /// a name for the module (to be used in the config file)
176         unsigned supportedRasChecks, /// RAS checks supported by this module
177         unsigned supportedMiscChecks /// non-RAS checks supported by this module
178         ) 
179         : NamedObject(name), m_defaultStatus(e_fail), m_controlFlag(e_Required),
180         m_enabledRasChecks(~0U), m_supportedRasChecks(supportedRasChecks), 
181         m_enabledMiscChecks(~0U), m_supportedMiscChecks(supportedMiscChecks),
182         m_config(GkConfig())
183 {
184         const PStringArray control(
185                 m_config->GetString(GkAuthSectionName, name, "").Tokenise(";,")
186                 );
187         if (control.GetSize() > 0) {
188                 const PString controlStr = control[0].Trim();
189                 if (strcasecmp(name, "default") == 0)
190                         m_controlFlag = e_Sufficient,
191                         m_defaultStatus = Toolkit::AsBool(controlStr) ? e_ok : e_fail;
192                 else if (controlStr *= "optional")
193                         m_controlFlag = e_Optional, m_defaultStatus = e_next;
194                 else if (controlStr *= "required")
195                         m_controlFlag = e_Required, m_defaultStatus = e_fail;
196                 else if (controlStr *= "sufficient")
197                         m_controlFlag = e_Sufficient, m_defaultStatus = e_fail;
198                 else
199                         PTRACE(1, "GKAUTH\tInvalid control flag '" << controlStr
200                                 << "' specified in the config for " << GetName()
201                                 );
202         } else
203                 PTRACE(1, "GKAUTH\tNo control flag specified in the config for module '" 
204                         << GetName() << '\''
205                         );
206
207         std::map<PString, unsigned> rasmap;
208         rasmap["GRQ"] = RasInfo<H225_GatekeeperRequest>::flag,
209         rasmap["RRQ"] = RasInfo<H225_RegistrationRequest>::flag,
210         rasmap["URQ"] = RasInfo<H225_UnregistrationRequest>::flag,
211         rasmap["ARQ"] = RasInfo<H225_AdmissionRequest>::flag,
212         rasmap["BRQ"] = RasInfo<H225_BandwidthRequest>::flag,
213         rasmap["DRQ"] = RasInfo<H225_DisengageRequest>::flag,
214         rasmap["LRQ"] = RasInfo<H225_LocationRequest>::flag,
215         rasmap["IRQ"] = RasInfo<H225_InfoRequest>::flag;
216                 
217         std::map<PString, unsigned> miscmap;
218         miscmap["SETUP"] = e_Setup;
219         miscmap["SETUPUNREG"] = e_SetupUnreg;
220         
221         if (control.GetSize() > 1) {
222                 m_enabledRasChecks = 0;
223                 m_enabledMiscChecks = 0;
224                 
225                 for (PINDEX i = 1; i < control.GetSize(); ++i) {
226                         const PString checkStr = control[i].Trim().ToUpper();
227                         if (rasmap.find(checkStr) != rasmap.end()) {
228                                 m_enabledRasChecks |= rasmap[checkStr];
229                                 if ((m_supportedRasChecks & rasmap[checkStr]) != rasmap[checkStr])
230                                         PTRACE(1, "GKAUTH\t" << GetName() << " does not support '"
231                                                 << control[i] << "' check"
232                                                 );
233                         } else if(miscmap.find(checkStr) != miscmap.end()) {
234                                 m_enabledMiscChecks |= miscmap[checkStr];
235                                 if ((m_supportedMiscChecks & miscmap[checkStr]) != miscmap[checkStr])
236                                         PTRACE(1, "GKAUTH\t" << GetName() << " does not support '"
237                                                 << control[i] << "' check"
238                                                 );
239                         } else
240                                 PTRACE(1, "GKAUTH\tInvalid check flag '" << control[i]
241                                         << "' specified in the config for " << GetName()
242                                         );
243                 }
244                 if ((m_enabledRasChecks & m_supportedRasChecks) == 0 
245                         && (m_enabledMiscChecks & m_supportedMiscChecks) == 0)
246                         PTRACE(1, "GKAUTH\tNo check flags have been specified "
247                                 "in the config for " << GetName() << " - it will be disabled"
248                                 );
249         }
250
251 #if PTRACING
252         // convert bit flags to human readable names
253         PString rasFlagsStr, miscFlagsStr;
254         
255         std::map<PString, unsigned>::const_iterator iter = rasmap.begin();
256         while (iter != rasmap.end()) {
257                 if (m_enabledRasChecks & iter->second) {
258                         if (!rasFlagsStr)
259                                 rasFlagsStr += ' ';
260                         rasFlagsStr += iter->first;
261                 }
262                 iter++;
263         }
264         
265         iter = miscmap.begin();
266         while (iter != miscmap.end()) {
267                 if (m_enabledMiscChecks & iter->second) {
268                         if (!miscFlagsStr)
269                                 miscFlagsStr += ' ';
270                         miscFlagsStr += iter->first;
271                 }
272                 iter++;
273         }
274         
275         if (rasFlagsStr.IsEmpty())
276                 rasFlagsStr = "NONE";
277         if (miscFlagsStr.IsEmpty())
278                 miscFlagsStr = "NONE";
279         
280         PTRACE(1, "GKAUTH\t" << GetName() << " rule added to check RAS: "
281                 << rasFlagsStr << ", OTHER: " << miscFlagsStr
282                 );
283 #endif  
284
285         m_h235Authenticators = NULL;
286 }
287
288 GkAuthenticator::~GkAuthenticator()
289 {
290         delete m_h235Authenticators;
291         PTRACE(1, "GKAUTH\t" << GetName() << " rule removed");
292 }
293
294 int GkAuthenticator::Check(RasPDU<H225_GatekeeperRequest> &, unsigned &)
295 {
296         return IsRasCheckEnabled(RasInfo<H225_GatekeeperRequest>::flag) 
297                 ? m_defaultStatus : e_next;
298 }
299
300 int GkAuthenticator::Check(
301         /// a request to be authenticated
302         RasPDU<H225_RegistrationRequest>& /*request*/,
303         /// authorization data (reject reason, ...)
304         RRQAuthData& /*authData*/
305         )
306 {
307         return IsRasCheckEnabled(RasInfo<H225_RegistrationRequest>::flag) 
308                 ? m_defaultStatus : e_next;
309 }
310
311 int GkAuthenticator::Check(RasPDU<H225_UnregistrationRequest> &, unsigned &)
312 {
313         return IsRasCheckEnabled(RasInfo<H225_UnregistrationRequest>::flag) 
314                 ? m_defaultStatus : e_next;
315 }
316
317 int GkAuthenticator::Check(
318         /// a request to be authenticated
319         RasPDU<H225_AdmissionRequest>& /*req*/,
320         /// authorization data (call duration limit, reject reason, ...)
321         ARQAuthData& /*authData*/
322         )
323 {
324         return IsRasCheckEnabled(RasInfo<H225_AdmissionRequest>::flag) 
325                 ? m_defaultStatus : e_next;
326 }
327
328 int GkAuthenticator::Check(RasPDU<H225_BandwidthRequest> &, unsigned &)
329 {
330         return IsRasCheckEnabled(RasInfo<H225_BandwidthRequest>::flag) 
331                 ? m_defaultStatus : e_next;
332 }
333
334 int GkAuthenticator::Check(RasPDU<H225_DisengageRequest> &, unsigned &)
335 {
336         return IsRasCheckEnabled(RasInfo<H225_DisengageRequest>::flag) 
337                 ? m_defaultStatus : e_next;
338 }
339
340 int GkAuthenticator::Check(RasPDU<H225_LocationRequest> &, unsigned &)
341 {
342         return IsRasCheckEnabled(RasInfo<H225_LocationRequest>::flag) 
343                 ? m_defaultStatus : e_next;
344 }
345
346 int GkAuthenticator::Check(RasPDU<H225_InfoRequest> &, unsigned &)
347 {
348         return IsRasCheckEnabled(RasInfo<H225_InfoRequest>::flag) 
349                 ? m_defaultStatus : e_next;
350 }
351
352 int GkAuthenticator::Check( 
353         SetupMsg &/*setup*/,
354         /// authorization data (call duration limit, reject reason, ...)
355         SetupAuthData& /*authData*/
356         )
357 {
358         return (IsMiscCheckEnabled(e_Setup) || IsMiscCheckEnabled(e_SetupUnreg)) 
359                 ? m_defaultStatus : e_next;
360 }
361
362 bool GkAuthenticator::GetH235Capability(
363         /// append supported authentication mechanism to this array
364         H225_ArrayOf_AuthenticationMechanism& mechanisms,
365         /// append supported algorithm OIDs for the given authentication
366         /// mechanism
367         H225_ArrayOf_PASN_ObjectId& algorithmOIDs
368         ) const
369 {
370         if (m_h235Authenticators && m_h235Authenticators->GetSize() > 0) {
371                 for (PINDEX i = 0; i < m_h235Authenticators->GetSize(); i++)
372                         (*m_h235Authenticators)[i].SetCapability(mechanisms, algorithmOIDs);
373                 return true;
374         } else
375                 return false;
376 }               
377
378 bool GkAuthenticator::IsH235Capability(
379         /// authentication mechanism
380         const H235_AuthenticationMechanism& mechanism,
381         /// algorithm OID for the given authentication mechanism
382         const PASN_ObjectId& algorithmOID
383         ) const
384 {
385         if (m_h235Authenticators)
386                 for (PINDEX i = 0; i < m_h235Authenticators->GetSize(); i++)
387                         if ((*m_h235Authenticators)[i].IsCapability(mechanism, algorithmOID))
388                                 return true;
389         return false;
390 }
391
392 bool GkAuthenticator::IsH235Capable() const
393 {
394         return m_h235Authenticators && m_h235Authenticators->GetSize() > 0;
395 }
396
397 void GkAuthenticator::SetSupportedChecks(
398         unsigned supportedRasChecks, /// RAS checks supported by this module
399         unsigned supportedMiscChecks /// non-RAS checks supported by this module
400         )
401 {
402         m_supportedRasChecks = supportedRasChecks;
403         m_supportedMiscChecks = supportedMiscChecks;
404 }
405
406 void GkAuthenticator::AppendH235Authenticator(
407         H235Authenticator* h235Auth /// H.235 authenticator to append
408         )
409 {
410         if (h235Auth) {
411                 if (m_h235Authenticators == NULL)
412                         m_h235Authenticators = new H235Authenticators();
413                 m_h235Authenticators->Append(h235Auth);
414         }
415 }
416
417 PString GkAuthenticator::GetUsername(
418         /// RRQ message with additional data
419         const RasPDU<H225_RegistrationRequest>& request
420         ) const
421 {
422         const H225_RegistrationRequest& rrq = request;
423         
424         PString username;
425         
426         if (rrq.HasOptionalField(H225_RegistrationRequest::e_terminalAlias))
427                 username = GetBestAliasAddressString(rrq.m_terminalAlias, false,
428                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
429                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
430                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
431                         );
432
433         if (username.IsEmpty()) {
434                 PIPSocket::Address addr;
435                 if (rrq.m_callSignalAddress.GetSize() > 0
436                         && GetIPFromTransportAddr(rrq.m_callSignalAddress[0], addr)
437                         && addr.IsValid())
438                         username = addr.AsString();
439                 else if (rrq.m_rasAddress.GetSize() > 0
440                         && GetIPFromTransportAddr(rrq.m_rasAddress[0], addr) 
441                         && addr.IsValid())
442                         username = addr.AsString();
443         }
444         
445         return username;
446 }
447
448 PString GkAuthenticator::GetUsername(
449         /// ARQ message with additional data
450         const RasPDU<H225_AdmissionRequest>& request,
451         /// additional data
452         ARQAuthData& authData
453         ) const
454 {
455         const H225_AdmissionRequest& arq = request;
456         const bool hasCall = authData.m_call.operator->() != NULL;
457         PString username;
458         
459         /// try to find h323_ID, email_ID or url_ID to use for User-Name
460         if (!arq.m_answerCall)
461                 username = GetBestAliasAddressString(arq.m_srcInfo, true, 
462                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
463                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
464                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
465                         );
466         else if (hasCall)
467                 username = GetBestAliasAddressString(authData.m_call->GetSourceAddress(), true,
468                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
469                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
470                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
471                         );
472                                 
473         if (authData.m_requestingEP && (username.IsEmpty() 
474                         || FindAlias(authData.m_requestingEP->GetAliases(), username) == P_MAX_INDEX))
475                 username = GetBestAliasAddressString(authData.m_requestingEP->GetAliases(), false,
476                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
477                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
478                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
479                         );
480
481         /// if no h323_ID, email_ID or url_ID has been found, try to find any alias
482         if (username.IsEmpty())
483                 if (!arq.m_answerCall)
484                         username = GetBestAliasAddressString(arq.m_srcInfo, false, 
485                                 AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
486                                 AliasAddressTagMask(H225_AliasAddress::e_email_ID)
487                                         | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
488                                 );
489                 else if (hasCall)
490                         username = GetBestAliasAddressString(
491                                 authData.m_call->GetSourceAddress(), true,
492                                 AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
493                                 AliasAddressTagMask(H225_AliasAddress::e_email_ID)
494                                         | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
495                                 );
496
497                 
498         if (username.IsEmpty()) {
499                 PIPSocket::Address addr;
500                 if (arq.HasOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress)
501                         && GetIPFromTransportAddr(arq.m_srcCallSignalAddress, addr)
502                         && addr.IsValid())
503                         username = addr.AsString();
504                 else if (authData.m_requestingEP 
505                         && GetIPFromTransportAddr(authData.m_requestingEP->GetCallSignalAddress(), addr) 
506                         && addr.IsValid())
507                         username = addr.AsString();
508         }
509         
510         return username;
511 }
512
513 PString GkAuthenticator::GetUsername(
514         const SetupMsg &setup,
515         /// additional data
516         SetupAuthData& authData
517         ) const
518 {
519         const bool hasCall = authData.m_call.operator->() != NULL;
520         PString username;                               
521         endptr callingEP;
522         Q931& q931pdu = setup.GetQ931();        
523         H225_Setup_UUIE &setupBody = setup.GetUUIEBody();
524         
525         if (hasCall)
526                 callingEP = authData.m_call->GetCallingParty();
527         
528         if (setupBody.HasOptionalField(H225_Setup_UUIE::e_sourceAddress)) {
529                 username = GetBestAliasAddressString(setupBody.m_sourceAddress, true,
530                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
531                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
532                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
533                         );
534                 if (!username && callingEP 
535                                 && FindAlias(callingEP->GetAliases(), username) == P_MAX_INDEX)
536                         username = PString();
537         }
538
539         if (username.IsEmpty() && hasCall) {
540                 username = GetBestAliasAddressString(
541                         authData.m_call->GetSourceAddress(), true,
542                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
543                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
544                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
545                         );
546                 if (!username && callingEP 
547                                 && FindAlias(callingEP->GetAliases(), username) == P_MAX_INDEX)
548                         username = PString();
549         }
550         
551         if (username.IsEmpty() && callingEP)
552                 username = GetBestAliasAddressString(callingEP->GetAliases(), false,
553                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
554                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
555                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
556                         );
557         
558         if (username.IsEmpty() && hasCall)
559                 username = GetBestAliasAddressString(
560                         authData.m_call->GetSourceAddress(), false,
561                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
562                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
563                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
564                         );
565
566         if (username.IsEmpty() && setupBody.HasOptionalField(H225_Setup_UUIE::e_sourceAddress))
567                 username = GetBestAliasAddressString(setupBody.m_sourceAddress, false,
568                         AliasAddressTagMask(H225_AliasAddress::e_h323_ID),
569                         AliasAddressTagMask(H225_AliasAddress::e_email_ID)
570                                 | AliasAddressTagMask(H225_AliasAddress::e_url_ID)
571                         );
572
573         if (username.IsEmpty())
574                 q931pdu.GetCallingPartyNumber(username);
575                 
576         if (username.IsEmpty()) {
577                 PIPSocket::Address addr(0);
578                 WORD port = 0;
579                 bool addrValid = false;
580         
581                 if (hasCall)
582                         addrValid = authData.m_call->GetSrcSignalAddr(addr, port) && addr.IsValid();
583                         
584                 if (!addrValid && setupBody.HasOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress))
585                         addrValid = GetIPFromTransportAddr(setupBody.m_sourceCallSignalAddress, addr)
586                                 && addr.IsValid();
587
588                 if (!addrValid && callingEP)
589                         addrValid = GetIPFromTransportAddr(callingEP->GetCallSignalAddress(), addr)
590                                 && addr.IsValid();
591
592                 if (addrValid)
593                         username = addr.AsString();
594         }
595         
596         return username;
597 }
598
599 PString GkAuthenticator::GetCallingStationId(
600         /// ARQ message with additional data
601         const RasPDU<H225_AdmissionRequest> &/*request*/,
602         /// additional data
603         ARQAuthData &authData
604         ) const
605 {
606         return authData.m_callingStationId;
607 }
608
609 PString GkAuthenticator::GetCallingStationId(
610         const SetupMsg &/*setup*/,
611         /// additional data
612         SetupAuthData &authData
613         ) const
614 {
615         return authData.m_callingStationId;
616 }
617
618 PString GkAuthenticator::GetCalledStationId(
619         /// ARQ message with additional data
620         const RasPDU<H225_AdmissionRequest> &/*request*/,
621         /// additional data
622         ARQAuthData &authData
623         ) const
624 {
625         return authData.m_calledStationId;
626 }
627
628 PString GkAuthenticator::GetCalledStationId(
629         const SetupMsg &/*setup*/,
630         /// additional data
631         SetupAuthData &authData
632         ) const
633 {
634         return authData.m_calledStationId;
635 }
636
637 PString GkAuthenticator::GetDialedNumber(
638         /// ARQ message with additional data
639         const RasPDU<H225_AdmissionRequest> &/*request*/,
640         /// additional data
641         ARQAuthData &authData
642         ) const
643 {
644         return authData.m_dialedNumber;
645 }
646
647 PString GkAuthenticator::GetDialedNumber(
648         const SetupMsg &/*setup*/,
649         /// additional data
650         SetupAuthData &authData
651         ) const
652 {
653         return authData.m_dialedNumber;
654 }
655
656
657 // class GkAuthenticatorList
658 GkAuthenticatorList::GkAuthenticatorList() 
659         : m_mechanisms(new H225_ArrayOf_AuthenticationMechanism),
660         m_algorithmOIDs(new H225_ArrayOf_PASN_ObjectId)
661 {
662 }
663
664 GkAuthenticatorList::~GkAuthenticatorList()
665 {
666         WriteLock lock(m_reloadMutex);
667         DeleteObjectsInContainer(m_authenticators);
668         m_authenticators.clear();
669         delete m_mechanisms;
670         delete m_algorithmOIDs;
671 }
672
673 void GkAuthenticatorList::OnReload()
674 {
675         // lock here to prevent too early authenticator destruction 
676         // from another thread
677         WriteLock lock(m_reloadMutex);
678
679         // first destroy old authenticators
680         DeleteObjectsInContainer(m_authenticators);
681         m_authenticators.clear();
682         
683         std::list<GkAuthenticator*> authenticators;     
684         GkAuthenticator *auth;
685         
686         const PStringArray authRules = GkConfig()->GetKeys(GkAuthSectionName);
687         for (PINDEX r = 0; r < authRules.GetSize(); r++) {
688                 auth = Factory<GkAuthenticator>::Create(authRules[r]);
689                 if (auth)
690                         authenticators.push_back(auth);
691         }
692
693         m_authenticators = authenticators;
694         
695         H225_ArrayOf_AuthenticationMechanism mechanisms;
696         H225_ArrayOf_PASN_ObjectId algorithmOIDs;
697
698         bool found = false;
699         int i, j, k;
700
701         // scan all authenticators that are either "required" or "sufficient"
702         // (skip "optional") and fill #mechanisms# and #algorithmOIDs# arrays
703         // with H.235 capabilities that are supported by all these authenticators
704         
705         std::list<GkAuthenticator*>::const_iterator iter = authenticators.begin();
706         
707         while (iter != authenticators.end()) {
708                 auth = *iter++;
709                 if (auth->IsH235Capable() 
710                                 && (auth->GetControlFlag() == GkAuthenticator::e_Required
711                                         || auth->GetControlFlag() == GkAuthenticator::e_Sufficient)) {
712                         if (mechanisms.GetSize() == 0) {
713                                 // append H.235 capability to empty arrays
714                                 auth->GetH235Capability(mechanisms, algorithmOIDs);
715                                 // should never happen, but we should check just for a case                             
716                                 if (algorithmOIDs.GetSize() == 0)
717                                         mechanisms.RemoveAll();
718                                 else
719                                         found = true;
720                                 continue;
721                         }
722
723                         // Already have H.235 capabilities - check the current
724                         // authenticator if it supports any of the capabilities.
725                         // Remove capabilities that are not supported
726
727                         H225_ArrayOf_AuthenticationMechanism matchedMechanisms;
728
729                         for (i = 0; i < algorithmOIDs.GetSize(); i++) {
730                                 bool matched = false;
731
732                                 for (j = 0; j < mechanisms.GetSize(); j++)
733                                         if (auth->IsH235Capability(mechanisms[j], algorithmOIDs[i])) {
734                                                 for (k = 0; k < matchedMechanisms.GetSize(); k++)
735                                                         if (matchedMechanisms[k].GetTag() == mechanisms[j].GetTag())
736                                                                 break;
737                                                 if (k == matchedMechanisms.GetSize()) {
738                                                         matchedMechanisms.SetSize(k+1);
739                                                         matchedMechanisms[k].SetTag(mechanisms[j].GetTag());
740                                                 }
741                                                 matched = true;
742                                         }
743
744                                 if (!matched) {
745                                         PTRACE(5, "GKAUTH\tAlgorithm OID: " << algorithmOIDs[i]
746                                                 << " removed from GCF list"
747                                                 );
748                                         algorithmOIDs.RemoveAt(i--);
749                                 }
750                         }
751
752                         for (i = 0; i < mechanisms.GetSize(); i++) {
753                                 for (j = 0; j < matchedMechanisms.GetSize(); j++)
754                                         if (mechanisms[i].GetTag() == matchedMechanisms[j].GetTag())
755                                                 break;
756                                 if (j == matchedMechanisms.GetSize()) {
757                                         PTRACE(5, "GKAUTH\tAuth method: " << mechanisms[i]
758                                                 << " removed from GCF list"
759                                                 );
760                                         mechanisms.RemoveAt(i--);
761                                 }
762                         }
763
764                         if (mechanisms.GetSize() == 0 || algorithmOIDs.GetSize() == 0)
765                                 break;
766                 }
767         }
768
769         // Scan "optional" authenticators if the above procedure has not found
770         // any H.235 capabilities or has found more than one
771         if ((!found) || mechanisms.GetSize() > 1 || algorithmOIDs.GetSize() > 1) {
772                 iter = authenticators.begin();
773                 while (iter != authenticators.end()) {
774                         auth = *iter++;
775                         if (auth->IsH235Capable() 
776                                         && auth->GetControlFlag() == GkAuthenticator::e_Optional) {
777                                 if (mechanisms.GetSize() == 0) {
778                                         auth->GetH235Capability(mechanisms, algorithmOIDs);
779                                         if (algorithmOIDs.GetSize() == 0 )
780                                                 mechanisms.RemoveAll();
781                                         else
782                                                 found = true;
783                                         continue;
784                                 }
785
786                                 H225_ArrayOf_AuthenticationMechanism matchedMechanisms;
787
788                                 for (i = 0; i < algorithmOIDs.GetSize(); i++) {
789                                         bool matched = false;
790
791                                         for (j = 0; j < mechanisms.GetSize(); j++)
792                                                 if (auth->IsH235Capability(mechanisms[j], algorithmOIDs[i])) {
793                                                         for (k = 0; k < matchedMechanisms.GetSize(); k++)
794                                                                 if (matchedMechanisms[k].GetTag() == mechanisms[j].GetTag())
795                                                                         break;
796                                                         if (k == matchedMechanisms.GetSize()) {
797                                                                 matchedMechanisms.SetSize(k+1);
798                                                                 matchedMechanisms[k].SetTag(mechanisms[j].GetTag());
799                                                         }
800                                                         matched = true;
801                                                 }
802
803                                         if (!matched) {
804                                                 PTRACE(5, "GKAUTH\tAlgorithm OID: " << algorithmOIDs[i]
805                                                         << " removed from GCF list"
806                                                         );
807                                                 algorithmOIDs.RemoveAt(i--);
808                                         }
809                                 }
810
811                                 for (i = 0; i < mechanisms.GetSize(); i++) {
812                                         for (j = 0; j < matchedMechanisms.GetSize(); j++)
813                                                 if (mechanisms[i].GetTag() == matchedMechanisms[j].GetTag())
814                                                         break;
815                                         if (j == matchedMechanisms.GetSize()) {
816                                                 PTRACE(5, "GKAUTH\tAuth method: " << mechanisms[i]
817                                                         << " removed from GCF list"
818                                                         );
819                                                 mechanisms.RemoveAt(i--);
820                                         }
821                                 }
822
823                                 if ((mechanisms.GetSize() == 0) || (algorithmOIDs.GetSize() == 0))
824                                         break;
825                         }
826                 }
827         }
828
829         if (mechanisms.GetSize() > 0 && algorithmOIDs.GetSize() > 0) {
830                 if (PTrace::CanTrace(4)) {
831 #if PTRACING
832                         ostream& strm = PTrace::Begin(4,__FILE__,__LINE__);
833                         strm <<"GkAuth\tH.235 capabilities selected for GCF:\n";
834                         strm <<"\tAuthentication mechanisms: \n";
835                         for (i = 0; i < mechanisms.GetSize(); i++)
836                                 strm << "\t\t" << mechanisms[i] << '\n';
837                         strm <<"\tAuthentication algorithm OIDs: \n";
838                         for (i = 0; i < algorithmOIDs.GetSize(); i++)
839                                 strm << "\t\t" << algorithmOIDs[i] << '\n';
840                         PTrace::End(strm);
841 #endif
842                 }
843         } else {
844                 PTRACE(4, "GKAUTH\tH.235 security is not active or conflicting "
845                         "H.235 capabilities are active - GCF will not select "
846                         "any particular capability"
847                         );
848                 mechanisms.RemoveAll();
849                 algorithmOIDs.RemoveAll();
850         }
851
852         // now switch to new setting
853         *m_mechanisms = mechanisms;
854         *m_algorithmOIDs = algorithmOIDs;
855 }
856
857 void GkAuthenticatorList::SelectH235Capability(
858         const H225_GatekeeperRequest& grq, 
859         H225_GatekeeperConfirm& gcf
860         )
861 {
862         ReadLock lock(m_reloadMutex);
863         
864         if (m_authenticators.empty())
865                 return;
866         
867         // if GRQ does not contain a list of authentication mechanisms simply return
868         if (!(grq.HasOptionalField(H225_GatekeeperRequest::e_authenticationCapability)
869                         && grq.HasOptionalField(H225_GatekeeperRequest::e_algorithmOIDs)
870                         && grq.m_authenticationCapability.GetSize() > 0
871                         && grq.m_algorithmOIDs.GetSize() > 0))
872                 return;
873
874         H225_ArrayOf_AuthenticationMechanism & mechanisms = *m_mechanisms;
875         H225_ArrayOf_PASN_ObjectId & algorithmOIDs = *m_algorithmOIDs;
876
877         // And now match H.235 capabilities found with those from GRQ
878         // to find the one to be returned in GCF                
879         for (int i = 0; i < grq.m_authenticationCapability.GetSize(); i++)
880                 for (int j = 0; j < mechanisms.GetSize(); j++)  
881                         if (grq.m_authenticationCapability[i].GetTag() == mechanisms[j].GetTag())
882                                 for (int l = 0; l < algorithmOIDs.GetSize(); l++)
883                                         for (int k = 0; k < grq.m_algorithmOIDs.GetSize(); k++)
884                                                 if (grq.m_algorithmOIDs[k] == algorithmOIDs[l]) {
885                                                         std::list<GkAuthenticator*>::const_iterator iter = m_authenticators.begin();
886                                                         while (iter != m_authenticators.end()) {
887                                                                 GkAuthenticator* auth = *iter++;
888                                                                 if (auth->IsH235Capable() && auth->IsH235Capability(mechanisms[j], algorithmOIDs[l])) {
889                                                                         gcf.IncludeOptionalField(H225_GatekeeperConfirm::e_authenticationMode);
890                                                                         gcf.m_authenticationMode = mechanisms[j];
891                                                                         gcf.IncludeOptionalField(H225_GatekeeperConfirm::e_algorithmOID);
892                                                                         gcf.m_algorithmOID = algorithmOIDs[l];
893
894                                                                         PTRACE(4, "GKAUTH\tGCF will select authentication "
895                                                                                 "mechanism: " << mechanisms[j] 
896                                                                                 << " and algorithm OID: "<< algorithmOIDs[l]
897                                                                                 );
898                                                                         return;
899                                                                 }
900                                                         }
901
902                                                         PTRACE(5, "GKAUTH\tAuthentication mechanism: "
903                                                                 << mechanisms[j] << " and algorithm OID: "
904                                                                 << algorithmOIDs[l] << " removed from GCF list"
905                                                                 );
906                                                 }
907 }
908
909 bool GkAuthenticatorList::Validate(
910         /// RRQ to be validated by authenticators
911         RasPDU<H225_RegistrationRequest>& request,
912         /// authorization data (reject reason, ...)
913         RRQAuthData& authData
914         )
915 {
916         ReadLock lock(m_reloadMutex);
917         std::list<GkAuthenticator*>::const_iterator i = m_authenticators.begin();
918         while (i != m_authenticators.end()) {
919                 GkAuthenticator* auth = *i++;
920                 if (auth->IsRasCheckEnabled(RasInfo<H225_RegistrationRequest>::flag)) {
921                         const int result = auth->Check(request, authData);
922                         if (result == GkAuthenticator::e_ok) {
923                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " RRQ check ok");
924                                 if (auth->GetControlFlag() != GkAuthenticator::e_Required)
925                                         return true;
926                         } else if (result == GkAuthenticator::e_fail) {
927                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " RRQ check failed");
928                                 return false;
929                         }
930                 }
931         }
932         return true;
933 }
934
935 bool GkAuthenticatorList::Validate(
936         /// ARQ to be validated by authenticators
937         RasPDU<H225_AdmissionRequest>& request,
938         /// authorization data (call duration limit, reject reason, ...)
939         ARQAuthData& authData
940         )
941 {
942         ReadLock lock(m_reloadMutex);
943         std::list<GkAuthenticator*>::const_iterator i = m_authenticators.begin();
944         while (i != m_authenticators.end()) {
945                 GkAuthenticator* auth = *i++;
946                 if (auth->IsRasCheckEnabled(RasInfo<H225_AdmissionRequest>::flag)) {
947                         const long oldDurationLimit = authData.m_callDurationLimit;
948                         const int result = auth->Check(request, authData);
949                         if (authData.m_callDurationLimit == 0) {
950                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " ARQ check failed: "
951                                         "call duration 0"
952                                         );
953                                 return false;
954                         }
955                         if (authData.m_callDurationLimit >= 0 && oldDurationLimit >= 0)
956                                 authData.m_callDurationLimit = PMIN(
957                                         authData.m_callDurationLimit, oldDurationLimit
958                                         );
959                         else
960                                 authData.m_callDurationLimit = PMAX(
961                                         authData.m_callDurationLimit, oldDurationLimit
962                                         );
963                         if (result == GkAuthenticator::e_ok) {
964                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " ARQ check ok");
965                                 if (auth->GetControlFlag() != GkAuthenticator::e_Required)
966                                         return true;
967                         } else if (result == GkAuthenticator::e_fail) {
968                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " ARQ check failed");
969                                 return false;
970                         }
971                 }
972         }
973         return true;
974 }
975
976 bool GkAuthenticatorList::Validate(
977         SetupMsg &setup,
978         /// authorization data (call duration limit, reject reason, ...)
979         SetupAuthData& authData
980         )
981 {
982         ReadLock lock(m_reloadMutex);
983         std::list<GkAuthenticator*>::const_iterator i = m_authenticators.begin();
984         while (i != m_authenticators.end()) {
985                 GkAuthenticator* auth = *i++;
986                 if (auth->IsMiscCheckEnabled(GkAuthenticator::e_Setup)
987                         || (!authData.m_fromRegistered 
988                                 && auth->IsMiscCheckEnabled(GkAuthenticator::e_SetupUnreg))) {
989                         const long oldDurationLimit = authData.m_callDurationLimit;
990                         const int result = auth->Check(setup, authData);
991                         if (authData.m_callDurationLimit == 0) {
992                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " Setup check failed: "
993                                         "call duration limit 0"
994                                         );
995                                 return false;
996                         }
997                         if (authData.m_callDurationLimit >= 0 && oldDurationLimit >= 0)
998                                 authData.m_callDurationLimit = PMIN(
999                                         authData.m_callDurationLimit, oldDurationLimit
1000                                         );
1001                         else
1002                                 authData.m_callDurationLimit = PMAX(
1003                                         authData.m_callDurationLimit, oldDurationLimit
1004                                         );
1005                         if (result == GkAuthenticator::e_ok) {
1006                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " Setup check ok");
1007                                 if (auth->GetControlFlag() != GkAuthenticator::e_Required)
1008                                         return true;
1009                         } else if (result == GkAuthenticator::e_fail) {
1010                                 PTRACE(3, "GKAUTH\t" << auth->GetName() << " Setup check failed");
1011                                 return false;
1012                         }
1013                 }
1014         }
1015         return true;
1016 }
1017
1018 // class CacheManager
1019 bool CacheManager::Retrieve(
1020         const PString& key, /// the key to look for
1021         PString& value /// filled with the value on return
1022         ) const
1023 {
1024         // quick check
1025         if (m_ttl == 0)
1026                 return false;
1027                 
1028         ReadLock lock(m_rwmutex);
1029         
1030         std::map<PString, PString>::const_iterator iter = m_cache.find(key);
1031         if (iter == m_cache.end())
1032                 return false;
1033         if (m_ttl >= 0) {
1034                 std::map<PString, long>::const_iterator i = m_ctime.find(key);
1035                 if (i == m_ctime.end() || (time(NULL) - i->second) >= m_ttl)
1036                         return false; // cache expired
1037         }
1038         value = (const char *)(iter->second);
1039         return true;
1040 }
1041
1042 void CacheManager::Save(
1043         const PString& key, /// a key to be stored
1044         const PString& value /// a value to be associated with the key
1045         )
1046 {
1047         if (m_ttl != 0) {
1048                 WriteLock lock(m_rwmutex);
1049                 m_cache[key] = (const char*)value;
1050                 m_ctime[key] = time(NULL);
1051         }
1052 }
1053
1054
1055 // class SimplePasswordAuth
1056 SimplePasswordAuth::SimplePasswordAuth(
1057         const char* name,
1058         unsigned supportedRasChecks,
1059         unsigned supportedMiscChecks
1060         ) 
1061         : GkAuthenticator(name, supportedRasChecks, supportedMiscChecks), 
1062         m_cache(NULL)
1063 {
1064         if (!GetConfig()->HasKey(name, "KeyFilled"))
1065                 PTRACE(1, "GKAUTH\t" << GetName() << " KeyFilled config variable "
1066                         "is missing"
1067                         );
1068         m_encryptionKey = GetConfig()->GetInteger(name, "KeyFilled", 0);
1069         m_checkID = Toolkit::AsBool(GetConfig()->GetString(name, "CheckID", "0"));
1070         m_cache = new CacheManager(GetConfig()->GetInteger(name, "PasswordTimeout", -1));
1071
1072 #ifdef OpenH323Factory
1073     PFactory<H235Authenticator>::KeyList_T keyList = PFactory<H235Authenticator>::GetKeyList();
1074     PFactory<H235Authenticator>::KeyList_T::const_iterator r;
1075     for (r = keyList.begin(); r != keyList.end(); ++r) {
1076        H235Authenticator * Auth = PFactory<H235Authenticator>::CreateInstance(*r);
1077        AppendH235Authenticator(Auth);
1078         }
1079 #else
1080         H235Authenticator* authenticator;
1081
1082         authenticator = new H235AuthSimpleMD5;
1083         authenticator->SetLocalId("dummy");
1084         authenticator->SetRemoteId("dummy");
1085         authenticator->SetPassword("dummy");
1086         AppendH235Authenticator(authenticator);
1087         authenticator = new H235AuthCAT;
1088         authenticator->SetLocalId("dummy");
1089         authenticator->SetRemoteId("dummy");
1090         authenticator->SetPassword("dummy");
1091         AppendH235Authenticator(authenticator);
1092
1093 //#if P_SSL
1094 //      authenticator = new H235AuthProcedure1;
1095 //      authenticator->SetLocalId("dummy");
1096 //      authenticator->SetRemoteId("dummy");
1097 //      authenticator->SetPassword("dummy");
1098 //      AppendH235Authenticator(authenticator);
1099 //#endif
1100
1101 #endif
1102
1103 }
1104
1105 SimplePasswordAuth::~SimplePasswordAuth()
1106 {
1107         delete m_cache;
1108 }
1109
1110 int SimplePasswordAuth::Check(RasPDU<H225_GatekeeperRequest> & request, unsigned &)
1111 {
1112         return doCheck(request);
1113 }
1114
1115 int SimplePasswordAuth::Check(
1116         RasPDU<H225_RegistrationRequest> & request, 
1117         RRQAuthData& /*authData*/
1118         )
1119 {
1120         H225_RegistrationRequest& rrq = request;
1121         return doCheck(request, 
1122                 rrq.HasOptionalField(H225_RegistrationRequest::e_terminalAlias) 
1123                         ? &rrq.m_terminalAlias : NULL
1124                 );
1125 }
1126
1127 int SimplePasswordAuth::Check(RasPDU<H225_UnregistrationRequest> & request, unsigned &)
1128 {
1129         return doCheck(request);
1130 }
1131
1132 int SimplePasswordAuth::Check(RasPDU<H225_BandwidthRequest> & request, unsigned &)
1133 {
1134         return doCheck(request);
1135 }
1136
1137 int SimplePasswordAuth::Check(RasPDU<H225_DisengageRequest> & request, unsigned &)
1138 {
1139         return doCheck(request);
1140 }
1141
1142 int SimplePasswordAuth::Check(RasPDU<H225_LocationRequest> & request, unsigned &)
1143 {
1144         return doCheck(request);
1145 }
1146
1147 int SimplePasswordAuth::Check(RasPDU<H225_InfoRequest> & request, unsigned &)
1148 {
1149         return doCheck(request);
1150 }
1151
1152 int SimplePasswordAuth::Check(
1153         /// ARQ to be authenticated/authorized
1154         RasPDU<H225_AdmissionRequest>& request, 
1155         /// authorization data (call duration limit, reject reason, ...)
1156         ARQAuthData& /*authData*/
1157         )
1158 {
1159         H225_AdmissionRequest& arq = request;
1160         return doCheck(request, &arq.m_srcInfo);
1161 }
1162
1163 bool SimplePasswordAuth::GetPassword(
1164         const PString& id, /// get the password for this id
1165         PString& passwd /// filled with the password on return
1166         )
1167 {
1168         if (id.IsEmpty())
1169                 return false;
1170         if (!GetConfig()->HasKey(GetName(), id))
1171                 return false;
1172         if (strcasecmp(id, "KeyFilled") == 0 || strcasecmp(id, "CheckID") == 0
1173                 || strcasecmp(id, "PasswordTimeout") == 0) {
1174                 PTRACE(2, "GKAUTH\t" << GetName() << " trying to get password for "
1175                         " the forbidden alias '" << id << '\''
1176                         );
1177                 return false;
1178         }
1179         passwd = Toolkit::Instance()->ReadPassword(GetName(), id, true);
1180         return true;
1181 }
1182
1183 bool SimplePasswordAuth::InternalGetPassword(
1184         const PString& id, /// get the password for this id
1185         PString& passwd /// filled with the password on return
1186         )
1187 {
1188         if (m_cache->Retrieve(id, passwd)) {
1189                 PTRACE(5, "GKAUTH\t" << GetName() << " cached password found for '"
1190                         << id << '\''
1191                         );
1192                 return true;
1193         }
1194         if (GetPassword(id, passwd)) {
1195                 m_cache->Save(id, passwd);
1196                 return true;
1197         } else
1198                 return false;
1199 }
1200
1201 int SimplePasswordAuth::CheckTokens(
1202         /// an array of tokens to be checked
1203         const H225_ArrayOf_ClearToken& tokens,
1204         /// aliases for the endpoint that generated the tokens
1205         const H225_ArrayOf_AliasAddress* aliases
1206         )
1207 {
1208         for (PINDEX i = 0; i < tokens.GetSize(); i++) {
1209                 H235_ClearToken& token = tokens[i];
1210
1211                 // check for Cisco Access Token
1212                 if (token.m_tokenOID == OID_CAT) {
1213                         if (!token.HasOptionalField(H235_ClearToken::e_generalID)) {
1214                                 PTRACE(3, "GKAUTH\t" << GetName() << " generalID field "
1215                                         "not found inside CAT token"
1216                                         );
1217                                 return e_fail;
1218                         }
1219                         const PString id = token.m_generalID;
1220                         if (m_checkID && (aliases == NULL || FindAlias(*aliases, id) == P_MAX_INDEX)) {
1221                                 PTRACE(3, "GKAUTH\t" << GetName() << " generalID '" << id
1222                                         << "' of CAT token does not match any alias for the endpoint"
1223                                         );
1224                                 return e_fail;
1225                         }
1226                         
1227                         PString passwd;
1228                         if (!InternalGetPassword(id, passwd)) {
1229                                 PTRACE(3, "GKAUTH\t" << GetName() << " password not found for '"
1230                                         << id << '\''
1231                                         );
1232                                 return e_fail;
1233                         }
1234
1235                         H235AuthCAT authCAT;
1236                         authCAT.SetLocalId(id);
1237                         authCAT.SetPassword(passwd);
1238                         if (authCAT.ValidateClearToken(token) == H235Authenticator::e_OK) {
1239                                 PTRACE(5, "GKAUTH\t" << GetName() << " CAT password match for '"
1240                                         << id << '\''
1241                                         );
1242                                 return e_ok;
1243                         } else
1244                                 return e_fail;
1245                 }
1246                 
1247                 if (token.HasOptionalField(H235_ClearToken::e_password)) {
1248                         if (!token.HasOptionalField(H235_ClearToken::e_generalID)) {
1249                                 PTRACE(3, "GKAUTH\t"<< GetName() << " generalID field not found"
1250                                         <<" inside the clear text token"
1251                                         );
1252                                 return e_fail;
1253                         }
1254                         const PString id = token.m_generalID;
1255                         if (m_checkID && (aliases == NULL || FindAlias(*aliases, id) == P_MAX_INDEX)) {
1256                                 PTRACE(3, "GKAUTH\t" << GetName() << " generalID '"
1257                                         <<"' does not match any alias for the endpoint"
1258                                         );
1259                                 return e_fail;
1260                         }
1261                         
1262                         PString passwd;
1263                         if (!InternalGetPassword(id, passwd)) {
1264                                 PTRACE(3, "GKAUTH\t" << GetName() << " password not found for '"
1265                                         << id << '\''
1266                                         );
1267                                 return e_fail;
1268                         }
1269                         
1270                         const PString tokenpasswd = token.m_password;
1271                         if (passwd == tokenpasswd) {
1272                                 PTRACE(5, "GKAUTH\t" << GetName() << " clear text password "
1273                                         "match for '" << id << '\''
1274                                         );
1275                                 return e_ok;
1276                         } else
1277                                 return e_fail;
1278                 }
1279         }
1280         return e_next;
1281 }
1282
1283 int SimplePasswordAuth::CheckCryptoTokens(
1284         /// an array of cryptoTokens to be checked
1285         const H225_ArrayOf_CryptoH323Token& tokens, 
1286         /// aliases for the endpoint that generated the tokens
1287         const H225_ArrayOf_AliasAddress* aliases,
1288         /// raw data for RAS PDU - required to validate some tokens
1289         /// like H.235 Auth Procedure I
1290         const PBYTEArray& rawPDU
1291         )
1292 {
1293         for (PINDEX i = 0; i < tokens.GetSize(); i++) {
1294                 if (tokens[i].GetTag() == H225_CryptoH323Token::e_cryptoEPPwdHash) {
1295                         H225_CryptoH323Token_cryptoEPPwdHash& pwdhash = tokens[i];
1296                         const PString id = AsString(pwdhash.m_alias, false);
1297                         if (m_checkID && (aliases == NULL || FindAlias(*aliases, id) == P_MAX_INDEX)) {
1298                                 PTRACE(3, "GKAUTH\t" << GetName() << " alias '" << id 
1299                                         << "' of the cryptoEPPwdHash token does not match "
1300                                         "any alias for the endpoint"
1301                                         );
1302                                 return e_fail;
1303                         }
1304
1305                         PString passwd;
1306                         if (!InternalGetPassword(id, passwd)) {
1307                                 PTRACE(3, "GKAUTH\t" << GetName() << " password not found for '"
1308                                         << id << '\''
1309                                         );
1310                                 return e_fail;
1311                         }
1312                         
1313                         H235AuthSimpleMD5 authMD5;
1314                         authMD5.SetLocalId(id);
1315                         authMD5.SetPassword(passwd);
1316                         if (authMD5.ValidateCryptoToken(tokens[i], rawPDU) == H235Authenticator::e_OK) {
1317                                 PTRACE(5, "GKAUTH\t" << GetName() << " MD5 password match for '"
1318                                         << id << '\''
1319                                         );
1320                                 return e_ok;
1321                         } else
1322                                 return e_fail;
1323 #if P_SSL
1324                 } else if (tokens[i].GetTag() == H225_CryptoH323Token::e_nestedcryptoToken) {
1325                         const H235_CryptoToken& nestedCryptoToken = tokens[i];
1326                         
1327                         if (nestedCryptoToken.GetTag() != H235_CryptoToken::e_cryptoHashedToken)
1328                                 continue;
1329                                 
1330                         const H235_CryptoToken_cryptoHashedToken& cryptoHashedToken = nestedCryptoToken;
1331                         const H235_ClearToken& clearToken = cryptoHashedToken.m_hashedVals;
1332                         
1333                         if (!clearToken.HasOptionalField(H235_ClearToken::e_sendersID)) {
1334                                 PTRACE(5, "GKAUTH\t" << GetName() << " hashedVals of nested "
1335                                         " cryptoHashedToken do not contain sendersID"
1336                                         );
1337                                 continue;
1338                         }
1339                         
1340                         PString id = clearToken.m_sendersID; 
1341                         if (m_checkID && (aliases == NULL || FindAlias(*aliases, id) == P_MAX_INDEX)) {
1342                                 PTRACE(3, "GKAUTH\t" << GetName() << " sendersID '" << id 
1343                                         << "' of the cryptoHashedToken hasgedVals does not match "
1344                                         "any alias for the endpoint"
1345                                         );
1346                                 return e_fail;
1347                         }
1348                         
1349                         PString passwd;
1350                         bool passwordFound = InternalGetPassword(id, passwd);
1351                         
1352                         //if a password is not found: senderID == endpointIdentifier?
1353                         if (!passwordFound) {
1354                                 H225_EndpointIdentifier epId;
1355                                 epId = id;
1356                                 endptr ep = RegistrationTable::Instance()->FindByEndpointId(epId);
1357                                 if (!ep) {
1358                                         PTRACE(3, "GKAUTH\t" << GetName() << " sendersID '" << id 
1359                                                 << "' of the cryptoHashedToken hashedVals does not match "
1360                                                 "any endpoint identifier"
1361                                                 );
1362                                         return e_fail;
1363                                 }
1364                                 
1365                                 // check all endpoint aliases for a password
1366                                 const H225_ArrayOf_AliasAddress aliases = ep->GetAliases();
1367                                 for (PINDEX i = 0; i < aliases.GetSize(); i++) {
1368                                         id = AsString(aliases[i], FALSE);
1369                                         passwordFound = InternalGetPassword(id, passwd);
1370                                         if (passwordFound)
1371                                                 break;
1372                                 }
1373                         }
1374                         
1375                         if (!passwordFound) {
1376                                 PTRACE(3, "GKAUTH\t" << GetName() << " password not found for '"
1377                                         << id << '\''
1378                                         );
1379                                 return e_fail;
1380                         }
1381                         
1382                         H235AuthProcedure1 authProcedure1;
1383                         authProcedure1.SetLocalId(Toolkit::GKName());
1384                         authProcedure1.SetPassword(passwd);
1385                         const int result = authProcedure1.ValidateCryptoToken(tokens[i], rawPDU);
1386                         if (result == H235Authenticator::e_OK) {
1387                                 PTRACE(5, "GKAUTH\t" << GetName() << " SHA-1 password match for '"
1388                                         << id << '\''
1389                                         );
1390                                 return e_ok;
1391                         } else if (result == H235Authenticator::e_Absent)
1392                                 continue;
1393                         else
1394                                 return e_fail;
1395 #endif
1396                 }
1397         }
1398         return e_next;
1399 }
1400
1401 bool SimplePasswordAuth::ResolveUserName(
1402                 const H225_ArrayOf_ClearToken& tokens,
1403             const H225_ArrayOf_CryptoH323Token& cryptotokens,
1404                 PString & username
1405                 )
1406 {
1407         for (PINDEX i = 0; i < cryptotokens.GetSize(); i++) {
1408           // MD5
1409                 if (cryptotokens[i].GetTag() == H225_CryptoH323Token::e_cryptoEPPwdHash) {
1410                         H225_CryptoH323Token_cryptoEPPwdHash& pwdhash = cryptotokens[i];
1411                         username = AsString(pwdhash.m_alias, false);
1412                         return true;
1413                 } else if (cryptotokens[i].GetTag() == H225_CryptoH323Token::e_nestedcryptoToken) {
1414                         H235_ClearToken clearToken;
1415                         bool found = false;
1416                         const H235_CryptoToken& nestedCryptoToken = cryptotokens[i];
1417
1418                     // H235.1
1419                         if (nestedCryptoToken.GetTag() == H235_CryptoToken::e_cryptoHashedToken) {
1420                           const H235_CryptoToken_cryptoHashedToken& cryptoHashedToken = nestedCryptoToken;
1421                           clearToken = cryptoHashedToken.m_hashedVals;
1422                           found = true;
1423                         }
1424                         // H235.2
1425                         if (nestedCryptoToken.GetTag() == H235_CryptoToken::e_cryptoSignedToken) {                      
1426                   const H235_CryptoToken_cryptoSignedToken & cryptoSignedToken = nestedCryptoToken;
1427               H235_SIGNED<H235_EncodedGeneralToken> m_Signed = cryptoSignedToken.m_token;
1428                           m_Signed.m_toBeSigned.DecodeSubType(clearToken);
1429                           found = true;
1430                         }
1431                 
1432                         if (found && (clearToken.HasOptionalField(H235_ClearToken::e_sendersID))) {
1433                username = clearToken.m_sendersID; 
1434                            return true;
1435                         }
1436                 } 
1437         }
1438
1439         for (PINDEX j = 0; j < cryptotokens.GetSize(); j++) {
1440                 H235_ClearToken& token = tokens[j];
1441                 // CAT
1442                         if (token.HasOptionalField(H235_ClearToken::e_generalID)) {
1443                 username = token.m_generalID;
1444                                 return true;
1445                         }
1446         }
1447
1448         return false;
1449 }
1450
1451 // class AliasAuth
1452 AliasAuth::AliasAuth(
1453         const char* name,
1454         unsigned supportedRasChecks,
1455         unsigned supportedMiscChecks
1456         ) 
1457         : GkAuthenticator(name, supportedRasChecks, supportedMiscChecks),
1458         m_cache(NULL)
1459 {
1460         m_cache = new CacheManager(GetConfig()->GetInteger(name, "CacheTimeout", -1));
1461 }
1462
1463 AliasAuth::~AliasAuth()
1464 {
1465         delete m_cache;
1466 }
1467
1468 int AliasAuth::Check(
1469         RasPDU<H225_RegistrationRequest>& request,
1470         RRQAuthData& /*authData*/
1471         )
1472 {
1473         H225_RegistrationRequest& rrq = request;
1474
1475         if (!rrq.HasOptionalField(H225_RegistrationRequest::e_terminalAlias)) {
1476                 PTRACE(3, "GKAUTH\t" << GetName() << " - terminalAlias field not found "
1477                         "in RRQ message"
1478                         );
1479                 return GetDefaultStatus();
1480         }
1481
1482         const H225_ArrayOf_AliasAddress& aliases = rrq.m_terminalAlias;
1483
1484         for (PINDEX i = 0; i <= aliases.GetSize(); i++) {
1485                 const PString alias = (i < aliases.GetSize())
1486                         ? AsString(aliases[i], false) : PString("default");
1487                 PString authcond;
1488                 if (InternalGetAuthConditionString(alias, authcond)) {
1489                         if (doCheck(rrq.m_callSignalAddress, authcond)) {
1490                                 PTRACE(5, "GKAUTH\t" << GetName() << " auth condition '"
1491                                         << authcond <<"' accepted RRQ from '" << alias << '\''
1492                                         );
1493                                 return e_ok;
1494                         } else {
1495                                 PTRACE(3, "GKAUTH\t" << GetName() << " auth condition '"
1496                                         << authcond <<"' rejected RRQ from '" << alias << '\''
1497                                         );
1498                                 return e_fail;
1499                         }
1500                 } else
1501                         PTRACE(4, "GKAUTH\t" << GetName() << " auth condition not found "
1502                                 << "for alias '" << alias << '\''
1503                                 );
1504         }
1505         return GetDefaultStatus();
1506 }
1507
1508 bool AliasAuth::GetAuthConditionString(
1509         /// an alias the condition string is to be retrieved for
1510         const PString& alias,
1511         /// filled with auth condition string that has been found
1512         PString& authCond
1513         )
1514 {
1515         if (alias.IsEmpty())
1516                 return false;
1517         if (!GetConfig()->HasKey("RasSrv::RRQAuth", alias))
1518                 return false;
1519         if (strcasecmp(alias, "CacheTimeout") == 0) {
1520                 PTRACE(2, "GKAUTH\t" << GetName() << " trying to get auth condition "
1521                         " string for the forbidden alias '" << alias << '\''
1522                         );
1523                 return false;
1524         }
1525         authCond = GetConfig()->GetString("RasSrv::RRQAuth", alias, "");
1526         return true;
1527 }
1528
1529 bool AliasAuth::InternalGetAuthConditionString(
1530         const PString& id, /// get the password for this id
1531         PString& authCond /// filled with the auth condition string on return
1532         )
1533 {
1534         if (m_cache->Retrieve(id, authCond)) {
1535                 PTRACE(5, "GKAUTH\t" << GetName() << " cached auth condition string "
1536                         "found for '" << id << '\''
1537                         );
1538                 return true;
1539         }
1540         if (GetAuthConditionString(id, authCond)) {
1541                 m_cache->Save(id, authCond);
1542                 return true;
1543         } else
1544                 return false;
1545 }
1546
1547 bool AliasAuth::doCheck(
1548         /// an array of source signalling addresses for an endpoint that sent the request
1549         const H225_ArrayOf_TransportAddress& sigaddr,
1550         /// auth condition string as returned by GetAuthConditionString
1551         const PString& condition
1552         )
1553 {
1554         const PStringArray authrules(condition.Tokenise("&|", FALSE));
1555 #if PTRACING
1556         if (authrules.GetSize() < 1) {
1557                 PTRACE(2, "GKAUTH\t" << GetName() << " contains an empty auth condition");
1558                 return false;
1559         }
1560 #endif
1561         for (PINDEX i = 0; i < authrules.GetSize(); ++i)
1562                 for (PINDEX j = 0; j < sigaddr.GetSize(); ++j)
1563                         if (CheckAuthRule(sigaddr[j], authrules[i])) {
1564                                 PTRACE(5, "GKAUTH\t" << GetName() << " auth rule '"
1565                                         << authrules[i] << "' applied successfully to RRQ "
1566                                         " from " << AsDotString(sigaddr[j])
1567                                         );
1568                                 return true;
1569                         }
1570         return false;
1571 }
1572
1573 bool AliasAuth::CheckAuthRule(
1574         /// a signalling address for the endpoint that sent the request
1575         const H225_TransportAddress& sigaddr,
1576         /// the auth rule to be used for checking
1577         const PString& authrule
1578         )
1579 {
1580         const PStringArray rule = authrule.Tokenise(":", false);
1581         if (rule.GetSize() < 1) {
1582                 PTRACE(1, "GKAUTH\t" << GetName() << " found invalid empty auth rule '"
1583                         << authrule << '\''
1584                         );
1585                 return false;
1586         }
1587         
1588         // authrule = rName[:params...]
1589         const PString rName = rule[0].Trim();
1590
1591         if (strcasecmp(rName, "confirm") == 0 || strcasecmp(rName, "allow") == 0)
1592                 return true;
1593         else if (strcasecmp(rName, "reject") == 0 || strcasecmp(rName, "deny") == 0
1594                 || strcasecmp(rName, "forbid") == 0)
1595                 return false;
1596         else if (strcasecmp(rName, "sigaddr") == 0) {
1597                 // condition 'sigaddr' example:
1598                 //   sigaddr:.*ipAddress .* ip = .* c3 47 e2 a2 .*port = 1720.*
1599                 if (rule.GetSize() < 2) {
1600                         PTRACE(1, "GKAUTH\t" << GetName() << " found invalid empty sigaddr "
1601                                 "auth rule '" << authrule << '\''
1602                                 );
1603                         return false;
1604                 }
1605                 return Toolkit::MatchRegex(AsString(sigaddr), rule[1].Trim()) != 0;
1606         } else if (strcasecmp(rName, "sigip") == 0) {
1607                 // condition 'sigip' example:
1608                 //   sigip:195.71.129.69:1720
1609                 if (rule.GetSize() < 2) {
1610                         PTRACE(1, "GKAUTH\t" << GetName() << " found invalid empty sigip "
1611                                 "auth rule '" << authrule << '\''
1612                                 );
1613                         return false;
1614                 }
1615                 PIPSocket::Address ip;
1616                 PIPSocket::GetHostAddress(rule[1].Trim(), ip);
1617                 const WORD port = (WORD)((rule.GetSize() < 3) 
1618                         ? GK_DEF_ENDPOINT_SIGNAL_PORT : rule[2].Trim().AsInteger());
1619                 return (sigaddr == SocketToH225TransportAddr(ip, port));
1620         } else {
1621                 PTRACE(1, "GKAUTH\t" << GetName() << " found unknown auth rule '"
1622                         << rName << '\''
1623                         );
1624                 return false;
1625         }
1626 }
1627
1628 // class PrefixAuth
1629
1630 // Initial author: Michael Rubashenkkov  2002/01/14 (GkAuthorize)
1631 // Completely rewrite by Chih-Wei Huang  2002/05/01
1632
1633 class AuthRule;
1634 class AuthObj;
1635
1636 class PrefixAuth : public GkAuthenticator 
1637 {
1638 public:
1639         typedef std::map< PString, AuthRule *, greater<PString> > Rules;
1640
1641         enum SupportedRasChecks {
1642                 PrefixAuthRasChecks = RasInfo<H225_AdmissionRequest>::flag
1643                         | RasInfo<H225_LocationRequest>::flag
1644         };
1645
1646         PrefixAuth(
1647                 const char* name,
1648                 unsigned supportedRasChecks = PrefixAuthRasChecks,
1649                 unsigned supportedMiscChecks = 0
1650                 );
1651                 
1652         virtual ~PrefixAuth();
1653
1654         // override from class GkAuthenticator
1655         virtual int Check(RasPDU<H225_LocationRequest>& request, unsigned& rejectReason);
1656
1657         /** Authenticate/Authorize ARQ message. Override from GkAuthenticator.
1658         
1659             @return
1660             e_fail - authentication failed
1661             e_ok - authenticated with this authenticator
1662             e_next - authentication could not be determined
1663         */
1664         virtual int Check(
1665                 /// ARQ to be authenticated/authorized
1666                 RasPDU<H225_AdmissionRequest>& request, 
1667                 /// authorization data (call duration limit, reject reason, ...)
1668                 ARQAuthData& authData
1669                 );
1670
1671 protected:
1672         virtual int doCheck(
1673                 const AuthObj& aobj
1674                 );
1675
1676 private:
1677         PrefixAuth();
1678         PrefixAuth(const PrefixAuth&);
1679         PrefixAuth& operator=(const PrefixAuth&);
1680         
1681 private:        
1682         Rules m_prefrules;
1683         int m_defaultRule;
1684 };
1685
1686 // Help classes for PrefixAuth
1687 class AuthObj // abstract class
1688 {
1689 public:
1690         virtual ~AuthObj() {}
1691
1692         virtual bool IsValid() const { return true; }
1693
1694         virtual PStringArray GetPrefixes() const = 0;
1695
1696         virtual PIPSocket::Address GetIP() const = 0;
1697         virtual PString GetAliases() const = 0;
1698 };
1699
1700 class ARQAuthObj : public AuthObj 
1701 {
1702 public:
1703         ARQAuthObj(
1704                 const H225_AdmissionRequest& arq
1705                 );
1706
1707         virtual bool IsValid() const { return m_ep; }
1708
1709         virtual PStringArray GetPrefixes() const;
1710
1711         virtual PIPSocket::Address GetIP() const;
1712         virtual PString GetAliases() const;
1713
1714 private:
1715         ARQAuthObj();
1716         ARQAuthObj(const ARQAuthObj&);
1717         ARQAuthObj& operator=(const ARQAuthObj&);
1718         
1719 private:
1720         const H225_AdmissionRequest& m_arq;
1721         endptr m_ep;
1722 };
1723
1724 class LRQAuthObj : public AuthObj 
1725 {
1726 public:
1727         LRQAuthObj(
1728                 const H225_LocationRequest& lrq
1729                 );
1730
1731         virtual PStringArray GetPrefixes() const;
1732
1733         virtual PIPSocket::Address GetIP() const;
1734         virtual PString GetAliases() const;
1735
1736 private:
1737         LRQAuthObj();
1738         LRQAuthObj(const LRQAuthObj&);
1739         LRQAuthObj& operator=(const LRQAuthObj&);
1740         
1741 private:
1742         const H225_LocationRequest& m_lrq;
1743         PIPSocket::Address m_ipAddress;
1744 };
1745
1746 class AuthRule : public NamedObject
1747 {
1748 public:
1749         enum Result {
1750                 e_nomatch,
1751                 e_allow,
1752                 e_deny
1753         };
1754
1755         AuthRule(
1756                 Result fate, 
1757                 bool inverted
1758                 ) : m_priority(1000), m_fate(fate), m_inverted(inverted), m_next(NULL) {}
1759         
1760         virtual ~AuthRule() { delete m_next; }
1761
1762         virtual bool Match(
1763                 const AuthObj& aobj
1764                 ) = 0;
1765                 
1766         int Check(
1767                 const AuthObj& aobj
1768                 );
1769         
1770         bool operator<(
1771                 const AuthRule& obj
1772                 ) const { return m_priority < obj.m_priority; }
1773         
1774         void SetNext(
1775                 AuthRule* next
1776                 ) { m_next = next; }
1777
1778 private:
1779         AuthRule();
1780         AuthRule(const AuthRule&);
1781         AuthRule& operator=(const AuthRule&);
1782         
1783 protected:
1784         /// the lesser the value, the higher the priority
1785         int m_priority; 
1786
1787 private:
1788         Result m_fate;
1789         bool m_inverted;
1790         AuthRule* m_next;
1791 };
1792
1793 class NullRule : public AuthRule 
1794 {
1795 public:
1796         NullRule() : AuthRule(e_nomatch, false) { SetName("NULL"); }
1797         
1798         virtual bool Match(
1799                 const AuthObj& /*aobj*/
1800                 ) { return false; }
1801
1802 private:
1803         NullRule(const NullRule&);
1804         NullRule& operator=(const NullRule&);
1805 };
1806
1807 class IPv4AuthRule : public AuthRule 
1808 {
1809 public:
1810         IPv4AuthRule(
1811                 Result fate, 
1812                 const PString& ipStr, 
1813                 bool inverted
1814                 );
1815
1816         virtual bool Match(
1817                 const AuthObj& aobj
1818                 );
1819
1820 private:
1821         IPv4AuthRule();
1822         IPv4AuthRule(const IPv4AuthRule&);
1823         IPv4AuthRule& operator=(const IPv4AuthRule&);
1824         
1825 private:
1826         PIPSocket::Address m_network, m_netmask;
1827 };
1828
1829 class AliasAuthRule : public AuthRule 
1830 {
1831 public:
1832         AliasAuthRule(
1833                 Result fate, 
1834                 const PString& aliasStr, 
1835                 bool inverted
1836                 ) : AuthRule(fate, inverted), m_pattern(aliasStr) 
1837         { 
1838                 m_priority = -1;
1839 #if PTRACING
1840                 SetName(PString((fate == e_allow) ? "allow alias" : "deny alias")
1841                         + (inverted ? ":!" : ":") + aliasStr
1842                         );
1843 #endif
1844         }
1845
1846         virtual bool Match(
1847                 const AuthObj& aobj
1848                 );
1849
1850 private:
1851         AliasAuthRule();
1852         AliasAuthRule(const AliasAuthRule&);
1853         AliasAuthRule& operator=(const AliasAuthRule&);
1854         
1855 private:
1856         PString m_pattern;
1857 };
1858
1859
1860 ARQAuthObj::ARQAuthObj(
1861         const H225_AdmissionRequest& arq
1862         ) 
1863         : m_arq(arq), m_ep(RegistrationTable::Instance()->FindByEndpointId(arq.m_endpointIdentifier))
1864 {
1865 }
1866
1867 PStringArray ARQAuthObj::GetPrefixes() const
1868 {
1869         PStringArray array;
1870         if (m_arq.HasOptionalField(H225_AdmissionRequest::e_destinationInfo)) {
1871                 const PINDEX ss = m_arq.m_destinationInfo.GetSize();
1872                 if (ss > 0) {
1873                         array.SetSize(ss);
1874                         for (PINDEX i = 0; i < ss; ++i)
1875                                 array[i] = AsString(m_arq.m_destinationInfo[i], false);
1876                 }
1877         }
1878         if (array.GetSize() == 0)
1879                 array.AppendString(PString());
1880         return array;
1881 }
1882
1883 PIPSocket::Address ARQAuthObj::GetIP() const
1884 {
1885         PIPSocket::Address result;
1886         const H225_TransportAddress& addr = 
1887                 m_arq.HasOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress) 
1888                 ? m_arq.m_srcCallSignalAddress : m_ep->GetCallSignalAddress();
1889         GetIPFromTransportAddr(addr, result);
1890         return result;
1891 }
1892
1893 PString ARQAuthObj::GetAliases() const
1894 {
1895         return AsString(m_ep->GetAliases());
1896 }
1897
1898 LRQAuthObj::LRQAuthObj(
1899         const H225_LocationRequest& lrq
1900         ) 
1901         : m_lrq(lrq)
1902 {
1903         GetIPFromTransportAddr(m_lrq.m_replyAddress, m_ipAddress);
1904 }
1905
1906 PStringArray LRQAuthObj::GetPrefixes() const
1907 {
1908         PStringArray array;
1909         const PINDEX ss = m_lrq.m_destinationInfo.GetSize();
1910         if (ss > 0) {
1911                 array.SetSize(ss);
1912                 for (PINDEX i = 0; i < ss; ++i)
1913                         array[i] = AsString(m_lrq.m_destinationInfo[i], false);
1914         }
1915         return array;
1916 }
1917
1918 PIPSocket::Address LRQAuthObj::GetIP() const
1919 {
1920         return m_ipAddress;
1921 }
1922
1923 PString LRQAuthObj::GetAliases() const
1924 {
1925         return m_lrq.HasOptionalField(H225_LocationRequest::e_sourceInfo) 
1926                 ? AsString(m_lrq.m_sourceInfo) : PString();
1927 }
1928
1929 int AuthRule::Check(
1930         const AuthObj& aobj
1931         )
1932 {
1933         if (Match(aobj) ^ m_inverted) {
1934                 PTRACE(5, "GKAUTH\tPrefix auth rule '" << GetName() << "' matched");
1935                 return m_fate;
1936         } else
1937                 return m_next ? m_next->Check(aobj) : e_nomatch;
1938 }
1939
1940 inline void delete_rule(PrefixAuth::Rules::value_type r)
1941 {
1942         delete r.second;
1943         r.second = NULL;
1944 }
1945
1946 IPv4AuthRule::IPv4AuthRule(
1947         Result fate, 
1948         const PString& ipStr, 
1949         bool inverted
1950         ) 
1951         : AuthRule(fate, inverted)
1952 {
1953         Toolkit::GetNetworkFromString(ipStr, m_network, m_netmask);
1954         DWORD n = ~PIPSocket::Net2Host(DWORD(m_netmask));
1955         for (m_priority = 0; n; n >>= 1)
1956                 ++m_priority;
1957 #if PTRACING
1958         SetName(PString((fate == e_allow) ? "allow ipv4(" : "deny ipv4(")
1959                 + PString(m_priority) + (inverted ? "):!" : "):") + ipStr
1960                 );
1961 #endif
1962 }
1963
1964 bool IPv4AuthRule::Match(
1965         const AuthObj& aobj
1966         )
1967 {
1968         return ((aobj.GetIP() & m_netmask) == m_network);
1969 }
1970
1971 bool AliasAuthRule::Match(
1972         const AuthObj& aobj
1973         )
1974 {
1975         return aobj.GetAliases().FindRegEx(m_pattern) != P_MAX_INDEX;
1976 }
1977
1978 inline bool is_inverted(const PString & cfg, PINDEX p)
1979 {
1980         return (p > 1) ? cfg[p-1] == '!' : false;
1981 }
1982
1983 inline bool comp_authrule_priority(AuthRule *a1, AuthRule *a2)
1984 {
1985         return *a1 < *a2;
1986 }
1987
1988 namespace {
1989 const char* const prfflag="prf:";
1990 const char* const allowflag="allow";
1991 const char* const denyflag="deny";
1992 const char* const ipflag="ipv4:";
1993 const char* const aliasflag="alias:";
1994 }
1995
1996 // class PrefixAuth
1997 PrefixAuth::PrefixAuth(
1998         const char* name,
1999         unsigned supportedRasChecks,
2000         unsigned supportedMiscChecks
2001         ) 
2002         : GkAuthenticator(name, supportedRasChecks, supportedMiscChecks)
2003 {
2004         m_defaultRule = GetDefaultStatus();
2005
2006         const int ipfl = strlen(ipflag);
2007         const int aliasfl = strlen(aliasflag);
2008         
2009         const PStringToString cfgs = GetConfig()->GetAllKeyValues(name);
2010         for (PINDEX i = 0; i < cfgs.GetSize(); ++i) {
2011                 PString key = cfgs.GetKeyAt(i);
2012                 if (key *= "default") {
2013                         m_defaultRule = Toolkit::AsBool(cfgs.GetDataAt(i)) ? e_ok : e_fail;
2014                         continue;
2015                 } else if (key *= "ALL") {
2016                         // use space (0x20) as the key so it will be the last resort
2017                         key = " ";
2018                 }
2019                 if (m_prefrules.find(key) != m_prefrules.end()) {
2020                         PTRACE(1, "GKAUTH\t" << GetName() << " duplicate entry for "
2021                                 "destination '" << key << '\''
2022                                 );
2023                         continue; //rule already exists? ignore
2024                 }
2025                 
2026                 const PStringArray rules = cfgs.GetDataAt(i).Tokenise("|", false);
2027                 const PINDEX sz = rules.GetSize();
2028                 if (sz < 1) {
2029                         PTRACE(1, "GKAUTH\t" << GetName() << " no rules found for "
2030                                 "destination '" << key << '\''
2031                                 );
2032                         continue;
2033                 }
2034                 //AuthRule *rls[sz];
2035                 AuthRule **rls = new AuthRule *[sz];
2036                 for (PINDEX j = 0; j < sz; ++j) {
2037                         // if not allowed, assume denial
2038                         const AuthRule::Result fate = (rules[j].Find(allowflag) != P_MAX_INDEX) 
2039                                 ? AuthRule::e_allow : AuthRule::e_deny;
2040                         PINDEX pp;
2041                         if ((pp = rules[j].Find(ipflag)) != P_MAX_INDEX)
2042                                 rls[j] = new IPv4AuthRule(fate, rules[j].Mid(pp + ipfl).Trim(), 
2043                                         is_inverted(rules[j], pp)
2044                                         );
2045                         else if ((pp = rules[j].Find(aliasflag)) != P_MAX_INDEX)
2046                                 rls[j] = new AliasAuthRule(fate, rules[j].Mid(pp+aliasfl).Trim(), 
2047                                         is_inverted(rules[j], pp)
2048                                         );
2049                         else {
2050                                 rls[j] = new NullRule;
2051                         }
2052                 }
2053
2054                 // sort the rules by priority
2055                 stable_sort(rls, rls + sz, comp_authrule_priority);
2056                 for (PINDEX k = 1; k < sz; ++k)
2057                         rls[k-1]->SetNext(rls[k]);
2058                 m_prefrules[key] = rls[0];
2059                 delete [] rls;
2060                 rls = NULL;
2061         }
2062
2063         if (m_prefrules.size() == 0)
2064                 PTRACE(1, "GKAUTH\t" << GetName() << " contains no rules - "
2065                         "check the config"
2066                         );
2067 }
2068
2069 PrefixAuth::~PrefixAuth()
2070 {
2071         for_each(m_prefrules.begin(), m_prefrules.end(), delete_rule);
2072 }
2073
2074 int PrefixAuth::Check(RasPDU<H225_LocationRequest> & request, unsigned &)
2075 {
2076         LRQAuthObj tmpObj((const H225_LocationRequest&)request); // fix for GCC 3.4.2
2077         return doCheck(tmpObj);
2078 }
2079
2080 int PrefixAuth::Check(
2081         /// ARQ to be authenticated/authorized
2082         RasPDU<H225_AdmissionRequest>& request, 
2083         /// authorization data (call duration limit, reject reason, ...)
2084         ARQAuthData& /*authData*/
2085         )
2086 {
2087         H225_AdmissionRequest& arq = request;
2088         if (arq.m_answerCall 
2089                 && arq.HasOptionalField(H225_AdmissionRequest::e_callIdentifier)
2090                 && CallTable::Instance()->FindCallRec(arq.m_callIdentifier)) {
2091                 PTRACE(5, "GKAUTH\t" << GetName() << " ARQ check skipped - call "
2092                         " already admitted and present in the call table"
2093                         );
2094                 return e_ok;
2095         }
2096         ARQAuthObj tmpObj(arq); // fix for GCC 3.4.2
2097         return doCheck(tmpObj);
2098 }
2099
2100 struct comp_pref { // function object
2101         comp_pref(const PString & s) : value(s) {}
2102         bool operator()(const PrefixAuth::Rules::value_type & v) const;
2103         const PString & value;
2104 };
2105
2106 inline bool comp_pref::operator()(const PrefixAuth::Rules::value_type & v) const
2107 {
2108         return (value.Find(v.first) == 0) || (v.first *= " ");
2109 }
2110
2111 int PrefixAuth::doCheck(
2112         const AuthObj& aobj
2113         )
2114 {
2115         if (!aobj.IsValid())
2116                 return e_fail;
2117         
2118         const PStringArray destinationInfo(aobj.GetPrefixes());
2119         for (PINDEX i = 0; i < destinationInfo.GetSize(); ++i) {
2120                 // find the first match rule
2121                 // since prefrules is descendently sorted
2122                 // it must be the most specific prefix
2123                 for (Rules::iterator j = m_prefrules.begin(); j != m_prefrules.end(); ++j) {
2124                         Rules::iterator iter = find_if(j, m_prefrules.end(), 
2125                                 comp_pref(destinationInfo[i])
2126                                 );
2127                         if (iter == m_prefrules.end())
2128                                 break;
2129                         switch (iter->second->Check(aobj))
2130                         {
2131                         case AuthRule::e_allow:
2132                                 PTRACE(4, "GKAUTH\t" << GetName() << " rule matched and "
2133                                         "accepted destination prefix '" 
2134                                         << ((iter->first == " ") ? PString("ALL") : iter->first)
2135                                         << "' for alias '" << destinationInfo[i] << '\''
2136                                         );
2137                                 return e_ok;
2138                                 
2139                         case AuthRule::e_deny:
2140                                 PTRACE(4, "GKAUTH\t" << GetName() << " rule matched and "
2141                                         "rejected destination prefix '" 
2142                                         << ((iter->first == " ") ? PString("ALL") : iter->first)
2143                                         << "' for alias '" << destinationInfo[i] << '\''
2144                                         );
2145                                 return e_fail;
2146                                 
2147                         default: // try next prefix...
2148                                 j = iter;
2149                                 PTRACE(4, "GKAUTH\t" << GetName() << " rule matched and "
2150                                         " could not reject or accept destination prefix '" 
2151                                         << ((iter->first == " ") ? PString("ALL") : iter->first)
2152                                         << "' for alias '" << destinationInfo[i] << '\''
2153                                         );
2154                         }
2155                 }
2156         }
2157 #if PTRACING
2158         if (m_defaultRule == e_ok)
2159                 PTRACE(4, "GKAUTH\t" << GetName() << " default rule accepted "
2160                         "the request"
2161                         );
2162         else if (m_defaultRule == e_fail)
2163                 PTRACE(4, "GKAUTH\t" << GetName() << " default rule rejected "
2164                         "the request"
2165                         );
2166         else
2167                 PTRACE(4, "GKAUTH\t" << GetName() << " could not reject or "
2168                         "accept the request"
2169                         );
2170 #endif
2171         return m_defaultRule;
2172 }
2173
2174 namespace { // anonymous namespace
2175         GkAuthCreator<GkAuthenticator> DefaultAuthenticatorCreator("default");
2176         GkAuthCreator<SimplePasswordAuth> SimplePasswordAuthCreator("SimplePasswordAuth");
2177         GkAuthCreator<AliasAuth> AliasAuthCreator("AliasAuth");
2178         GkAuthCreator<PrefixAuth> PrefixAuthCreator("PrefixAuth");
2179 } // end of anonymous namespace