Пример #1
0
void SignedUrl::sign( Url& urlToSign )
{
    UtlString existingUrlSignature;
    UtlString urlString;

    urlToSign.toString( urlString );
    if( urlToSign.getUrlParameter( SignatureUrlParamName, existingUrlSignature ) == TRUE )
    {
        OsSysLog::add(FAC_SIP, PRI_DEBUG,
                      "SignedUrl::sign URL '%s' already signed - updating signature",
                      urlString.data() );
    }
    UtlString userInfo;
    UtlString hostPort;
    UtlString strSignature;

    urlToSign.getUserId( userInfo );
    urlToSign.getHostWithPort( hostPort );

    computeSignature( userInfo, hostPort, strSignature );
    urlToSign.setUrlParameter( SignatureUrlParamName, strSignature.data() );

    OsSysLog::add(FAC_SIP, PRI_DEBUG,
                  "SignedUrl::sign URL signed: '%s' with signature '%s'",
                  urlString.data(), strSignature.data() );
}
Пример #2
0
UtlBoolean SignedUrl::isUrlSigned( Url& signedUrl )
{
    UtlBoolean bUrlProperlySigned;
    UtlString existingUrlSignature;
    UtlString urlString;

    signedUrl.toString( urlString );
    if( signedUrl.getUrlParameter( SignatureUrlParamName, existingUrlSignature ) == FALSE )
    {
        bUrlProperlySigned = FALSE;
        OsSysLog::add(FAC_SIP, PRI_DEBUG,
                      "SignedUrl::isUrlSigned URL '%s' not signed",
                      urlString.data() );
    }
    else
    {
        UtlString userInfo;
        UtlString hostPort;
        UtlString strReferenceSignature;

        signedUrl.getUserId( userInfo );
        signedUrl.getHostWithPort( hostPort );
        computeSignature( userInfo, hostPort, strReferenceSignature );

        if( strReferenceSignature.compareTo( existingUrlSignature ) == 0 )
        {
            bUrlProperlySigned = TRUE;
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SignedUrl::isUrlSigned URL '%s' is properly signed",
                          urlString.data() );
        }
        else
        {
            bUrlProperlySigned = FALSE;
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SignedUrl::isUrlSigned URL '%s' does not have a valid signature. "
                          "Expected signature: '%s'", urlString.data(), strReferenceSignature.data() );
        }
    }
    return bUrlProperlySigned;
}
AuthPlugin::AuthResult
MSFT_ExchangeTransferHack::authorizeAndModify(const UtlString& id,
                                              const Url&  requestUri,
                                              RouteState& routeState,
                                              const UtlString& method,
                                              AuthResult  priorResult,
                                              SipMessage& request,
                                              bool bSpiralingRequest,  
                                              UtlString&  reason
                                              )
{
   AuthResult result = CONTINUE; // we modify, but never make an authorization decision

   if (mUserAgentRegEx) // if not configured, do nothing
   {
      // get the call-id to use in logging
      UtlString callId;
      request.getCallIdField(&callId);

      /*
       * Note: a REFER from Exchange, with the bug we are hunting here, will always look like
       * it is tranferring to some foreign domain.  This will cause the TransferControl AuthPlugin
       * to ALLOW it.  If TransferControl starts challenging REFER from Exchange, that may mean
       * that MSFT has fixed the bug this plugin is meant to compensate for.
       */
      if (DENY != priorResult) // ignore anything some other plugin has already nixed
      {
         if (method.compareTo(SIP_REFER_METHOD) == 0) // we only care about REFER
         {
            UtlString userAgent;
            request.getUserAgentField( &userAgent );

            if (mUserAgentRegEx->Search(userAgent)) // does this look like Exchange?
            {
               UtlString targetStr;
               if (request.getReferToField(targetStr)) // get the address of the transfer target
               {
                  Url target(targetStr);
                  if (Url::SipUrlScheme == target.getScheme()) // target address parsed ok?
                  {
                     // check whether or not this is REFER with Replaces
                     UtlString targetDialog;
                     if (!target.getHeaderParameter(SIP_REPLACES_FIELD, targetDialog))
                     {
                        /*
                         * This is a REFER without Replaces from Exchange
                         * so check the domain parts of the two URIs to see if they match.
                         */

                        // Get the domain part of the transfer-target URI
                        UtlString targetDomain;
                        target.getHostWithPort(targetDomain);

                        // Get the domain part of the request URI
                        UtlString requestDomain;
                        requestUri.getHostWithPort(requestDomain);

                        if (targetDomain.compareTo(requestDomain, UtlString::ignoreCase) == 0)
                        {
                           // The domains are the same; this is the bug we're looking for...

                           UtlString correctDomain;
                           mpSipRouter->getDomain(correctDomain);
                           target.setHostAddress(correctDomain);
                           target.setHostPort(PORT_NONE);

                           UtlString modifiedTarget;
                           target.toString(modifiedTarget);
                           request.setReferToField(modifiedTarget.data());

                           Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                                         "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                                         "corrected transfer target domain in call '%s'\n"
                                         "changed '@%s' -> '@%s'",
                                         mInstanceName.data(), callId.data(),
                                         targetDomain.data(), correctDomain.data()
                                         );
                        }
                        else
                        {
                           // oh my god... did MSFT fix Exchange?
                           Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                                         "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                                         "request and target domain differ in '%s'; not modified",
                                         mInstanceName.data(), callId.data()
                                         );
                        }
                     }
                     else
                     {
                        // This is a REFER with Replaces from Exchange
                        // I don't expect this to happen, but if it does then don't mess with it.
                        Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                                      "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                                      "allowing REFER with Replaces in call '%s' to '%s'; no action",
                                      mInstanceName.data(), callId.data(), targetDialog.data()
                                      );
                     }
                  }
                  else
                  {
                     Os::Logger::instance().log(FAC_AUTH, PRI_WARNING,
                                   "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                                   "unrecognized refer target '%s' for call '%s'",
                                   mInstanceName.data(), targetStr.data(), callId.data()
                                   );
                  }
               }
               else
               {
                  // REFER without a Refer-To header... incorrect, but just ignore it.
                  Os::Logger::instance().log(FAC_AUTH, PRI_WARNING,
                                "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                                "REFER method without Refer-To in call '%s'",
                                mInstanceName.data(), callId.data()
                                );
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                             "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                             "User-Agent '%s' does not match recognizer in %s",
                             mInstanceName.data(), userAgent.data(), callId.data()
                             );
            }
         }
         else
         {
            // not a REFER - ignore it.
         }
      }
      else
      {
         // Some earlier plugin already decided on this - don't waste time figuring it out.
         Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "MSFT_ExchangeTransferHack[%s]::authorizeAndModify "
                       "prior authorization result %s for call %s",
                       mInstanceName.data(), AuthResultStr(priorResult), callId.data()
                       );
      }
   }
   return result;
}
Пример #4
0
AuthPlugin::AuthResult
CallerAlias::authorizeAndModify(const UtlString& id,    /**< The authenticated identity of the
                                                         *   request originator, if any (the null
                                                         *   string if not).
                                                         *   This is in the form of a SIP uri
                                                         *   identity value as used in the
                                                         *   credentials database (user@domain)
                                                         *   without the scheme or any parameters.
                                                         */
                                const Url&  requestUri, ///< parsed target Uri
                                RouteState& routeState, ///< the state for this request.  
                                const UtlString& method,///< the request method
                                AuthResult  priorResult,///< results from earlier plugins.
                                SipMessage& request,    ///< see AuthPlugin regarding modifying
                                bool bSpiralingRequest, ///< spiraling indication 
                                UtlString&  reason      ///< rejection reason
                                )
{
   // get the call-id to use in logging
   UtlString callId;
   request.getCallIdField(&callId);

   if (   (priorResult != DENY) // no point in modifying a request that won't be sent
       )   
   {
      UtlString callerFrom;
      UtlString callerFromTagOffsetStr;
      UtlString aliasFrom;
      UtlString aliasFromTagOffsetStr;
      UtlString originalFromTag;

      if (   !routeState.getParameter(mInstanceName.data(), CALLER_FROM_PARAM, callerFrom)
          || !routeState.getParameter(mInstanceName.data(), CALLER_TAG_OFFSET_PARAM, callerFromTagOffsetStr)
          || !routeState.getParameter(mInstanceName.data(), ALIAS_FROM_PARAM, aliasFrom)
          || !routeState.getParameter(mInstanceName.data(), ALIAS_TAG_OFFSET_PARAM, aliasFromTagOffsetStr)
          || !routeState.originalCallerFromTagValue(mInstanceName.data(), originalFromTag)
          )
      {
         if (   routeState.isMutable()
             && routeState.directionIsCallerToCalled(mInstanceName.data())
             ) // a new dialog?
         {
            /*
             * Get the callers identity by getting the caller URI and:
             *    remove all parameters
             *    remove the scheme name
             */
            UtlString callerIdentity;

            UtlString originalFromField;
            request.getFromField(&originalFromField);
            Url originalFromUrl(originalFromField);
            
            /*
             * Extract the from identity as a key for the caller alias table
             * Start with the From header field (someday we should use the Identity if present)
             */
            Url fromUrl(originalFromUrl);
            fromUrl.removeParameters(); // parameters are not relevant for this 
         
            Url::Scheme fromUrlScheme = fromUrl.getScheme();
            switch (fromUrlScheme)
            {
            case Url::SipsUrlScheme:
               // sips and sip are equivalent for identity purposes,
               //   so just set to sip 
               fromUrl.setScheme(Url::SipUrlScheme);
               //   and fall through to extract the identity...

            case Url::SipUrlScheme:
               // case Url::TelUrlScheme: will go here, since 'tel' and 'sip' are the same length
               fromUrl.getUri(callerIdentity);
               callerIdentity.remove(0,4 /* strlen("sip:") */); // strip off the scheme name
               break;

            default:
               // for all other schemes, treat identity as null
               Os::Logger::instance().log(FAC_SIP, PRI_WARNING,
                             "CallerAlias[%s]::check4andApplyAlias From uses unsupported scheme '%s'"
                             " - using null identity",
                             mInstanceName.data(),
                             Url::schemeName(fromUrlScheme)
                             );
               break;
            }

            /*
             * Determine whether the identity is one for which this proxy
             * is authoritative; if not, we will not use wildcard matches.
             */
            bool identityIsLocal = mpSipRouter->isLocalDomain(fromUrl);
            
            // now we have callerIdentity set; use for looking up each contact.
            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "CallerAlias[%s]::check4andApplyAlias "
                          "\n  caller '%s' %s",
                          mInstanceName.data(),
                          callerIdentity.data(),
                          identityIsLocal ? "is local" : "is not local"
                          );

            /*
             * Examine the request URI,
             * checking for a caller alias set for its domain(including asssociated gateway sipxecsLineid)  with callerIdentity
             */

            UtlString sipxecsLineIdField;
            requestUri.getUrlParameter(SIPX_SIPXECS_LINEID_URI_PARAM, sipxecsLineIdField);

            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "getUrlParameter: sipxecsLineid[%s]"
                             " in CallerAlias",
                             sipxecsLineIdField.data()
                             );

            UtlString targetDomain;
            requestUri.getHostWithPort(targetDomain);

            if (!(sipxecsLineIdField.isNull()))
            {
                targetDomain.append(";").append(SIPX_SIPXECS_LINEID_URI_PARAM).append("=").append(sipxecsLineIdField.data());
            }

            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "CallerAlias::targetDomain [%s]",
                          targetDomain.data()
                          );

            // look up any caller alias for this identity and contact domain
            UtlString callerAlias;
            if (identityIsLocal && getCallerAlias(callerIdentity, targetDomain, callerAlias) )
            {
               // found a caller alias, so rewrite the From information
               /*
                * The From header requires special handling
                * - we need to preserve the tag, if any, from the original header
                */
               originalFromUrl.getFieldParameter("tag", originalFromTag);

               Url newFromUrl(callerAlias.data());
               newFromUrl.removeFieldParameter("tag"); // specifying a tag is a no-no
               if ( !originalFromTag.isNull() )
               {
                  newFromUrl.setFieldParameter("tag", originalFromTag.data());
               }
               UtlString newFromFieldValue;
               newFromUrl.toString(newFromFieldValue);
                   
               // log the change we are making before stripping the tag from the field values
               Os::Logger::instance().log( FAC_SIP, PRI_INFO,
                             "CallerAlias[%s]::check4andApplyAlias call %s set caller alias\n"
                             "  Original-From: %s\n"
                             "  Aliased-From:  %s",
                             mInstanceName.data(), callId.data(),
                             originalFromField.data(),
                             newFromFieldValue.data()
                             );

               // rewrite the caller identity with the aliased value
               request.setRawFromField(newFromFieldValue.data());

               // Factor the tag values out of the field values stored in the RouteState
               //  We do this because otherwise we'll end up encoding and sending two copies
               //  of the tag; since some phones send really long tag values (no one knows why),
               //  this can cause such large Record-Route headers that they cause interop problems.
               if ( ! originalFromTag.isNull() )
               {
                  // find the offset of the tag value in the callers from field
                  ssize_t callerFromTagOffset;
                  callerFromTagOffset = originalFromField.index(originalFromTag);
                  callerFromTagOffsetStr.appendNumber(callerFromTagOffset);
                  // strip the tag value from the original From value to be stored in the RouteState
                  originalFromField.replace(callerFromTagOffset, originalFromTag.length(), "");
                  
                  // find the offset of the tag value in the aliased from field
                  ssize_t aliasFromTagOffset;
                  aliasFromTagOffset = newFromFieldValue.index(originalFromTag);
                  aliasFromTagOffsetStr.appendNumber(aliasFromTagOffset);
                  // strip the tag value from the aliased From value to be stored in the RouteState
                  newFromFieldValue.replace(aliasFromTagOffset, originalFromTag.length(), "");
               }

               // save the original and new values so that we can fix them later
               routeState.setParameter(mInstanceName.data(),
                                       CALLER_FROM_PARAM,originalFromField);
               routeState.setParameter(mInstanceName.data(),
                                       CALLER_TAG_OFFSET_PARAM,callerFromTagOffsetStr);
               routeState.setParameter(mInstanceName.data(),
                                       ALIAS_FROM_PARAM,newFromFieldValue);
               routeState.setParameter(mInstanceName.data(),
                                       ALIAS_TAG_OFFSET_PARAM,aliasFromTagOffsetStr);
            }
            else
            {
               Os::Logger::instance().log( FAC_SIP, PRI_DEBUG,
                             "CallerAlias[%s]::check4andApplyAlias call %s found no alias",
                             mInstanceName.data(), callId.data()
                             );
            }
         }
         else
         {
            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                          "CallerAlias[%s]::authorizeAndModify "
                          "not mutable - no rewrite",
                          mInstanceName.data()                          
                          );
         }
      }
      else // the callerFrom and aliasFrom parameters were found
      {
         /*
          * This request has had its From rewritten, so fix either the From
          * or the To depending on which direction this request is going.
          */
         if (!request.isResponse()) // can't modify responses, so don't bother
         {
            size_t tagOffset;
            
            if (routeState.directionIsCallerToCalled(mInstanceName.data()))
            {
               // replace the from tag value in the stored aliased header
               tagOffset = strtol(aliasFromTagOffsetStr.data(), NULL, 10);
               aliasFrom.insert(tagOffset, originalFromTag);

               // put the aliased header into the message
               request.setRawFromField(aliasFrom);
               Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "CallerAlias[%s]::authorizeAndModify "
                             "call %s reset From",
                             mInstanceName.data(), callId.data()
                             );
            }
            else // direction is Called to Caller
            {
               // replace the from tag value in the stored original header
               tagOffset = strtol(callerFromTagOffsetStr.data(), NULL, 10);
               callerFrom.insert(tagOffset, originalFromTag);

               request.setRawToField(callerFrom.data());
               Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "CallerAlias[%s]::authorizeAndModify "
                             "call %s reset To",
                             mInstanceName.data(), callId.data()
                             );
            }
         }
      }
   }
   return AuthPlugin::CONTINUE;
}