OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / gnugk / sqlauth.cxx
1 /*
2  * sqlauth.cxx
3  *
4  * SQL authentication/authorization modules for GNU Gatekeeper
5  *
6  * $Id: sqlauth.cxx,v 1.10 2006/04/14 13:56:19 willamowius Exp $
7  *
8  * Copyright (c) 2004, Michal Zygmuntowicz
9  *
10  * This work is published under the GNU Public License (GPL)
11  * see file COPYING for details.
12  * We also explicitely grant the right to link this code
13  * with the OpenH323 library.
14  */
15 #if defined(_WIN32) && (_MSC_VER <= 1200)
16 #pragma warning(disable:4786) // warning about too long debug symbol off
17 #pragma warning(disable:4284)
18 #endif
19
20 #include <ptlib.h>
21 #include <h235.h>
22 #include <h323pdu.h>
23 #include <h235auth.h>
24 #include <limits>
25
26 #include "gk_const.h"
27 #include "h323util.h"
28 #include "stl_supp.h"
29 #include "RasTbl.h"
30 #include "RasPDU.h"
31 #include "Routing.h"
32 #include "Toolkit.h"
33 #include "RasSrv.h"
34 #include "gksql.h"
35 #include "sigmsg.h"
36 #include "h323util.h"
37 #include "Neighbor.h"
38 #include "gkauth.h"
39
40 using Routing::Route;
41
42 /// Generic SQL authenticator for H.235 enabled endpoints
43 class SQLPasswordAuth : public SimplePasswordAuth
44 {
45 public:
46         /// build authenticator reading settings from the config
47         SQLPasswordAuth(
48                 /// name for this authenticator and for the config section to read settings from
49                 const char* authName
50                 );
51         
52         virtual ~SQLPasswordAuth();
53
54 protected:
55         /** Override from SimplePasswordAuth.
56         
57             @return
58             True if the password has been found for the given alias.
59         */
60         virtual bool GetPassword(
61                 /// alias to check the password for
62                 const PString& alias,
63                 /// password string, if the match is found
64                 PString& password
65                 );
66
67 private:
68         SQLPasswordAuth();
69         SQLPasswordAuth(const SQLPasswordAuth&);
70         SQLPasswordAuth& operator=(const SQLPasswordAuth&);
71         
72 protected:
73         /// connection to the SQL database
74         GkSQLConnection* m_sqlConn;
75         /// parametrized query string for password retrieval
76         PString m_query;
77 };
78
79 /// Generic SQL authenticator for alias/IP based authentication
80 class SQLAliasAuth : public AliasAuth
81 {
82 public:
83         /// build authenticator reading settings from the config
84         SQLAliasAuth(
85                 /// name for this authenticator and for the config section to read settings from
86                 const char* authName
87                 );
88         
89         virtual ~SQLAliasAuth();
90
91 protected:
92         /** Get auth condition string for the given alias. 
93             This implementation searches the SQL database for the string.
94             Override from AliasAuth.
95                 
96             @return
97             The AliasAuth condition string for the given alias.
98         */
99         virtual bool GetAuthConditionString(
100                 /// an alias the condition string is to be retrieved for
101                 const PString& alias,
102                 /// filled with auth condition string that has been found
103                 PString& authCond
104                 );
105
106 private:
107         SQLAliasAuth();
108         SQLAliasAuth(const SQLAliasAuth&);
109         SQLAliasAuth& operator=(const SQLAliasAuth&);
110         
111 protected:
112         /// connection to the SQL database
113         GkSQLConnection* m_sqlConn;
114         /// parametrized query string for the auth condition string retrieval
115         PString m_query;
116 };
117
118 /// Generic SQL authenticator for non-password, SQL based authentication
119 class SQLAuth : public GkAuthenticator
120 {
121 public:
122         enum SupportedChecks {
123                 SQLAuthRasChecks = RasInfo<H225_RegistrationRequest>::flag
124                         | RasInfo<H225_AdmissionRequest>::flag
125                         | RasInfo<H225_LocationRequest>::flag,
126                 SQLAuthMiscChecks = e_Setup | e_SetupUnreg
127         };
128         
129         /// build authenticator reading settings from the config
130         SQLAuth(
131                 /// name for this authenticator and for the config section to read settings from
132                 const char* authName,
133                 /// RAS check events supported by this module
134                 unsigned supportedRasChecks = SQLAuthRasChecks,
135                 /// Misc check events supported by this module
136                 unsigned supportedMiscChecks = SQLAuthMiscChecks
137                 );
138         
139         virtual ~SQLAuth();
140
141         /** Authenticate using data from RRQ RAS message.
142         
143                 @return:
144                 #GkAuthenticator::Status enum# with the result of authentication.
145         */
146         virtual int Check(
147                 /// RRQ RAS message to be authenticated
148                 RasPDU<H225_RegistrationRequest>& rrqPdu, 
149                 /// authorization data (reject reason, ...)
150                 RRQAuthData& authData
151                 );
152                 
153         /** Authenticate using data from ARQ RAS message.
154         
155                 @return:
156                 #GkAuthenticator::Status enum# with the result of authentication.
157         */
158         virtual int Check(
159                 /// ARQ nessage to be authenticated
160                 RasPDU<H225_AdmissionRequest> & arqPdu, 
161                 /// authorization data (call duration limit, reject reason, ...)
162                 ARQAuthData& authData
163                 );
164
165         /** Authenticate using data from LRQ RAS message.
166         
167                 @return:
168                 #GkAuthenticator::Status enum# with the result of authentication.
169         */
170         virtual int Check(
171                 RasPDU<H225_LocationRequest>& req,
172                 unsigned& rejectReason
173                 );
174                 
175         /** Authenticate using data from Q.931 Setup message.
176         
177                 @return:
178                 #GkAuthenticator::Status enum# with the result of authentication.
179         */
180         virtual int Check(
181                 /// Q.931/H.225 Setup message to be authenticated
182                 SetupMsg &setup,
183                 /// authorization data (call duration limit, reject reason, ...)
184                 SetupAuthData& authData
185                 );
186
187 private:
188         SQLAuth();
189         SQLAuth(const SQLAuth&);
190         SQLAuth& operator=(const SQLAuth&);
191
192 protected:
193         /// connection to the SQL database
194         GkSQLConnection* m_sqlConn;
195         /// parametrized query string for RRQ auth
196         PString m_regQuery;
197         /// parametrized query string for LRQ auth
198         PString m_nbQuery;
199         /// parametrized query string for ARQ/Setup auth
200         PString m_callQuery;
201 };
202
203
204 namespace {
205
206 /// a common wrapper for SELECT query execution and result retrieval
207 bool RunQuery(
208         const PString &traceStr,
209         GkSQLConnection *conn,
210         const PString &query,
211         const std::map<PString, PString>& params,
212         GkSQLResult::ResultRow& resultRow,
213         long timeout
214         )
215 {
216         resultRow.clear();
217         
218         if (conn == NULL) {
219                 PTRACE(2, traceStr << ": query failed - SQL connection not active");
220                 return false;
221         }
222         
223         if (query.IsEmpty()) {
224                 PTRACE(2, traceStr << ": query failed - query string not configured");
225                 return false;
226         }
227         
228         GkSQLResult* result = conn->ExecuteQuery(query, params, timeout);
229         if (result == NULL) {
230                 PTRACE(2, traceStr << ": query failed - timeout or fatal error");
231                 return false;
232         }
233
234         if (!result->IsValid()) {
235                 PTRACE(2, traceStr << ": query failed (" << result->GetErrorCode()
236                         << ") - " << result->GetErrorMessage()
237                         );
238                 delete result;
239                 return false;
240         }
241         
242         if (result->GetNumRows() < 1)
243                 PTRACE(3, traceStr << ": query returned no rows");
244         else if (result->GetNumFields() < 1)
245                 PTRACE(2, traceStr << ": bad-formed query - "
246                         "no columns found in the result set"
247                         );
248         else if (!result->FetchRow(resultRow) || resultRow.empty())
249                 PTRACE(2, traceStr << ": query failed - could not fetch the result row");
250         else {
251                 delete result;
252                 return true;
253         }
254
255         delete result;
256         return false;
257 }
258
259 inline GkSQLResult::ResultRow::iterator FindField(
260         GkSQLResult::ResultRow& result,
261         const PString& fieldName
262         )
263 {
264         GkSQLResult::ResultRow::iterator i = result.begin();
265         while (i != result.end() && i->second != fieldName)
266                 i++;
267         return i;
268 }
269
270 } /* namespace */
271
272
273 SQLPasswordAuth::SQLPasswordAuth(
274         const char* authName
275         )
276         : SimplePasswordAuth(authName), m_sqlConn(NULL)
277 {
278         PConfig* cfg = GetConfig();
279
280         const PString driverName = cfg->GetString(authName, "Driver", "");
281         if (driverName.IsEmpty()) {
282                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
283                         "no SQL driver selected"
284                         );
285                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
286                 RasServer::Instance()->Stop();
287                 return;
288         }
289         
290         m_sqlConn = GkSQLConnection::Create(driverName, authName);
291         if (m_sqlConn == NULL) {
292                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
293                         "could not find " << driverName << " database driver"
294                         );
295                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
296                 RasServer::Instance()->Stop();
297                 return;
298         }
299
300         SetCacheTimeout(cfg->GetInteger(authName, "CacheTimeout", 0));
301                 
302         m_query = cfg->GetString(authName, "Query", "");
303         if (m_query.IsEmpty()) {
304                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
305                         "no query configured"
306                         );
307                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
308                 RasServer::Instance()->Stop();
309                 return;
310         } else
311                 PTRACE(4, "SQLAUTH\t" << GetName() << " query: " << m_query);
312                 
313         if (!m_sqlConn->Initialize(cfg, authName)) {
314                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
315                         "could not connect to the database"
316                         );
317                 return;
318         }
319 }
320
321 SQLPasswordAuth::~SQLPasswordAuth()
322 {
323         delete m_sqlConn;
324 }
325
326 bool SQLPasswordAuth::GetPassword(
327         const PString& alias,
328         PString& password
329         )
330 {
331         GkSQLResult::ResultRow result;
332         std::map<PString, PString> params;
333         params["1"] = alias;
334         params["u"] = alias;
335         params["2"] = Toolkit::GKName();
336         params["g"] = Toolkit::GKName();
337
338         if (!RunQuery("SQLAUTH\t" + GetName() + "('" + alias + "')", m_sqlConn, m_query, params, result, -1))
339                 return false;
340                 
341         password = result[0].first;
342         return true;
343 }
344
345 SQLAliasAuth::SQLAliasAuth(
346         const char* authName
347         )
348         : AliasAuth(authName), m_sqlConn(NULL)
349 {
350         PConfig* cfg = GetConfig();
351
352         const PString driverName = cfg->GetString(authName, "Driver", "");
353         if (driverName.IsEmpty()) {
354                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
355                         "no SQL driver selected"
356                         );
357                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
358                 RasServer::Instance()->Stop();
359                 return;
360         }
361         
362         m_sqlConn = GkSQLConnection::Create(driverName, authName);
363         if (m_sqlConn == NULL) {
364                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
365                         "could not find " << driverName << " database driver"
366                         );
367                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
368                 RasServer::Instance()->Stop();
369                 return;
370         }
371
372         SetCacheTimeout(cfg->GetInteger(authName, "CacheTimeout", 0));
373         
374         m_query = cfg->GetString(authName, "Query", "");
375         if (m_query.IsEmpty()) {
376                 PTRACE(1, "SQLAUTH\t" << GetName() << " module creation failed: "
377                         "no query configured"
378                         );
379                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
380                 RasServer::Instance()->Stop();
381                 return;
382         } else
383                 PTRACE(4, "SQLAUTH\t" << GetName() << " query: " << m_query);
384                 
385         if (!m_sqlConn->Initialize(cfg, authName)) {
386                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
387                         "could not connect to the database"
388                         );
389                 return;
390         }
391 }
392
393 SQLAliasAuth::~SQLAliasAuth()
394 {
395         delete m_sqlConn;
396 }
397
398 bool SQLAliasAuth::GetAuthConditionString(
399         const PString& alias,
400         PString& authCond
401         )
402 {
403         GkSQLResult::ResultRow result;
404         std::map<PString, PString> params;
405         params["1"] = alias;
406         params["u"] = alias;
407         params["2"] = Toolkit::GKName();
408         params["g"] = Toolkit::GKName();
409
410         if (!RunQuery("SQLAUTH\t" + GetName() + "('" + alias + "')", m_sqlConn, m_query, params, result, -1))
411                 return false;
412                 
413         authCond = result[0].first;
414         return true;
415 }
416
417
418 SQLAuth::SQLAuth(
419         const char* authName,
420         unsigned supportedRasChecks,
421         unsigned supportedMiscChecks
422         ) 
423         : 
424         GkAuthenticator(authName, supportedRasChecks, supportedMiscChecks), 
425         m_sqlConn(NULL)
426 {
427         PConfig* cfg = GetConfig();
428
429         const PString driverName = cfg->GetString(authName, "Driver", "");
430         if (driverName.IsEmpty()) {
431                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
432                         "no SQL driver selected"
433                         );
434                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
435                 RasServer::Instance()->Stop();
436                 return;
437         }
438         
439         m_sqlConn = GkSQLConnection::Create(driverName, authName);
440         if (m_sqlConn == NULL) {
441                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
442                         "could not find " << driverName << " database driver"
443                         );
444                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
445                 RasServer::Instance()->Stop();
446                 return;
447         }
448
449         m_regQuery = cfg->GetString(authName, "RegQuery", "");
450         if (m_regQuery.IsEmpty() && IsRasCheckEnabled(RasInfo<H225_RegistrationRequest>::flag)) {
451                 PTRACE(1, "SQLAUTH\t" << GetName() << " module creation failed: "
452                         "no RRQ query configured"
453                         );
454                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
455                 RasServer::Instance()->Stop();
456                 return;
457         } else if (!m_regQuery)
458                 PTRACE(4, "SQLAUTH\t" << GetName() << " RRQ query: " << m_regQuery);
459
460         m_nbQuery = cfg->GetString(authName, "NbQuery", "");
461         if (m_nbQuery.IsEmpty() && IsRasCheckEnabled(RasInfo<H225_LocationRequest>::flag)) {
462                 PTRACE(1, "SQLAUTH\t" << GetName() << " module creation failed: "
463                         "no LRQ query configured"
464                         );
465                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
466                 RasServer::Instance()->Stop();
467                 return;
468         } else if (!m_nbQuery)
469                 PTRACE(4, "SQLAUTH\t" << GetName() << " LRQ query: " << m_nbQuery);
470
471         m_callQuery = cfg->GetString(authName, "CallQuery", "");
472         if (m_callQuery.IsEmpty() && (IsRasCheckEnabled(RasInfo<H225_AdmissionRequest>::flag)
473                         || IsMiscCheckEnabled(e_Setup) || IsMiscCheckEnabled(e_SetupUnreg))) {
474                 PTRACE(1, "SQLAUTH\t" << GetName() << " module creation failed: "
475                         "no ARQ/Setup query configured"
476                         );
477                 PTRACE(0, "SQLAUTH\tFATAL: Shutting down");
478                 RasServer::Instance()->Stop();
479                 return;
480         } else if (!m_callQuery)
481                 PTRACE(4, "SQLAUTH\t" << GetName() << " ARQ/Setup query: " << m_callQuery);
482
483         if (!m_sqlConn->Initialize(cfg, authName)) {
484                 PTRACE(0, "SQLAUTH\t" << GetName() << " module creation failed: "
485                         "could not connect to the database"
486                         );
487                 return;
488         }
489 }
490
491 SQLAuth::~SQLAuth()
492 {
493         delete m_sqlConn;
494 }
495
496 int SQLAuth::Check(
497         /// RRQ RAS message to be authenticated
498         RasPDU<H225_RegistrationRequest>& rrqPdu, 
499         /// authorization data (reject reason, ...)
500         RRQAuthData& authData
501         )
502 {
503         H225_RegistrationRequest &rrq = rrqPdu;
504         std::map<PString, PString> params;
505         
506         // get the username for User-Name attribute             
507         params["u"] = GetUsername(rrqPdu);
508         params["g"] = Toolkit::GKName();
509         
510         PIPSocket::Address addr = (rrqPdu.operator->())->m_peerAddr;
511
512         const PString traceStr = "SQLAUTH\t" + GetName() + "(RRQ from "
513                 + addr.AsString() + " Username=" + params["u"]
514                 + ")";
515         params["callerip"] = addr.AsString();
516         
517         addr = (rrqPdu.operator->())->m_localAddr;
518         params["gkip"] = addr.AsString();
519
520         if (rrq.HasOptionalField(H225_RegistrationRequest::e_terminalAlias)) {
521                 PString aliasList;
522                 for (PINDEX i = 0; i < rrq.m_terminalAlias.GetSize(); i++) {
523                         if(i > 0)
524                                 aliasList += ",";
525                         aliasList += AsString(rrq.m_terminalAlias[i], FALSE);
526                 }
527                 params["aliases"] = aliasList;
528         }
529
530         GkSQLResult::ResultRow result;  
531         if (!RunQuery(traceStr, m_sqlConn, m_regQuery, params, result, -1)) {
532                 authData.m_rejectReason = H225_RegistrationRejectReason::e_resourceUnavailable;
533                 return GetDefaultStatus();
534         }
535
536         if (!Toolkit::AsBool(result[0].first)) {
537                 authData.m_rejectReason = H225_RegistrationRejectReason::e_securityDenial;
538                 return e_fail;
539         }
540
541         GkSQLResult::ResultRow::const_iterator iter = FindField(result, "billingmode");
542         if (iter != result.end()) {
543                 const PString &s = iter->first;
544                 if (!s) {
545                         if (strspn((const char*)s,"0123456789.") == (size_t)s.GetLength()) {
546                                 const int intVal = s.AsInteger();
547                                 if (intVal == 0)
548                                         authData.m_billingMode = H225_CallCreditServiceControl_billingMode::e_credit;
549                                 else if (intVal == 1 || intVal == 2)
550                                         authData.m_billingMode = H225_CallCreditServiceControl_billingMode::e_debit;
551                         } else {
552                                 PTRACE(3, traceStr << " - invalid billingmode attribute '"
553                                         << s << '\''
554                                         );
555                         }
556                 }
557         }
558
559         iter = FindField(result, "creditamount");
560         if (iter != result.end()) {
561                 if (!iter->first)
562                         authData.m_amountString = iter->first;
563         }
564
565         iter = FindField(result, "aliases");
566         if (iter != result.end()) {
567                 PStringArray aliases = iter->first.Tokenise(",");
568                 if (aliases.GetSize() > 0 
569                                 && rrq.HasOptionalField(H225_RegistrationRequest::e_terminalAlias)) {
570                         PINDEX i = 0;
571                         while (i < rrq.m_terminalAlias.GetSize()) {
572                                 PINDEX j = aliases.GetStringsIndex(AsString(rrq.m_terminalAlias[i], FALSE));
573                                 if( j == P_MAX_INDEX )
574                                         rrq.m_terminalAlias.RemoveAt(i);
575                                 else {
576                                         i++;
577                                         aliases.RemoveAt(j);
578                                 }
579                         }
580                 }
581                 for (PINDEX i = 0; i < aliases.GetSize(); i++) {
582                         if (rrq.HasOptionalField(H225_RegistrationRequest::e_terminalAlias))
583                                 rrq.m_terminalAlias.SetSize(rrq.m_terminalAlias.GetSize()+1);
584                         else {
585                                 rrq.IncludeOptionalField(H225_RegistrationRequest::e_terminalAlias);
586                                 rrq.m_terminalAlias.SetSize(1);
587                         }
588                         H323SetAliasAddress(aliases[i], rrq.m_terminalAlias[rrq.m_terminalAlias.GetSize()-1]);
589                 }
590         }
591                         
592         return e_ok;
593 }
594                 
595 int SQLAuth::Check(
596         /// ARQ nessage to be authenticated
597         RasPDU<H225_AdmissionRequest> & arqPdu, 
598         /// authorization data (call duration limit, reject reason, ...)
599         ARQAuthData& authData
600         )
601 {
602         const H225_AdmissionRequest &arq = arqPdu;
603         std::map<PString, PString> params;
604         
605         PIPSocket::Address addr = (arqPdu.operator->())->m_peerAddr;
606
607         const PString traceStr = "SQLAUTH\t" + GetName() + "(ARQ from "
608                 + addr.AsString() + " CRV=" + PString(arq.m_callReferenceValue.GetValue() & 0x7fff)
609                 + ")";
610         params["callerip"] = addr.AsString();
611                 
612         // get the username for User-Name attribute             
613         params["u"] = GetUsername(arqPdu, authData);
614         params["g"] = Toolkit::GKName();
615         
616         addr = (arqPdu.operator->())->m_localAddr;
617         params["gkip"] = addr.AsString();
618
619         params["Calling-Station-Id"] = GetCallingStationId(arqPdu, authData);
620         params["Called-Station-Id"] = GetCalledStationId(arqPdu, authData);
621         params["Dialed-Number"] = GetDialedNumber(arqPdu, authData);
622         params["bandwidth"] = PString(arq.m_bandWidth.GetValue());
623         params["answer"] = arq.m_answerCall ? "1" : "0";
624         params["arq"] = "1";
625         
626         GkSQLResult::ResultRow result;  
627         if (!RunQuery(traceStr, m_sqlConn, m_callQuery, params, result, -1)) {
628                 authData.m_rejectReason = H225_AdmissionRejectReason::e_resourceUnavailable;
629                 return GetDefaultStatus();
630         }
631
632         if (!Toolkit::AsBool(result[0].first)) {
633                 authData.m_rejectReason = H225_AdmissionRejectReason::e_securityDenial;
634                 return e_fail;
635         }
636
637         GkSQLResult::ResultRow::const_iterator iter = FindField(result, "billingmode");
638         if (iter != result.end()) {
639                 const PString &s = iter->first;
640                 if (!s) {
641                         if (strspn((const char*)s,"0123456789.") == (size_t)s.GetLength()) {
642                                 const int intVal = s.AsInteger();
643                                 if (intVal == 0)
644                                         authData.m_billingMode = H225_CallCreditServiceControl_billingMode::e_credit;
645                                 else if (intVal == 1 || intVal == 2)
646                                         authData.m_billingMode = H225_CallCreditServiceControl_billingMode::e_debit;
647                         } else {
648                                 PTRACE(3, traceStr << " - invalid billingmode attribute '"
649                                         << s << '\''
650                                         );
651                         }
652                 }
653         }
654
655         iter = FindField(result, "creditamount");
656         if (iter != result.end()) {
657                 if (!iter->first)
658                         authData.m_amountString = iter->first;
659         }
660
661         iter = FindField(result, "credittime");
662         if (iter != result.end()) {
663                 const PString &s = iter->first;
664                 if (s.GetLength() > 0
665                         && strspn((const char*)s, "0123456789") == (size_t)s.GetLength()) {
666                         PUInt64 limit = s.AsUnsigned64();
667                         if (limit > PUInt64(std::numeric_limits<long>::max()))
668                                 authData.m_callDurationLimit = std::numeric_limits<long>::max();
669                         else
670                                 authData.m_callDurationLimit = static_cast<long>(limit);
671                         PTRACE(5, traceStr << " - duration limit set to "
672                                 << authData.m_callDurationLimit
673                                 );
674                         if (authData.m_callDurationLimit == 0) {
675                                 authData.m_rejectReason = H225_AdmissionRejectReason::e_securityDenial;
676                                 return e_fail;
677                         }
678                 }
679         }
680
681         iter = FindField(result, "redirectnumber");
682         if (iter != result.end()) {
683                 const PString &s = iter->first;
684                 if (!s) {
685                         authData.SetRouteToAlias(s);
686                         PTRACE(5, traceStr << " - call redirected to the number " << s);
687                 }
688         }
689                         
690         iter = FindField(result, "redirectip");
691         if (iter != result.end()) {
692                 const PString &s = iter->first;
693                 if (!s) {
694                         PStringArray tokens(s.Tokenise("; \t", FALSE));
695                         for (PINDEX i = 0; i < tokens.GetSize(); ++i) {
696                                 PIPSocket::Address addr;
697                                 WORD port = 0;
698                                         
699                                 if (GetTransportAddress(tokens[i], GK_DEF_ENDPOINT_SIGNAL_PORT, addr, port)
700                                                 && addr.IsValid() && port != 0) {
701                                         Route route("SQL", addr, port);
702                                         route.m_destEndpoint = RegistrationTable::Instance()->FindBySignalAdr(
703                                                 SocketToH225TransportAddr(addr, port)
704                                                 );
705                                         authData.m_destinationRoutes.push_back(route);
706                                         PTRACE(5, traceStr << " - call redirected to the address " <<
707                                                 route.AsString()
708                                                 );
709                                 }
710                         }
711                 }
712         }
713
714         iter = FindField(result, "proxy");
715         if (iter != result.end()) {
716                 const PString &s = iter->first;
717                 if (!s) {
718                         authData.m_proxyMode = Toolkit::AsBool(s)
719                                 ? CallRec::ProxyEnabled : CallRec::ProxyDisabled;
720                         PTRACE(5, traceStr << " - proxy mode "
721                                 << (authData.m_proxyMode == CallRec::ProxyEnabled ? "enabled" : "disabled")
722                                 );
723                 }
724         }
725                         
726         return e_ok;
727 }
728
729 int SQLAuth::Check(
730         RasPDU<H225_LocationRequest>& lrqPdu,
731         unsigned& rejectReason
732         )
733 {
734         H225_LocationRequest &lrq = lrqPdu;
735         std::map<PString, PString> params;
736         
737         PIPSocket::Address addr = (lrqPdu.operator->())->m_peerAddr;
738
739         const PString traceStr = "SQLAUTH\t" + GetName() + "(LRQ from "
740                 + addr.AsString() + ")";
741         params["nbip"] = addr.AsString();
742         params["nbid"] = RasServer::Instance()->GetNeighbors()->GetNeighborIdBySigAdr(addr);
743         params["g"] = Toolkit::GKName();
744         
745         addr = (lrqPdu.operator->())->m_localAddr;
746         params["gkip"] = addr.AsString();
747
748         if (lrq.HasOptionalField(H225_LocationRequest::e_sourceInfo)) {
749                 params["Calling-Station-Id"] = GetBestAliasAddressString(lrq.m_sourceInfo,
750                         false, AliasAddressTagMask(H225_AliasAddress::e_dialedDigits)
751                                 | AliasAddressTagMask(H225_AliasAddress::e_partyNumber)
752                         );
753                 params["src-info"] = AsString(lrq.m_sourceInfo);
754         }
755         params["Called-Station-Id"] = GetBestAliasAddressString(lrq.m_destinationInfo,
756                 false, AliasAddressTagMask(H225_AliasAddress::e_dialedDigits)
757                         | AliasAddressTagMask(H225_AliasAddress::e_partyNumber)
758                 );
759         params["dest-info"] = AsString(lrq.m_destinationInfo);
760
761         if (lrq.HasOptionalField(H225_LocationRequest::e_bandWidth))
762                 params["bandwidth"] = PString(lrq.m_bandWidth.GetValue());
763
764         GkSQLResult::ResultRow result;  
765         if (!RunQuery(traceStr, m_sqlConn, m_nbQuery, params, result, -1)) {
766                 rejectReason = H225_LocationRejectReason::e_resourceUnavailable;
767                 return GetDefaultStatus();
768         }
769
770         if (!Toolkit::AsBool(result[0].first)) {
771                 rejectReason = H225_LocationRejectReason::e_securityDenial;
772                 return e_fail;
773         }
774
775         GkSQLResult::ResultRow::const_iterator iter = FindField(result, "destination");
776         if (iter != result.end()) {
777                 PStringArray aliases = iter->first.Tokenise(",");
778                 if (aliases.GetSize() > 0) {
779                         PINDEX i = 0;
780                         while (i < lrq.m_destinationInfo.GetSize()) {
781                                 PINDEX j = aliases.GetStringsIndex(AsString(lrq.m_destinationInfo[i], FALSE));
782                                 if( j == P_MAX_INDEX )
783                                         lrq.m_destinationInfo.RemoveAt(i);
784                                 else {
785                                         i++;
786                                         aliases.RemoveAt(j);
787                                 }
788                         }
789                 }
790                 for (PINDEX i = 0; i < aliases.GetSize(); i++) {
791                         const PINDEX sz = lrq.m_destinationInfo.GetSize();
792                         lrq.m_destinationInfo.SetSize(sz + 1);
793                         H323SetAliasAddress(aliases[i], lrq.m_destinationInfo[sz]);
794                 }
795         }
796                         
797         return e_ok;
798 }
799         
800 int SQLAuth::Check(
801         /// Q.931/H.225 Setup message to be authenticated
802         SetupMsg &setup,
803         /// authorization data (call duration limit, reject reason, ...)
804         SetupAuthData& authData
805         )
806 {
807         std::map<PString, PString> params;
808         
809         PIPSocket::Address addr;
810         setup.GetPeerAddr(addr);
811
812         const PString traceStr = "SQLAUTH\t" + GetName() + "(Setup from "
813                 + addr.AsString() + " CRV=" + PString(setup.GetQ931().GetCallReference())
814                 + ")";
815         params["callerip"] = addr.AsString();
816                 
817         // get the username for User-Name attribute             
818         params["u"] = GetUsername(setup, authData);
819         params["g"] = Toolkit::GKName();
820         
821         setup.GetLocalAddr(addr);
822         params["gkip"] = addr.AsString();
823
824         params["Calling-Station-Id"] = GetCallingStationId(setup, authData);
825         params["Called-Station-Id"] = GetCalledStationId(setup, authData);
826         params["Dialed-Number"] = GetDialedNumber(setup, authData);
827         params["answer"] = "0";
828         params["arq"] = "0";
829
830         if (authData.m_call)
831                 params["bandwidth"] = PString(authData.m_call->GetBandwidth());
832
833         GkSQLResult::ResultRow result;  
834         if (!RunQuery(traceStr, m_sqlConn, m_callQuery, params, result, -1)) {
835                 authData.m_rejectCause = Q931::TemporaryFailure;
836                 return GetDefaultStatus();
837         }
838
839         if (!Toolkit::AsBool(result[0].first)) {
840                 authData.m_rejectCause = Q931::CallRejected;
841                 return e_fail;
842         }
843
844         GkSQLResult::ResultRow::const_iterator iter = FindField(result, "credittime");
845         if (iter != result.end()) {
846                 const PString &s = iter->first;
847                 if (s.GetLength() > 0
848                         && strspn((const char*)s, "0123456789") == (size_t)s.GetLength()) {
849                         PUInt64 limit = s.AsUnsigned64();
850                         if (limit > PUInt64(std::numeric_limits<long>::max()))
851                                 authData.m_callDurationLimit = std::numeric_limits<long>::max();
852                         else
853                                 authData.m_callDurationLimit = static_cast<long>(limit);
854                         PTRACE(5, traceStr << " - duration limit set to "
855                                 << authData.m_callDurationLimit
856                                 );
857                         if (authData.m_callDurationLimit == 0) {
858                                 authData.m_rejectCause = Q931::CallRejected;
859                                 return e_fail;
860                         }
861                 }
862         }
863
864         iter = FindField(result, "redirectnumber");
865         if (iter != result.end()) {
866                 const PString &s = iter->first;
867                 if (!s) {
868                         authData.SetRouteToAlias(s);
869                         PTRACE(5, traceStr << " - call redirected to the number " << s);
870                 }
871         }
872                         
873         iter = FindField(result, "redirectip");
874         if (iter != result.end()) {
875                 const PString &s = iter->first;
876                 if (!s) {
877                         PStringArray tokens(s.Tokenise("; \t", FALSE));
878                         for (PINDEX i = 0; i < tokens.GetSize(); ++i) {
879                                 PIPSocket::Address addr;
880                                 WORD port = 0;
881                                         
882                                 if (GetTransportAddress(tokens[i], GK_DEF_ENDPOINT_SIGNAL_PORT, addr, port)
883                                                 && addr.IsValid() && port != 0) {
884                                         Route route("SQL", addr, port);
885                                         route.m_destEndpoint = RegistrationTable::Instance()->FindBySignalAdr(
886                                                 SocketToH225TransportAddr(addr, port)
887                                                 );
888                                         authData.m_destinationRoutes.push_back(route);
889                                         PTRACE(5, traceStr << " - call redirected to the address " <<
890                                                 route.AsString()
891                                                 );
892                                 }
893                         }
894                 }
895         }
896
897         iter = FindField(result, "proxy");
898         if (iter != result.end()) {
899                 const PString &s = iter->first;
900                 if (!s) {
901                         authData.m_proxyMode = Toolkit::AsBool(s)
902                                 ? CallRec::ProxyEnabled : CallRec::ProxyDisabled;
903                         PTRACE(5, traceStr << " - proxy mode "
904                                 << (authData.m_proxyMode == CallRec::ProxyEnabled ? "enabled" : "disabled")
905                                 );
906                 }
907         }
908                         
909         return e_ok;
910 }
911
912
913 namespace { // anonymous namespace
914         GkAuthCreator<SQLPasswordAuth> SQLPasswordAuthCreator("SQLPasswordAuth");
915         GkAuthCreator<SQLAliasAuth> SQLAliasAuthCreator("SQLAliasAuth");
916         GkAuthCreator<SQLAuth> SQLAuthCreator("SQLAuth");
917 } // end of anonymous namespace