OsStatus SipRedirectorFallback::determineCallerLocationFromProvisionedUserLocation( const SipMessage& message, UtlString& callerLocation ) { OsStatus result = OS_FAILED; callerLocation.remove( 0 ); // First, determine the identity of the caller. This is done by looking for // a properly signed P-Asserted identity in the request message. // If the request contains a P-Asserted-Identity header and is not signed, // we will not trust it the returned location will be blank. UtlString matchedIdentityHeader; SipXauthIdentity sipxIdentity; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRedirectorFallback:: unbound entities allowing: %s", mAllowUnbound ? "TRUE" : "FALSE"); if (!mAllowUnbound) { SipXauthIdentity sipxIdentity( message, matchedIdentityHeader, false ); } else { SipXauthIdentity sipxIdentity( message, matchedIdentityHeader, false, SipXauthIdentity::allowUnbound); } if( !matchedIdentityHeader.isNull() ) { UtlString authenticatedUserIdentity; bool bRequestIsAuthenticated; bRequestIsAuthenticated = sipxIdentity.getIdentity( authenticatedUserIdentity ); if( bRequestIsAuthenticated ) { // we now have the autheticated identity of the caller. Look up the user location // database to find out the location that is mapped to it. //ResultSet userLocationsResult; // Check in User Location database if user has locations //mpUserLocationDbInstance->getLocations( authenticatedUserIdentity, userLocationsResult ); // Get the caller's site location. Only the first returned location is used. // This is not a problem given that a user should only belong to one location. EntityRecord entity; EntityDB* entityDb = SipRegistrar::getInstance(NULL)->getEntityDB(); if (entityDb->findByIdentity(authenticatedUserIdentity.str(), entity)) { callerLocation = entity.location().c_str(); result = OS_SUCCESS; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::determineCallerLocationFromProvisionedUserLocation mapped user '%s' taken from header '%s' to location '%s' based on its provisioned location", mLogName.data(), authenticatedUserIdentity.data(), authenticatedUserIdentity.data(), entity.location().c_str() ); } } } return result; }
void Notifier::sendNotifyForeachSubscription ( const char* key, const char* event, SipMessage& notify, const SipMessage* subscribe) { SubscribeDB::Subscriptions subscriptions; int timeNow = (int)OsDateTime::getSecsSinceEpoch(); // Get all subscriptions associated with this identity SubscribeDB::defaultCollection().collection().getUnexpiredSubscriptions( SUBSCRIPTION_COMPONENT_STATUS, key, event, timeNow, subscriptions ); // Add the static configured contacts. UtlString userUri(key); UtlString eventType(event); UtlString userContact; UtlString userFromUri; UtlString userToUri; UtlString userCallid; EntityRecord entity; if (EntityDB::defaultCollection().collection().findByIdentity(std::string(key), entity)) { std::vector<EntityRecord::StaticUserLoc> staticUserLoc = entity.staticUserLoc(); if (staticUserLoc.size() > 0) { //staticUserLoc[0].event.c_str(); userContact = staticUserLoc[0].contact.c_str(); userFromUri = staticUserLoc[0].fromUri.c_str(); userToUri = staticUserLoc[0].toUri.c_str(); userCallid = staticUserLoc[0].callId.c_str(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "Notifier::sendNotifyForeachSubscription configured contact %s", userUri.data()); int notifycseq = 0; userCallid.append("-"); userCallid.appendNumber((mpStaticSeq++ & 0xFFFF), "%04x"); UtlString id(""); UtlString subscriptionState("terminated"); UtlString recordroute(""); SendTheNotify(notify, mpSipUserAgent, userUri, userContact, userFromUri, userToUri, userCallid, notifycseq, eventType, id, subscriptionState, recordroute); } } int numSubscriptions = subscriptions.size(); if ( numSubscriptions > 0 ) { Os::Logger::instance().log( FAC_SIP, PRI_INFO, "Notifier::sendNotifyForeachSubscription: " " %d '%s' subscriptions for '%s'", numSubscriptions, event, key ); UtlString subscribeCallid; if ( subscribe ) { subscribe->getCallIdField(&subscribeCallid); Os::Logger::instance().log( FAC_SIP, PRI_INFO, "Notifier::sendNotifyForeachSubscription: " " notify only '%s'", subscribeCallid.data() ); } // There may be any number of subscriptions // for the same identity and event type! // send a notify to each for (SubscribeDB::Subscriptions::iterator iter = subscriptions.begin(); iter != subscriptions.end(); iter++ ) { Subscription& record = *iter; UtlString uri = record.uri().c_str(); UtlString callid = record.callId().c_str(); UtlString contact = record.contact().c_str(); int expires = record.expires(); UtlString eventtype = record.eventType().c_str(); UtlString id = record.id().c_str(); UtlString to = record.toUri().c_str(); UtlString from = record.fromUri().c_str(); if ( subscribe && subscribeCallid != callid ) { Os::Logger::instance().log( FAC_SIP, PRI_DEBUG, "Notifier::sendNotifyForeachSubscription: " " skipping '%s'; notify only '%s'", callid.data(), subscribeCallid.data() ); continue; } UtlString key = record.key().c_str(); UtlString recordroute= record.recordRoute().c_str(); int notifycseq = record.notifyCseq(); // the recordRoute column in the database is optional // and can be set to null, the IMDB does not support null columns // so look to see if the field is set to "%" a special single character // reserved value we use to null columns in the IMDB if ( record.recordRoute().empty() ) { recordroute.remove(0); } UtlString subscriptionState; int requestedExpires = -1; if ( subscribe ) { subscribe->getExpiresField(&requestedExpires); } if ( requestedExpires == 0 ) { subscriptionState = SIP_SUBSCRIPTION_TERMINATED; // the subscription should be removed from the database after this NOTIFY is sent } else { subscriptionState = SIP_SUBSCRIPTION_ACTIVE ";expires="; char expStr[10]; sprintf(expStr, "%d", expires); subscriptionState.append(expStr); } // increment the outbound cseq sent with the notify // this will guarantee that duplicate messages are rejected notifycseq += 1; SendTheNotify(notify, mpSipUserAgent, uri, contact, to, from, callid, notifycseq, eventtype, id, subscriptionState, recordroute); // Update the Notify sequence number (CSeq) in the IMDB // (We must supply a dummy XML version number.) SubscribeDB::defaultCollection().collection().updateNotifyUnexpiredSubscription ( SUBSCRIPTION_COMPONENT_STATUS, to, from, callid, eventtype, id, timeNow, notifycseq, 0 ); } } else { Os::Logger::instance().log( FAC_SIP, PRI_INFO, "Notifier::sendNotifyForeachSubscription: " " no '%s' subscriptions for '%s'", event, key ); } }
RedirectPlugin::LookUpStatus SipRedirectorRegDB::lookUp( const SipMessage& message, const UtlString& requestString, const Url& requestUri, const UtlString& method, ContactList& contactList, RequestSeqNo requestSeqNo, int redirectorNo, SipRedirectorPrivateStorage*& privateStorage, ErrorDescriptor& errorDescriptor) { unsigned long timeNow = OsDateTime::getSecsSinceEpoch(); // Local copy of requestUri Url requestUriCopy = requestUri; // Look for any grid parameter and remove it. UtlString gridParameter; UtlBoolean gridPresent = requestUriCopy.getUrlParameter("grid", gridParameter, 0); if (gridPresent) { requestUriCopy.removeUrlParameter("grid"); } if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG)) { UtlString temp; requestUriCopy.getUri(temp); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp gridPresent = %d, gridParameter = '%s', " "requestUriCopy after removing grid = '%s'", mLogName.data(), gridPresent, gridParameter.data(), temp.data()); } RegDB::Bindings registrations; // Give the ~~in~ URIs separate processing. UtlString user; requestUriCopy.getUserId(user); if (user.index(URI_IN_PREFIX) == 0) { // This is a ~~in~ URI. // Check for an '&' separator. ssize_t s = user.last('&'); if (s != UTL_NOT_FOUND) { // This is a ~~in~[user]&[instrument] URI. const char* instrumentp = user.data() + s + 1; UtlString u; u.append(user, sizeof (URI_IN_PREFIX) - 1, s - (sizeof (URI_IN_PREFIX) - 1)); requestUriCopy.setUserId(u); //regDB-> // getUnexpiredContactsUserInstrument(requestUriCopy, instrumentp, timeNow, registrations); UtlString identity; requestUriCopy.getIdentity(identity); _dataStore.regDB().getUnexpiredContactsUserInstrument(identity.str(), instrumentp, timeNow, registrations); } else { // This is a ~~in~[instrument] URI. const char* instrumentp = user.data() + sizeof (URI_IN_PREFIX) - 1; _dataStore.regDB().getUnexpiredContactsInstrument(instrumentp, timeNow, registrations); } } else { // Note that getUnexpiredContactsUser will reduce the requestUri to its // identity (user/host/port) part before searching in the // database. The requestUri identity is matched against the // "identity" column of the database, which is the identity part of // the "uri" column which is stored in registration.xml. UtlString identity; requestUriCopy.getIdentity(identity); _dataStore.regDB().getUnexpiredContactsUser(identity.str(), timeNow, registrations); } int numUnexpiredContacts = registrations.size(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp got %d unexpired contacts", mLogName.data(), numUnexpiredContacts); // Check for a per-user call forward timer. // Don't set timer if we're not going to forward to voicemail. std::ostringstream userCfwdTimer; bool foundUserCfwdTimer = false; if (method.compareTo(SIP_INVITE_METHOD) == 0) { UtlString noRoute; requestUriCopy.getUrlParameter("sipx-noroute", noRoute); if ((!noRoute.isNull()) && (noRoute.compareTo("Voicemail") == 0)) { // This is not a call scenerio controlled by this users "forward to voicemail" timer } else { UtlString identity; requestUriCopy.getIdentity(identity); EntityRecord entity; foundUserCfwdTimer = _dataStore.entityDB().findByIdentity(identity.str(), entity); if (foundUserCfwdTimer) userCfwdTimer << entity.callForwardTime(); } } for (RegDB::Bindings::const_iterator iter = registrations.begin(); iter != registrations.end(); iter++) { // Query the Registration DB for the contact, expires and qvalue columns. Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp contact = '%s', qvalue = '%s', path = '%s'", mLogName.data(), iter->getContact().c_str(), iter->getQvalue().c_str(), iter->getPath().c_str() ); Url contactUri(iter->getContact().c_str()); // If available set the per-user call forward timer. if (foundUserCfwdTimer) { contactUri.setHeaderParameter("expires", userCfwdTimer.str().c_str()); } // If the contact URI is the same as the request URI, ignore it. if (!contactUri.isUserHostPortEqual(requestUriCopy)) { // Check if the q-value from the database is valid, and if so, // add it into contactUri. if (!iter->getQvalue().empty()) { // :TODO: (XPL-3) need a RegEx copy constructor here // Check if q value is numeric and between the range 0.0 and 1.0. static RegEx qValueValid("^(0(\\.\\d{0,3})?|1(\\.0{0,3})?)$"); if (qValueValid.Search(iter->getQvalue().c_str())) { contactUri.setFieldParameter(SIP_Q_FIELD, iter->getQvalue().c_str()); } } // Re-apply any grid parameter. if (gridPresent) { contactUri.setUrlParameter("grid", gridParameter); } contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, "INT"); // Check if database contained a Path value. If so, add a Route // header parameter to the contact with the Path vector taken from // the registration data. if (!iter->getPath().empty()) { UtlString existingRouteValue; std::string pathVector = iter->getPath(); if ( contactUri.getHeaderParameter(SIP_ROUTE_FIELD, existingRouteValue)) { // there is already a Route header parameter in the contact; append it to the // Route derived from the Path vector. pathVector += SIP_MULTIFIELD_SEPARATOR; pathVector += existingRouteValue.str(); } contactUri.setHeaderParameter(SIP_ROUTE_FIELD, pathVector.c_str()); } // Add the contact. contactList.add( contactUri, *this ); } } return RedirectPlugin::SUCCESS; }
bool CallerAlias::getCallerAlias ( const UtlString& identity, const UtlString& domain, UtlString& callerAlias_ ) const { if (!_pEntities) return false; EntityRecord userEntity; EntityRecord gatewayEntity; bool hasUserEntity = false; bool hasGatewayEntity = false; std::string callerAlias; OS_LOG_INFO(FAC_SIP, "CallerAlias::getCallerAlias - EntityDB::findByIdentity for identity=" << identity.str() << " domain=" << domain.str()); hasUserEntity = _pEntities->collection().findByIdentity(identity.str(), userEntity); hasGatewayEntity = _pEntities->collection().findByIdentity(domain.str(), gatewayEntity); if (hasGatewayEntity && gatewayEntity.callerId().transformExtension) { size_t loc = identity.str().find("@"); if (loc != std::string::npos) { std::string userId = identity.str().substr(0, loc); // // Check if we need to truncate the userId to a certain length // if (gatewayEntity.callerId().extensionLength > 0 && userId.length() > (size_t)gatewayEntity.callerId().extensionLength) userId = string_right(userId, gatewayEntity.callerId().extensionLength); // // Now check if a prefix is specified // if (!gatewayEntity.callerId().extensionPrefix.empty()) { std::string buff = gatewayEntity.callerId().extensionPrefix; buff += userId; userId = userId = buff; } callerAlias = "<sip:"; callerAlias += userId; callerAlias += identity.str().substr(loc); callerAlias += ">"; } } else { if (hasUserEntity && !userEntity.callerId().id.empty()) callerAlias = userEntity.callerId().id; else if (hasGatewayEntity) gatewayEntity.callerId().ignoreUserCalleId = true; if (hasGatewayEntity && gatewayEntity.callerId().ignoreUserCalleId) { if (gatewayEntity.callerId().enforcePrivacy) { callerAlias = "sip:[email protected]"; } else if (!gatewayEntity.callerId().id.empty()) { callerAlias = gatewayEntity.callerId().id; } } } if (!callerAlias.empty()) callerAlias_ = callerAlias.c_str(); else OS_LOG_WARNING(FAC_SIP, "CallerAlias::getCallerAlias - No caller alias configured for identity=" << identity.str() << " domain=" << domain.str()); return !callerAlias.empty(); }
RedirectPlugin::LookUpStatus SipRedirectorMapping::lookUp( const SipMessage& message, const UtlString& requestString, const Url& requestUri, const UtlString& method, ContactList& contactList, RequestSeqNo requestSeqNo, int redirectorNo, SipRedirectorPrivateStorage*& privateStorage, ErrorDescriptor& errorDescriptor) { UtlString callTag = "UNK"; UtlString permissionName; ResultSet urlMappingRegistrations; ResultSet urlMappingPermissions; // @JC This variable is strangely overloaded // If we have no permissions then add any encountered // contacts. If we do have permissions then the // permission must match UtlBoolean permissionFound = TRUE; if (mMappingRulesLoaded == OS_SUCCESS) { mMap.getContactList( requestUri, urlMappingRegistrations, urlMappingPermissions, callTag); } int numUrlMappingPermissions = urlMappingPermissions.getSize(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp " "got %d UrlMapping Permission requirements for %d contacts", mLogName.data(), numUrlMappingPermissions, urlMappingRegistrations.getSize()); if (numUrlMappingPermissions > 0) { // check if we have field parameter that indicates that some permissions should be ignored UtlString ignorePermissionStr; // :KLUDGE: remove const_cast and uri declaration after XSL-88 gets fixed Url& uri = const_cast<Url&>(requestUri); uri.getUrlParameter("sipx-noroute", ignorePermissionStr); EntityRecord entity; std::set<std::string> permissions; if (_dataStore.entityDB().findByIdentityOrAlias(requestUri, entity)) permissions = entity.permissions(); size_t numDBPermissions = permissions.size(); for (int i = 0; i<numUrlMappingPermissions; i++) { UtlHashMap record; urlMappingPermissions.getIndex(i, record); UtlString permissionKey("permission"); UtlString urlMappingPermissionStr = *((UtlString*) record.findValue(&permissionKey)); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp checking permissions DB for " "urlMappingPermissions[%d] = '%s'", mLogName.data(), i, urlMappingPermissionStr.data()); // Try to match the permission // so assume it cannot be found unless we // see a match in the IMDB permissionFound = FALSE; // if the permission we are looking for is the one the we are supposed to ignore, // than assume that permission is not found if (urlMappingPermissionStr.compareTo(ignorePermissionStr, UtlString::ignoreCase) == 0) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp ignoring permission '%s'", mLogName.data(), ignorePermissionStr.data()); continue; } UtlString permissionsFound; for (std::set<std::string>::const_iterator iter = permissions.begin(); iter != permissions.end(); iter++) { UtlString dbPermissionStr = iter->c_str(); bool equal = dbPermissionStr.compareTo(urlMappingPermissionStr, UtlString::ignoreCase) == 0; if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG)) { permissionsFound.append(" "); permissionsFound.append(dbPermissionStr); if (equal) { permissionsFound.append("[matches]"); } } if (equal) { // matching permission found in IMDB permissionFound = TRUE; break; } dbPermissionStr.remove(0); } Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp %d permissions configured for request URI '%s'. Checking: %s", mLogName.data(), numDBPermissions, requestUri.toString().data(), permissionsFound.data()); if (permissionFound) { break; } urlMappingPermissionStr.remove(0); } } // either there were no requirements to match against voicemail // or there were and we found a match in the IMDB for the URI // so now add the contacts to the SIP message if (permissionFound) { int numUrlMappingRegistrations = urlMappingRegistrations.getSize(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp got %d UrlMapping Contacts", mLogName.data(), numUrlMappingRegistrations); if (numUrlMappingRegistrations > 0) { for (int i = 0; i < numUrlMappingRegistrations; i++) { UtlHashMap record; urlMappingRegistrations.getIndex(i, record); UtlString contactKey("contact"); UtlString contact= *(dynamic_cast <UtlString*> (record.findValue(&contactKey))); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp contact = '%s'", mLogName.data(), contact.data()); Url contactUri(contact); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp contactUri = '%s'", mLogName.data(), contactUri.toString().data()); // We no longer check for recursive loops here because we // have comprehensive loop detection in the proxy. UtlString recordRoute; UtlString curCallDest; if (message.getRecordRouteField(0,&recordRoute)) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp RecordRouteField = '%s'", mLogName.data(), recordRoute.data()); } contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, callTag.data()); // Add the contact. contactList.add( contactUri, *this ); } } } return RedirectPlugin::SUCCESS; }
UtlBoolean SubscribeServerThread::isAuthorized ( const SipMessage* message, SipMessage *responseMessage, StatusPluginReference* pluginContainer) { UtlBoolean retIsAuthorized = FALSE; UtlString requestUser; Url identityUrl; message->getUri(NULL, NULL, NULL, &requestUser); identityUrl.setUserId(requestUser); identityUrl.setHostAddress(mDefaultDomain); EntityDB* entityDb = StatusServer::getInstance()->getEntityDb(); if( pluginContainer ) { // if the plugin has permissions, we must match all these against the IMDB if( pluginContainer->hasPermissions() ) { // permission required. Check for required permission in permission IMDB // All required permissions should match EntityRecord entity; entityDb->findByIdentity(identityUrl, entity); std::set<std::string> permissions = entity.permissions(); int numDBPermissions = permissions.size(); if( numDBPermissions > 0 ) { UtlBoolean nextPermissionMatched = TRUE; UtlSListIterator* pluginPermissionIterator = pluginContainer->permissionsIterator(); UtlString* pluginPermission; // Iterated through the plugin permissions matching // them one by one against the IMDB while( (pluginPermission = (UtlString*)(*pluginPermissionIterator)()) && nextPermissionMatched ) { //check againt all permissions in IMDB nextPermissionMatched = FALSE; UtlString identity, permission; for ( std::set<std::string>::iterator iter = permissions.begin(); iter != permissions.end(); iter++ ) { permission = iter->c_str(); if (pluginPermission->compareTo(permission, UtlString::ignoreCase ) == 0) { nextPermissionMatched = TRUE; break; } } } delete pluginPermissionIterator; // after going thru all permissions find out if all matched or not if( nextPermissionMatched ) { Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -" " All permissions matched - request is AUTHORIZED"); retIsAuthorized = TRUE; } else { Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -" " One or more Permissions did not match - request is UNAUTHORIZED"); retIsAuthorized = FALSE; } } else { // one or more permissions needed by plugin and none in IMDB => UNAUTHORIZED Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -" " No Permissions in IMDB - request is UNAUTHORIZED"); retIsAuthorized = FALSE; } } else { Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthorized() -" " No Permissions required - request is always AUTHORIZED"); retIsAuthorized = TRUE; } } //set the error response message id unauthorized if(!retIsAuthorized) { responseMessage->setResponseData(message,SIP_FORBIDDEN_CODE, SIP_FORBIDDEN_TEXT); } return retIsAuthorized; }