H350 Module
     __________________________________________________________

   Table of Contents

   1. Admin Guide

        1.1. Overview

              1.1.1. Example H.350 commObject LDAP Entry

        1.2. Dependencies

              1.2.1. OpenSIPS Modules
              1.2.2. External Libraries or Applications

        1.3. Exported Parameters

              1.3.1. ldap_session (string)
              1.3.2. base_dn (string)
              1.3.3. search_scope (string)

        1.4. Exported Functions

              1.4.1. h350_sipuri_lookup(sip_uri)
              1.4.2. h350_auth_lookup(auth_username,
                      "username_avp_spec/pwd_avp_spec")

              1.4.3. h350_result_call_preferences(avp_name_prefix)
              1.4.4. h350_result_service_level(avp_name_prefix)

   Resources
   2. Contributors

        2.1. By Commit Statistics
        2.2. By Commit Activity

   3. Documentation

        3.1. Contributors

   List of Tables

   2.1. Top contributors by DevScore^(1), authored commits^(2) and
          lines added/removed^(3)

   2.2. Most recently active contributors^(1) to this module

   List of Examples

   1.1. Example H.350 commObject storing SIP account data
   1.2. ldap_session parameter usage
   1.3. base_dn parameter usage
   1.4. search_scope parameter usage
   1.5. Example Usage
   1.6. Example Usage
   1.7. Example H.350 callPreferenceURI simple call forwarding
          rules

   1.8. Example Usage
   1.9. Example SIPIdentityServiceLevel values and resulting AVPs
   1.10. Example Usage

Chapter 1. Admin Guide

1.1. Overview

   The OpenSIPS H350 module enables an OpenSIPS SIP proxy server
   to access SIP account data stored in an LDAP [RFC4510]
   directory containing H.350 [H.350] commObjects. ITU-T
   Recommendation H.350 standardizes LDAP object classes to store
   Real-Time Communication (RTC) account data. In particular,
   H.350.4 [H.350.4] defines an object class called sipIdentity
   that includes attribute specifications for SIP account data
   like SIP URI, SIP digest username/password, or service level.
   This allows to store SIP account data in a vendor neutral way
   and lets different entities, like SIP proxies, provisioning, or
   billing applications, access the data in a standardized format.

   The ViDe H.350 Cookbook [vide-h.350-cb] is a good reference for
   deploying an H.350 directory. Besides general information on
   H.350, LDAP, and related standards, this document explains how
   to set up an H.350/LDAP directory and discusses different
   deployment scenarios.

   The H350 module uses the OpenSIPS LDAP module to import H.350
   attribute values into the OpenSIPS routing script variable
   space. The module exports functions to parse and store the
   H.350 attribute values from the OpenSIPS routing script. It
   allows a script writer to implement H.350 based SIP digest
   authentication, call forwarding, SIP URI alias to AOR
   rewriting, and service level parsing.

1.1.1. Example H.350 commObject LDAP Entry

   The following example shows a typical H.350 commObject LDAP
   entry storing SIP account data.

   Example 1.1. Example H.350 commObject storing SIP account data
Attribute Name                Attribute Value(s)
--------------                -----------------

# LDAP URI identifying the owner of this commObject, typically
# points to an entry in the enterprise directory
commOwner       ldap://dir.example.com/dc=example,dc=com??one?(uid=bob)

# Unique identifier for this commObject, used for referencing
# this object e.g. from the enterprise directory
commUniqueId                  298217asdjgj213

# Determines if this commObject should be listed on white pages
commPrivate                   false

# Valid SIP URIs for this account (can be used to store alias SIP URIs
# like DIDs as well)
SIPIdentitySIPURI             sip:bob@example.com
                              sip:bob@alias.example.com
                              sip:+1919123456@alias.example.com
# SIP digest username
SIPIdentityUserName           bob

# SIP digest password
SIPIdentityPassword           pwd

# SIP proxy address
SIPIdentityProxyAddress       sip.example.com

# SIP registrar address
SIPIdentityRegistrarAddress   sip.example.com

# Call preferences: Forward to voicemail on no response
# after 20 seconds and on busy
callPreferenceURI             sip:bob@voicemail.example.com n:20000
                              sip:bob@voicemail.example.com b

# Account service level(s)
SIPIdentityServiceLevel       long_distance
                              conferencing

# H.350 object classes
objectClass                   top
                              commObject
                              SIPIdentity
                              callPreferenceURIObject

1.2. Dependencies

1.2.1. OpenSIPS Modules

   The module depends on the following modules (the listed modules
   must be loaded before this module):
     * LDAP

1.2.2. External Libraries or Applications

   The following libraries or applications must be installed
   before running OpenSIPS with this module loaded:
     * OpenLDAP library (libldap), libldap header files
       (libldap-dev) are needed for compilation

1.3. Exported Parameters

1.3.1. ldap_session (string)

   Name of the LDAP session to be used for H.350 queries, as
   defined in the LDAP module configuration file.

   Default value: ""

   Example 1.2. ldap_session parameter usage
modparam("h350", "ldap_session", "h350");

1.3.2. base_dn (string)

   Base LDAP DN to start LDAP search for H.350 entries. For best
   performance, this should be set to the direct ancestor of the
   H.350 objects.

   Default value: ""

   Example 1.3. base_dn parameter usage
modparam("h350", "base_dn", "ou=h350,dc=example,dc=com");

1.3.3. search_scope (string)

   LDAP search scope for H.350 queries, one of "one", "base", or
   "sub".

   Default value: "one"

   Example 1.4. search_scope parameter usage
modparam("h350", "search_scope", "sub");

1.4. Exported Functions

1.4.1. h350_sipuri_lookup(sip_uri)

   This function performs an LDAP search query for an H.350
   commObject with a SIPIdentitySIPURI of sip_uri. The sip_uri
   parameter first gets escaped according the rules for LDAP
   filter strings. The result of the LDAP search is stored
   internally and can be accessed either by one of the
   h350_result* or one of the ldap_result* functions from the
   OpenSIPS LDAP module.

   The function returns -1 (FALSE) for internal errors, and -2
   (FALSE) if no H.350 commObject was found with a matching
   sip_uri. n > 0 (TRUE) is returned if n H.350 commObjects were
   found.

   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
   FAILURE_ROUTE and BRANCH_ROUTE.

   Function Parameters:

   sip_uri (string)
          H.350 SIPIdentitySIPURI to search for in directory.

   Return Values:

   n > 0 (TRUE):

          + n H.350 commObjects found.

   -1 (FALSE):

          + Internal error occurred.

   -2 (FALSE):

          + No H.350 commObject found.

   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
   BRANCH_ROUTE, and ONREPLY_ROUTE.

   Example 1.5. Example Usage
#
# H.350 lookup for callee
#

if (!h350_sipuri_lookup("sip:$rU@$rd"))
{
    switch ($retcode)
    {
    case -2:
        xlog("L_INFO",
             "h350 callee lookup: no entry found in H.350 directory");
        exit;
    case -1:
        sl_send_reply(500, "Internal server error");
        exit;
    }
}

# now h350_result* or ldap_result* functions can be used

1.4.2. h350_auth_lookup(auth_username,
"username_avp_spec/pwd_avp_spec")

   This function performs an LDAP search query for SIP digest
   authentication credentials in an H.350 directory. The H.350
   directory is searched for a commObject with SIPIdentityUserName
   of auth_username. If such a commObject is found, the SIP digest
   authentication username and password are stored in AVPs
   username_avp_spec and pwd_avp_spec, respectively.
   pv_*_authorize functions from AUTH module can then be used to
   perform SIP digest authentication.

   The function returns 1 (TRUE) if an H.350 commObject was found,
   -1 (FALSE) in case of an internal error, and -2 (FALSE) if no
   matching commObject was found.

   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
   FAILURE_ROUTE and BRANCH_ROUTE.

   Function Parameters:

   auth_username (string)
          H.350 SIPIdentityUserName to search for in directory.

   username_avp_spec (var)
          Specification for authentication username AVP, e.g.
          $avp(username).

   pwd_avp_spec (var)
          Specification for authentication password AVP, e.g.
          $avp(pwd).

   Return Values:

   1 (TRUE):

          + H.350 commObject found and SIP digest authentication
            credentials stored in username_avp_spec and
            pwd_avp_spec.

   -1 (FALSE):

          + Internal error occurred.

   -2 (FALSE):

          + No H.350 commObject found.

   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
   BRANCH_ROUTE, and ONREPLY_ROUTE.

   Example 1.6. Example Usage
# -- auth params --
modparam("auth", "username_spec", "$avp(auth_user)")
modparam("auth", "password_spec", "$avp(auth_pwd)")
modparam("auth", "calculate_ha1", 1)

# -- h350 params --
modparam("h350", "ldap_session", "h350")
modparam("h350", "base_dn", "ou=h350,dc=example,dc=com")
modparam("h350", "search_scope", "one")


route[1]
{
    #
    # H.350 based SIP digest authentication
    #

    # challenge all requests not including an Auth header
    if (!(is_present_hf("Authorization") ||
          is_present_hf("Proxy-Authorization")))
    {
        if (is_method("REGISTER"))
        {
            www_challenge("example.com", 0);
            exit;
        }
        proxy_challenge("example.com", 0);
        exit;
    }

    # get digest password from H.350 using auth username ($au)
    if (!h350_auth_lookup($au,
                          "$avp(auth_user)/$avp(auth_pwd)"))
    {
        switch ($retcode)
        {
        case -2:
            sl_send_reply(401, "Unauthorized");
            exit;
        case -1:
            sl_send_reply(500, "Internal server error");
            exit;
        }
    }

    # REGISTER requests
    if (is_method("REGISTER"))
    {
        if (!pv_www_authorize("example.com"))
        {
            if ($retcode == -5)
            {
                sl_send_reply(500, "Internal server error");
                exit;
            }
            else {
                www_challenge("example.com", 0);
                exit;
            }
        }

        consume_credentials();
        xlog("L_INFO",
             "REGISTER request successfully authenticated");
        return(1);
    }

    # non-REGISTER requests
    if (!pv_proxy_authorize("example.com"))
    {
        if ($retcode == -5)
        {
            sl_send_reply(500, "Internal server error");
            exit;
        }
        else {
            proxy_challenge("example.com", 0);
            exit;
        }
    }

    consume_credentials();
    xlog("L_INFO", "$rm request successfully authenticated");
    return(1);
}

1.4.3. h350_result_call_preferences(avp_name_prefix)

   This function parses the callPreferenceURI attribute of an
   H.350 commObject, which must have been fetched through
   h350_*_lookup or ldap_search. callPreferenceURI is a
   multi-valued attribute that stores call preference rules like
   e.g. forward-on-busy or forward-unconditionally. Directory
   services architecture for call forwarding and preferences
   [H.350.6] defines a format for simple call forwarding rules:

     target_uri type[:argument]

   In a SIP environment, target_uri is typically the call
   forwarding rule's target SIP URI, although it could be any type
   of URI, e.g. an HTTP pointer to a CPL script. Four different
   values are specified for type: b for "forward on busy", n for
   "forward on no answer", u for "forward unconditionally", and f
   for "forward on destination not found". The optional argument
   is a string indicating the time in milliseconds after which the
   call forwarding should occur.

   Example 1.7. Example H.350 callPreferenceURI simple call
   forwarding rules

# Example 1:
# forward to sip:voicemail@example.com on no answer after 15 seconds:

callPreferenceURI: sip:voicemail@example.com n:15000

# Example 2:
# unconditionally forward to sip:alice@example.com:

callPreferenceURI: sip:alice@example.com u

# Example 3:
# forward to sip:bob@example.com and sip:alice@example.com
# (forking) on destination not found:

callPreferenceURI: sip:bob@example.com f
callPreferenceURI: sip:alice@example.com f

   h350_result_call_preferences stores these call forwarding rules
   as AVPs according to the following rules:

#
# AVP storing a forwarding rule's target URI
#

AVP name  = avp_name_prefix + '_' + type
AVP value = target_uri

#
# AVP storing a forwarding rule's argument
#

AVP name  = avp_name_prefix + '_' + type + '_t'
AVP value = argument / 1000

   Example 1 from above would result in two AVPs: $avp("prefix_n")
   = "sip:voicemail@example.com" and $avp("prefix_n_t") = 15.

   Example 2: $avp("prefix_u") = "sip:alice@example.com".

   Example 3: $avp("prefix_f[1]") = "sip:bob@example.com" and
   $avp("prefix_f[2]]") = "sip:alice@example.com".

   These AVPs can then be used to implement the desired behavior
   in the OpenSIPS routing script.

   This function returns the number of successfully parsed simple
   call forwarding rules (TRUE), in case the H.350
   callPreferenceURI attribute contained one or multiple values
   matching the simple call forwarding rule syntax described
   above. It returns -1 (FALSE) for internal errors, and -2
   (FALSE) if none of the rules matched or if no callPreferenceURI
   attribute was found.

   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
   FAILURE_ROUTE and BRANCH_ROUTE.

   Function Parameters:

   avp_name_prefix (string)
          Name prefix for call forwarding rule AVPs, as described
          above.

   Return Values:

   n > 0 (TRUE):

          + n simple call forwarding rules found.

   -1 (FALSE):

          + Internal error occurred.

   -2 (FALSE):

          + No simple call forwarding rule found, or
            callPreferenceURI not present.

   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
   BRANCH_ROUTE, and ONREPLY_ROUTE.

   Example 1.8. Example Usage
#
# H.350 lookup for callee
#

... h350_sipuri_lookup("sip:$rU@$rd") ...

#
# store H.350 call preferences in AVP
#

if (!h350_result_call_preferences("callee_pref_") && ($retcode == -1))
{
    sl_send_reply(500, "Internal server error");
    exit;
}

# $avp(callee_pref_u)   == CFU URI(s)
# $avp(callee_pref_n)   == CFNR URI(s)
# $avp(callee_pref_n_t) == CFNR timeout in seconds
# $avp(callee_pref_b)   == CFB URI(s)
# $avp(callee_pref_f)   == CFOFFLINE URI(s)

#
# Example for forward-unconditionally (CFU)
#

if (is_avp_set("$avp(callee_pref_u)"))
{
    # replace R-URI with CFU URI, g will fetch all CFU URIs
    # --> request can fork
    if (avp_pushto("$ru", "$avp(callee_pref_u)/g"))
    {
            avp_delete("$avp(callee_pref_u)");
    } else
    {
            sl_send_reply(500, "Internal server error");
            exit;
    }
    sl_send_reply(181, "Call is being forwarded");
    t_relay();
    exit;
}

1.4.4. h350_result_service_level(avp_name_prefix)

   Directory services architecture for SIP [H.350.4] defines a
   multi-valued LDAP attribute named SIPIdentityServiceLevel,
   which can be used to store SIP account service level values in
   an LDAP directory. This function parses the
   SIPIdentityServiceLevel attribute and stores all service level
   values as AVPs for later retrieval in the OpenSIPS routing
   script. The function accesses the H.350 commObject fetched by a
   call to h350_*_lookup or ldap_search.

   The resulting AVPs have a name of the form avp_name_prefix +
   SIPIdentityServiceLevel attribute value, and an integer value
   of 1.

   Example 1.9. Example SIPIdentityServiceLevel values and
   resulting AVPs
SIPIdentityServiceLevel: longdistance
SIPIdentityServiceLevel: international
SIPIdentityServiceLevel: 900

after calling h350_result_service_level("sl_"), the following AVPs
will be available in the routing script:

$avp("sl_longdistance") = 1
$avp("sl_international") = 1
$avp("sl_900") = 1

   This function returns the number of added AVPs (TRUE), -1
   (FALSE)for internal errors, and -2 (FALSE)if no
   SIPIdentityServiceLevel attribute was found.

   The function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
   FAILURE_ROUTE and BRANCH_ROUTE.

   Function Parameters:

   avp_name_prefix (string)
          Name prefix for service level AVPs, as described above.

   Return Values:

   n > 0 (TRUE):

          + n AVPs added.

   -1 (FALSE):

          + Internal error occurred.

   -2 (FALSE):

          + No SIPIdentityServiceLevel attribute found.

   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
   BRANCH_ROUTE, and ONREPLY_ROUTE.

   Example 1.10. Example Usage
#
# H.350 SIP digest authentication for caller
#

... h350_auth_lookup("$au", ...) ...

#
# store caller's service level as AVP
#

if (!h350_result_service_level("caller_sl_") && ($retcode == -1))
{
    sl_send_reply(500, "Internal server error");
    exit;
}

#
# make routing decision based on service level AVPs
#

if (is_avp_set("$avp(caller_sl_international)"))
{
    t_relay();
}
else {
    sl_send_reply(403, "Forbidden");
}
exit;

Resources

   [H.350] Directory Services Architecture for Multimedia
   Conferencing. August 2003. ITU-T.

   [H.350.4] Directory services architecture for SIP. August 2003.
   ITU-T.

   [H.350.6] Directory services architecture for call forwarding
   and preferences. March 2004. ITU-T.

   [ViDe-H.350-Cookbook] ViDe H.350 Cookbook. 2005. ViDe.

   [RFC4510] Lightweight Directory Access Protocol (LDAP):
   Technical Specification Road Map. June 2006. Internet
   Engineering Task Force.

Chapter 2. Contributors

2.1. By Commit Statistics

   Table 2.1. Top contributors by DevScore^(1), authored
   commits^(2) and lines added/removed^(3)
     Name DevScore Commits Lines ++ Lines --
   1. Christian Schlatter 21 3 1993 1
   2. Bogdan-Andrei Iancu (@bogdan-iancu) 15 13 52 50
   3. Daniel-Constantin Mierla (@miconda) 12 9 79 83
   4. Liviu Chircu (@liviuchircu) 10 8 25 37
   5. Vlad Patrascu (@rvlad-patrascu) 9 3 80 247
   6. Razvan Crainea (@razvancrainea) 7 5 50 59
   7. Konstantin Bokarius 3 1 1 4
   8. Peter Lemenkov (@lemenkov) 3 1 1 1
   9. Edson Gellert Schubert 3 1 0 85

   (1) DevScore = author_commits + author_lines_added /
   (project_lines_added / project_commits) + author_lines_deleted
   / (project_lines_deleted / project_commits)

   (2) including any documentation-related commits, excluding
   merge commits. Regarding imported patches/code, we do our best
   to count the work on behalf of the proper owner, as per the
   "fix_authors" and "mod_renames" arrays in
   opensips/doc/build-contrib.sh. If you identify any
   patches/commits which do not get properly attributed to you,
   please submit a pull request which extends "fix_authors" and/or
   "mod_renames".

   (3) ignoring whitespace edits, renamed files and auto-generated
   files

2.2. By Commit Activity

   Table 2.2. Most recently active contributors^(1) to this module
                     Name                   Commit Activity
   1. Bogdan-Andrei Iancu (@bogdan-iancu) Jan 2008 - Mar 2020
   2. Razvan Crainea (@razvancrainea)     Jun 2011 - Sep 2019
   3. Vlad Patrascu (@rvlad-patrascu)     May 2017 - Apr 2019
   4. Peter Lemenkov (@lemenkov)          Jun 2018 - Jun 2018
   5. Liviu Chircu (@liviuchircu)         Mar 2014 - Jun 2018
   6. Daniel-Constantin Mierla (@miconda) Sep 2007 - Mar 2008
   7. Konstantin Bokarius                 Mar 2008 - Mar 2008
   8. Edson Gellert Schubert              Feb 2008 - Feb 2008
   9. Christian Schlatter                 Aug 2007 - Dec 2007

   (1) including any documentation-related commits, excluding
   merge commits

Chapter 3. Documentation

3.1. Contributors

   Last edited by: Vlad Patrascu (@rvlad-patrascu), Peter Lemenkov
   (@lemenkov), Liviu Chircu (@liviuchircu), Razvan Crainea
   (@razvancrainea), Bogdan-Andrei Iancu (@bogdan-iancu),
   Daniel-Constantin Mierla (@miconda), Konstantin Bokarius, Edson
   Gellert Schubert, Christian Schlatter.

   Documentation Copyrights:

   Copyright © 2007 University of North Carolina
