Navigation


Changeset 356:e203fc0c95e3 in freeDiameter


Ignore:
Timestamp:
Jul 1, 2010, 3:47:34 PM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Updated the app_radgw extension to allow more souple management of sessions, and stateful gateway features.

Location:
extensions/app_radgw
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • extensions/app_radgw/rgw.h

    r271 r356  
    6868void rgw_msg_dump(struct rgw_radius_msg_meta * msg);
    6969int rgw_msg_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth);
    70 int rgw_msg_create_base(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, struct session ** session, struct msg ** diam);
     70int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam);
    7171int rgw_msg_init(void);
    7272
     
    117117void rgw_plg_start_cache(void);
    118118int rgw_plg_loop_req(struct rgw_radius_msg_meta **rad, struct session **session, struct msg **diam_msg, struct rgw_client * cli);
    119 int rgw_plg_loop_ans(struct rgw_radius_msg_meta *req, struct session *session, struct msg **diam_ans, struct radius_msg ** rad_ans, struct rgw_client * cli);
     119int rgw_plg_loop_ans(struct rgw_radius_msg_meta *req, struct session *session, struct msg **diam_ans, struct radius_msg ** rad_ans, struct rgw_client * cli, int * stateful);
    120120void rgw_plg_fini(void);
    121121
  • extensions/app_radgw/rgw_common.h

    r333 r356  
    7272
    7373        /* handle an incoming RADIUS message */
    74         int     (*rgwp_rad_req) ( struct rgwp_config * conf, struct session * session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli );
    75         /* ret 0: continue;
     74        int     (*rgwp_rad_req) ( struct rgwp_config * conf, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli );
     75        /* ret >0: critical error (errno), log and exit.
     76           ret 0: continue;
    7677           ret -1: stop processing this message
    7778           ret -2: reply the content of rad_ans to the RADIUS client immediatly
    78            ret >0: critical error (errno), log and exit.
    7979         */
    8080       
    8181        /* handle the corresponding Diameter answer */
    82         int     (*rgwp_diam_ans) ( struct rgwp_config * conf, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli );
     82        int     (*rgwp_diam_ans) ( struct rgwp_config * conf, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful );
    8383        /* ret 0: continue; ret >0: error; ret: -1 ... (tbd) */
    84 
     84        /* if *stateful = 1 on return, the session will not be destroyed after RADIUS answer is sent. The extension must ensure to register a timeout on the session in this case. */
     85       
    8586} rgwp_descriptor;
    8687
  • extensions/app_radgw/rgw_msg.c

    r278 r356  
    137137}
    138138
    139 static struct dict_object * cache_sess_id = NULL;
    140 static struct dict_object * cache_dest_host = NULL;
    141 static struct dict_object * cache_dest_realm = NULL;
    142139static struct dict_object * cache_orig_host = NULL;
    143140static struct dict_object * cache_orig_realm = NULL;
     
    146143{
    147144        TRACE_ENTRY();
    148         CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &cache_sess_id, ENOENT) );
    149         CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &cache_dest_host, ENOENT) );
    150         CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &cache_dest_realm, ENOENT) );
    151145        CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &cache_orig_host, ENOENT) );
    152146        CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) );
     
    154148}
    155149
    156 /* Create a msg with origin-host & realm, and session-id, and a session object from a RADIUS request message */
    157 int rgw_msg_create_base(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, struct session ** session, struct msg ** diam)
     150/* Create a new Diameter msg with origin-host & realm */
     151int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam)
    158152{
    159         int idx, i;
    160         const char * prefix = "Diameter/";
    161         size_t pref_len;
    162         char * dh = NULL;
    163         size_t dh_len = 0;
    164         char * dr = NULL;
    165         size_t dr_len = 0;
    166         char * si = NULL;
    167         size_t si_len = 0;
    168         char * un = NULL;
    169         size_t un_len = 0;
    170        
    171153        char * fqdn;
    172154        char * realm;
    173         char * sess_str = NULL;
    174155       
    175156        struct avp *avp = NULL;
    176157        union avp_value avp_val;
    177158       
    178         TRACE_ENTRY("%p %p %p %p", msg, cli, session, diam);
    179         CHECK_PARAMS( msg && cli && session && (*session == NULL) && diam && (*diam == NULL) );
    180        
    181         pref_len = strlen(prefix);
    182        
    183         /* Is there a State attribute with prefix "Diameter/" in the message? (in that case: Diameter/Destination-Host/Destination-Realm/Session-Id) */
    184         /* NOTE: RFC4005 says "Origin-Host" here, but it's not coherent with the rules for answers. Destination-Host makes more sense */
    185         /* Is there a Class attribute with prefix "Diameter/" in the message? (in that case: Diameter/Session-Id) */
    186         for (idx = 0; idx < msg->radius.attr_used; idx++) {
    187                 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[idx]);
    188                 char * attr_val = (char *)(attr + 1);
    189                 size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
    190                
    191                 if ((attr->type == RADIUS_ATTR_USER_NAME)
    192                                 && attr_len) {
    193                         TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr_len, attr_val);
    194                         un = attr_val;
    195                         un_len = attr_len;
    196                         continue;
    197                 }
    198                
    199                 if ((attr->type == RADIUS_ATTR_STATE)
    200                                 && (attr_len > pref_len + 5 /* for the '/'s and non empty strings */ )
    201                                 && ! strncmp(attr_val, prefix, pref_len)) { /* should we make it strncasecmp? */
    202                         int i, start;
    203                
    204                         TRACE_DEBUG(ANNOYING, "Found a State attribute with '%s' prefix (attr #%d).", prefix, idx);
    205 
    206                         /* Now parse the value and check its content is valid. Unfortunately we cannot use strchr here since strings are not \0-terminated */
    207 
    208                         i = start = pref_len;
    209                         dh = attr_val + i;
    210                         for (; (i < attr_len - 2) && (attr_val[i] != '/'); i++) /* loop */;
    211                         if ( i >= attr_len - 2 ) continue; /* the attribute format is not good */
    212                         dh_len = i - start;
    213 
    214                         start = ++i;
    215                         dr = attr_val + i;
    216                         for (; (i < attr_len - 1) && (attr_val[i] != '/'); i++) /* loop */;
    217                         if ( i >= attr_len - 1 ) continue; /* the attribute format is not good */
    218                         dr_len = i - start;
    219 
    220                         i++;
    221                         si = attr_val + i;
    222                         si_len = attr_len - i;
    223 
    224                         TRACE_DEBUG(ANNOYING, "Attribute parsed successfully: DH:'%.*s' DR:'%.*s' SI:'%.*s'.", dh_len, dh, dr_len, dr, si_len, si);
    225                         /* Remove from the message */
    226                         for (i = idx + 1; i < msg->radius.attr_used; i++)
    227                                 msg->radius.attr_pos[i - 1] = msg->radius.attr_pos[i];
    228                         msg->radius.attr_used -= 1;
    229                         break;
    230                 }
    231                
    232                 if ((attr->type == RADIUS_ATTR_CLASS)
    233                                 && (attr_len > pref_len )
    234                                 && ! strncmp(attr_val, prefix, pref_len)) {
    235                         si = attr_val + pref_len;
    236                         si_len = attr_len - pref_len;
    237                         TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), SI:'%.*s'.", prefix, idx, si_len, si);
    238                         /* Remove from the message */
    239                         for (i = idx + 1; i < msg->radius.attr_used; i++)
    240                                 msg->radius.attr_pos[i - 1] = msg->radius.attr_pos[i];
    241                         msg->radius.attr_used -= 1;
    242                         break;
    243                 }
    244                
    245         }
     159        TRACE_ENTRY("%p %p", cli, diam);
     160        CHECK_PARAMS( cli && diam && (*diam == NULL) );
    246161       
    247162        /* Get information on this peer */
    248163        CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
    249164       
    250         /* Create the session object */
    251         if (si_len) {
    252                 CHECK_FCT( fd_sess_fromsid ( si, si_len, session, &idx) );
    253         } else {
    254                 if (un) {
    255                         int len;
    256                         /* If not found, create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
    257                         CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
    258                         len = sprintf(sess_str, "%.*s;%s", un_len, un, fd_g_config->cnf_diamid);
    259                         CHECK_FCT( fd_sess_new(session, fqdn, sess_str, len) );
    260                         free(sess_str);
    261                         idx = 1;
    262                 }
    263         }
    264        
    265165        /* Create an empty Diameter message so that extensions can store their AVPs */
    266166        CHECK_FCT(  fd_msg_new ( NULL, MSGFL_ALLOC_ETEID, diam )  );
    267        
    268         if (*session) {
    269                 CHECK_FCT( fd_sess_getsid(*session, &sess_str) );
    270                 if (idx == 0) {
    271                         TRACE_DEBUG(INFO, "Another message was translated for this session ('%s') and not answered yet, discarding the new RADIUS request.", sess_str);
    272                         *session = NULL;
    273                         return EALREADY;
    274                 }
    275                
    276                 TRACE_DEBUG(FULL, "Translating new message for session '%s'...", sess_str);
    277                
    278                 /* Add the Session-Id AVP as first AVP */
    279                 CHECK_FCT( fd_msg_avp_new ( cache_sess_id, 0, &avp ) );
    280                 memset(&avp_val, 0, sizeof(avp_val));
    281                 avp_val.os.data = (unsigned char *)sess_str;
    282                 avp_val.os.len = strlen(sess_str);
    283                 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    284                 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_FIRST_CHILD, avp) );
    285 
    286         } else {
    287                 TRACE_DEBUG(FULL, "No session has been created for this message");
    288         }
    289        
    290         /* Add the Destination-Realm as next AVP */
    291         CHECK_FCT( fd_msg_avp_new ( cache_dest_realm, 0, &avp ) );
    292         memset(&avp_val, 0, sizeof(avp_val));
    293         if (dr) {
    294                 avp_val.os.data = (unsigned char *)dr;
    295                 avp_val.os.len = dr_len;
    296         } else {
    297                 int i = 0;
    298                 if (un) {
    299                         /* Is there an '@' in the user name? We don't care for decorated NAI here */
    300                         for (i = un_len - 2; i > 0; i--) {
    301                                 if (un[i] == '@') {
    302                                         i++;
    303                                         break;
    304                                 }
    305                         }
    306                 }
    307                 if (i == 0) {
    308                         /* Not found in the User-Name => we use the local domain of this gateway */
    309                         avp_val.os.data = fd_g_config->cnf_diamrlm;
    310                         avp_val.os.len  = fd_g_config->cnf_diamrlm_len;
    311                 } else {
    312                         avp_val.os.data = un + i;
    313                         avp_val.os.len  = un_len - i;
    314                 }
    315         }
    316         CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    317         CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
    318        
    319         /* Add the Destination-Host as next AVP */
    320         if (dh) {
    321                 CHECK_FCT( fd_msg_avp_new ( cache_dest_host, 0, &avp ) );
    322                 memset(&avp_val, 0, sizeof(avp_val));
    323                 avp_val.os.data = (unsigned char *)dh;
    324                 avp_val.os.len = dh_len;
    325                 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    326                 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
    327         }
    328167       
    329168        /* Add the Origin-Host as next AVP */
  • extensions/app_radgw/rgw_plugins.c

    r271 r356  
    349349                if (plg->descriptor->rgwp_rad_req) {
    350350                        TRACE_DEBUG(ANNOYING, "Calling next plugin: %s", plg->descriptor->rgwp_name);
    351                         ret = (*plg->descriptor->rgwp_rad_req)(plg->cs, *session, &(*rad)->radius, &rad_ans, diam_msg, cli);
     351                        ret = (*plg->descriptor->rgwp_rad_req)(plg->cs, session, &(*rad)->radius, &rad_ans, diam_msg, cli);
    352352                        if (ret)
    353353                                break;
     
    391391
    392392/* Loop in the extension list (same as req) to convert data from diam_ans to rad_ans */
    393 int rgw_plg_loop_ans(struct rgw_radius_msg_meta *req, struct session *session, struct msg **diam_ans, struct radius_msg ** rad_ans, struct rgw_client * cli)
     393int rgw_plg_loop_ans(struct rgw_radius_msg_meta *req, struct session *session, struct msg **diam_ans, struct radius_msg ** rad_ans, struct rgw_client * cli, int * stateful)
    394394{
    395395        int ret = 0;
    396396        struct fd_list * head = NULL, *li;
    397397       
    398         TRACE_ENTRY("%p %p %p %p %p", req, session, diam_ans, rad_ans, cli);
    399         CHECK_PARAMS( req && session && diam_ans && *diam_ans && rad_ans && *rad_ans && cli);
     398        TRACE_ENTRY("%p %p %p %p %p %p", req, session, diam_ans, rad_ans, cli, stateful);
     399        CHECK_PARAMS( req && session && diam_ans && *diam_ans && rad_ans && *rad_ans && cli && stateful);
     400       
     401        *stateful = 0; /* default: stateless gateway */
    400402       
    401403        /* Get the list of extensions of the RADIUS request */
     
    407409        for (li = head->next; li != head; li = li->next) {
    408410                struct plg_descr * plg = ((struct plg_accel_item *) li)->plg;
     411                int locstateful = 0;
    409412               
    410413                if (plg->descriptor->rgwp_diam_ans) {
    411414                        TRACE_DEBUG(ANNOYING, "Calling next plugin: %s", plg->descriptor->rgwp_name);
    412                         ret = (*plg->descriptor->rgwp_diam_ans)(plg->cs, session, diam_ans, rad_ans, (void *)cli);
     415                        ret = (*plg->descriptor->rgwp_diam_ans)(plg->cs, session, diam_ans, rad_ans, (void *)cli, &locstateful);
    413416                        if (ret)
    414417                                break;
     418                        *stateful |= locstateful;
    415419                } else {
    416420                        TRACE_DEBUG(ANNOYING, "Skipping extension '%s' (NULL callback)", plg->descriptor->rgwp_name);
  • extensions/app_radgw/rgw_worker.c

    r278 r356  
    130130               
    131131                /* Note: after this point, the radius message buffer may not be consistent with the array of attributes anymore. */
     132                diam_msg = NULL;
     133               
     134                /* Create an empty message with only Origin information (no session, no destination -- added by the plugins) */
     135                CHECK_FCT_DO( rgw_msg_create_base(cli, &diam_msg),
     136                        {
     137                                /* An error occurred, discard message */
     138                                rgw_msg_free(&msg);
     139                                rgw_clients_dispose(&cli);
     140                                continue;
     141                        }  );
    132142               
    133143                session = NULL;
    134                 diam_msg = NULL;
    135                
    136                 /* Create the session and an empty message with default common AVPs */
    137                 CHECK_FCT_DO( rgw_msg_create_base(msg, cli, &session, &diam_msg),
    138                         {
    139                                 /* An error occurred, discard message */
    140                                 rgw_msg_free(&msg);
    141                                 rgw_clients_dispose(&cli);
    142                                 continue;
    143                         }  );
    144144               
    145145                /* Pass the message to the list of registered plugins */
     
    158158                                continue;
    159159                        }  );
    160                 if (msg == NULL) {
     160                if (msg == NULL) { /* Error or RADIUS answer locally generated */
    161161                        rgw_clients_dispose(&cli);
    162162                        if (diam_msg) {
     
    164164                                diam_msg = NULL;
    165165                        }
    166                         if (session) {
    167                                 CHECK_FCT_DO( fd_sess_destroy(&session), );
    168                         }
    169166                        continue; /* the message was handled already */
    170167                }
     
    172169                pb = 0;
    173170               
    174                 /* Check the created Diameter message */
     171                /* Check the created Diameter message -- it will be invalid if no callback has handled the RADIUS message */
    175172                if ((diam_msg == NULL) || ( fd_msg_parse_rules(diam_msg, fd_g_config->cnf_dict, NULL) ) ) {
    176173                        fd_log_debug("[radgw] No or invalid Diameter message was generated after processing the RADIUS command %hhd (%s).\n"
    177                                         " This is likely an implementation problem, please report.\n",
     174                                        " It may indicate a gateway configuration problem, or implementation issue in a plugin.\n",
    178175                                        msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code));
    179                         /* We might also dump the conflicting rule here if useful */
     176                        /* We should also dump the conflicting rule here to help debug? */
    180177                        pb++;
    181178                }
     
    189186                                        msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code));
    190187                }
    191                
    192                 /* Check the session is correct (for debug) */
    193                 ASSERT(session != NULL);
    194188               
    195189                if (pb) {
     
    253247        struct avp_hdr  *ahdr;
    254248        int pb = 0;
     249        int keepsession=0;
    255250       
    256251        TRACE_ENTRY("%p %p", pa, ans);
     
    261256       
    262257        /* Pass the Diameter answer to the same extensions as the request */
    263         CHECK_FCT_DO( rgw_plg_loop_ans(pa->rad, pa->sess, ans, &rad_ans, pa->cli), goto out );
     258        CHECK_FCT_DO( rgw_plg_loop_ans(pa->rad, pa->sess, ans, &rad_ans, pa->cli, &keepsession), goto out );
    264259
    265260        if (*ans != NULL) {
     
    293288
    294289                if (pb) {
    295                         TRACE_DEBUG(INFO, "[radgw] WARNING: %d mandatory AVP in the Diameter answer have not been translated to RADIUS!\n Please use plg_debug.rgwx for more information.", pb);
     290                        TRACE_DEBUG(INFO, "[radgw] WARNING: %d mandatory AVP in the Diameter answer have not been translated to RADIUS!\n Please use debug.rgwx for more information.", pb);
    296291                }
    297292        }
     
    303298
    304299out:
    305         /* Destroy remaining session data (stateless gateway) */
    306         CHECK_FCT_DO( fd_sess_destroy(&pa->sess),  );
     300        if (!keepsession) {
     301                /* Destroy remaining session data (stateless gateway) */
     302                CHECK_FCT_DO( fd_sess_destroy(&pa->sess),  );
     303        }
    307304       
    308305        /* Clear the Diameter message */
  • extensions/app_radgw/rgwx_acct.c

    r296 r356  
    285285
    286286/* Incoming RADIUS request */
    287 static int acct_rad_req( struct rgwp_config * cs, struct session * session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
     287static int acct_rad_req( struct rgwp_config * cs, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
    288288{
    289289        int idx;
     
    300300        struct avp ** avp_tun = NULL, *avp = NULL;
    301301       
     302        const char * prefix = "Diameter/";
     303        size_t pref_len;
     304        char * si = NULL;
     305        size_t si_len = 0;
     306       
    302307        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
    303308        CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCOUNTING_REQUEST) && rad_ans && diam_fw && *diam_fw);
     309       
     310        pref_len = strlen(prefix);
    304311       
    305312        /*
     
    309316              port or the NAS does not distinguish among its ports.
    310317        */
     318        /* We also enforce that the message contains a CLASS attribute with Diameter/ prefix containing the Session-Id. */
    311319        for (idx = 0; idx < rad_req->attr_used; idx++) {
    312320                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
     
    342350                                                   |  v[3] ;
    343351                                break;
     352                               
     353                        case RADIUS_ATTR_CLASS:
     354                                {
     355                                        char * attr_val = (char *)(attr + 1);
     356                                        size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
     357                                        if ((attr_len > pref_len ) && ! strncmp(attr_val, prefix, pref_len)) {
     358                                                int i;
     359                                                si = attr_val + pref_len;
     360                                                si_len = attr_len - pref_len;
     361                                                TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), SI:'%.*s'.", prefix, idx, si_len, si);
     362                                                /* Remove from the message */
     363                                                for (i = idx + 1; i < rad_req->attr_used; i++)
     364                                                        rad_req->attr_pos[i - 1] = rad_req->attr_pos[i];
     365                                                rad_req->attr_used -= 1;
     366                                                break;
     367                                        }
     368                                }
     369                                break;
     370
    344371                }
    345372        }
     
    418445        }
    419446       
     447        /* Check if we got a valid session information, otherwise the server will not be able to handle the data... */
     448        if (!*session && !si) {
     449                TRACE_DEBUG(INFO, "[acct.rgwx] RADIUS Account-Request from %s did not contain a CLASS attribute with Diameter session information, reject.", rgw_clients_id(cli));
     450                return EINVAL;
     451        }
     452       
     453        /* Create the Session-Id AVP if needed */
     454        if (!*session) {
     455                CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) );
     456               
     457                TRACE_DEBUG(FULL, "[auth.rgwx] Translating new accounting message for session '%.*s'...", si_len, si);
     458               
     459                /* Add the Session-Id AVP as first AVP */
     460                CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
     461                value.os.data = (unsigned char *)si;
     462                value.os.len = si_len;
     463                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
     464                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
     465        }
     466               
    420467        /* Add the command code */
    421468        {
     
    10921139                }
    10931140                st->term_cause = str_cause;
    1094                 CHECK_FCT( fd_sess_state_store( cs->sess_hdl, session, &st ) );
     1141                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &st ) );
    10951142        }
    10961143       
     
    11281175}
    11291176
    1130 static int acct_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli )
     1177static int acct_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
    11311178{
    11321179        struct sess_state * st = NULL;
  • extensions/app_radgw/rgwx_auth.c

    r296 r356  
    7171                struct dict_object * CHAP_Ident;                /* CHAP-Ident */
    7272                struct dict_object * CHAP_Response;             /* CHAP-Response */
     73                struct dict_object * Destination_Host;          /* Destination-Host */
     74                struct dict_object * Destination_Realm;         /* Destination-Realm */
    7375                struct dict_object * Connect_Info;              /* Connect-Info */
    7476                struct dict_object * EAP_Payload;               /* EAP-Payload */
     
    154156        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Response", &new->dict.CHAP_Response, ENOENT) );
    155157        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Connect-Info", &new->dict.Connect_Info, ENOENT) );
     158        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &new->dict.Destination_Host, ENOENT) );
     159        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &new->dict.Destination_Realm, ENOENT) );
    156160        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "EAP-Payload", &new->dict.EAP_Payload, ENOENT) );
    157161        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &new->dict.Error_Message, ENOENT) );
     
    222226
    223227/* Handle an incoming RADIUS request */
    224 static int auth_rad_req( struct rgwp_config * cs, struct session * session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
     228static int auth_rad_req( struct rgwp_config * cs, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
    225229{
    226230        int idx;
     
    230234        int got_eap = 0;
    231235        int got_empty_eap = 0;
     236        const char * prefix = "Diameter/";
     237        size_t pref_len;
     238        char * dh = NULL;
     239        size_t dh_len = 0;
     240        char * dr = NULL;
     241        size_t dr_len = 0;
     242        char * si = NULL;
     243        size_t si_len = 0;
     244        char * un = NULL;
     245        size_t un_len = 0;
    232246        uint32_t status_type;
    233247        size_t nattr_used = 0;
     
    236250       
    237251        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
    238         CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw);
     252        CHECK_PARAMS(cs && session && rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCESS_REQUEST) && rad_ans && diam_fw && *diam_fw);
     253       
     254        pref_len = strlen(prefix);
    239255       
    240256        /*
     
    269285                        and associated with the session state.
    270286                     -> sub_echo_drop should handle the Proxy-State attribute (conf issue)
    271 
    272               -  If the RADIUS request contained a State attribute and the
    273                  prefix of the data is "Diameter/", the data following the
    274                  prefix contains the Diameter Origin-Host/Origin-Realm/Session-
    275                  Id.  If no such attributes are present and the RADIUS command
    276                  is an Access-Request, a new Session-Id is created.  The
    277                  Session-Id is included in the Session-Id AVP.
    278                      -> done in rgw_msg_create_base.
    279287
    280288              -  The Diameter Origin-Host and Origin-Realm AVPs MUST be created
     
    305313        */
    306314       
    307         /* Check basic information is there */
     315        /* Check basic information is there, and also retrieve some attribute information */
    308316        for (idx = 0; idx < rad_req->attr_used; idx++) {
    309317                struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]);
     318                char * attr_val = (char *)(attr + 1);
     319                size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
     320               
    310321                switch (attr->type) {
    311322                        case RADIUS_ATTR_NAS_IP_ADDRESS:
     
    327338                                got_passwd += 1;
    328339                                break;
     340                               
     341                        /* Is there a State attribute with prefix "Diameter/" in the message? (in that case: Diameter/Destination-Host/Destination-Realm/Session-Id) */
     342                        /* NOTE: RFC4005 says "Origin-Host" here, but it's not coherent with the rules for answers. Destination-Host makes more sense */
     343                        case RADIUS_ATTR_STATE:
     344                                if ((attr_len > pref_len + 5 /* for the '/'s and non empty strings */ )
     345                                        && ! strncmp(attr_val, prefix, pref_len)) { /* should we make it strncasecmp? */
     346                                        int i, start;
     347
     348                                        TRACE_DEBUG(ANNOYING, "Found a State attribute with '%s' prefix (attr #%d).", prefix, idx);
     349
     350                                        /* Now parse the value and check its content is valid. Unfortunately we cannot use strchr here since strings are not \0-terminated */
     351
     352                                        i = start = pref_len;
     353                                        dh = attr_val + i;
     354                                        for (; (i < attr_len - 2) && (attr_val[i] != '/'); i++) /* loop */;
     355                                        if ( i >= attr_len - 2 ) continue; /* the attribute format is not good */
     356                                        dh_len = i - start;
     357
     358                                        start = ++i;
     359                                        dr = attr_val + i;
     360                                        for (; (i < attr_len - 1) && (attr_val[i] != '/'); i++) /* loop */;
     361                                        if ( i >= attr_len - 1 ) continue; /* the attribute format is not good */
     362                                        dr_len = i - start;
     363
     364                                        i++;
     365                                        si = attr_val + i;
     366                                        si_len = attr_len - i;
     367
     368                                        TRACE_DEBUG(ANNOYING, "Attribute parsed successfully: DH:'%.*s' DR:'%.*s' SI:'%.*s'.", dh_len, dh, dr_len, dr, si_len, si);
     369                                        /* Remove from the message */
     370                                        for (i = idx + 1; i < rad_req->attr_used; i++)
     371                                                rad_req->attr_pos[i - 1] = rad_req->attr_pos[i];
     372                                        rad_req->attr_used -= 1;
     373                                }
     374                                break;
     375               
     376                        case RADIUS_ATTR_USER_NAME:
     377                                if (attr_len) {
     378                                        TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr_len, attr_val);
     379                                        un = attr_val;
     380                                        un_len = attr_len;
     381                                }
     382                                break;
     383                       
    329384                }
    330385        }
     
    346401                return EINVAL;
    347402        }
     403       
     404       
     405       
     406        /*
     407              -  If the RADIUS request contained a State attribute and the
     408                 prefix of the data is "Diameter/", the data following the
     409                 prefix contains the Diameter Origin-Host/Origin-Realm/Session-
     410                 Id.  If no such attributes are present and the RADIUS command
     411                 is an Access-Request, a new Session-Id is created.  The
     412                 Session-Id is included in the Session-Id AVP.
     413        */
     414       
     415        /* Add the Destination-Realm AVP */
     416        CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Realm, 0, &avp ) );
     417        if (dr) {
     418                value.os.data = (unsigned char *)dr;
     419                value.os.len = dr_len;
     420        } else {
     421                int i = 0;
     422                if (un) {
     423                        /* Is there an '@' in the user name? We don't care for decorated NAI here */
     424                        for (i = un_len - 2; i > 0; i--) {
     425                                if (un[i] == '@') {
     426                                        i++;
     427                                        break;
     428                                }
     429                        }
     430                }
     431                if (i == 0) {
     432                        /* Not found in the User-Name => we use the local domain of this gateway */
     433                        value.os.data = fd_g_config->cnf_diamrlm;
     434                        value.os.len  = fd_g_config->cnf_diamrlm_len;
     435                } else {
     436                        value.os.data = un + i;
     437                        value.os.len  = un_len - i;
     438                }
     439        }
     440        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
     441        CHECK_FCT( fd_msg_avp_add ( *diam_fw, *session ? MSG_BRW_LAST_CHILD : MSG_BRW_FIRST_CHILD, avp) );
     442       
     443        /* Add the Destination-Host if found */
     444        if (dh) {
     445                CHECK_FCT( fd_msg_avp_new ( cs->dict.Destination_Host, 0, &avp ) );
     446                value.os.data = (unsigned char *)dh;
     447                value.os.len = dh_len;
     448                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
     449                CHECK_FCT( fd_msg_avp_add ( *diam_fw, *session ? MSG_BRW_LAST_CHILD : MSG_BRW_FIRST_CHILD, avp) );
     450        }
     451       
     452        /* Create the session if it is not already done */
     453        if (*session == NULL) {
     454                char * sess_str = NULL;
     455               
     456                if (si_len) {
     457                        /* We already have the Session-Id, just use it */
     458                        CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) );
     459                } else {
     460                        /* Create a new Session-Id string */
     461                       
     462                        char * fqdn;
     463                        char * realm;
     464                       
     465                        /* Get information on the RADIUS client */
     466                        CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
     467                       
     468                        /* If we have a user name, create the new session with it */
     469                        if (un) {
     470                                int len;
     471                                /* If not found, create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
     472                                CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
     473                                len = sprintf(sess_str, "%.*s;%s", un_len, un, fd_g_config->cnf_diamid);
     474                                CHECK_FCT( fd_sess_new(session, fqdn, sess_str, len) );
     475                                free(sess_str);
     476                        } else {
     477                                /* We don't have enough information to create the Session-Id, the RADIUS message is probably invalid */
     478                                TRACE_DEBUG(INFO, "RADIUS Access-Request does not contain a User-Name attribute, rejecting.");
     479                                return EINVAL;
     480                        }       
     481                }
     482               
     483                /* Now, add the Session-Id AVP at beginning of Diameter message */
     484                CHECK_FCT( fd_sess_getsid(*session, &sess_str) );
     485               
     486                TRACE_DEBUG(FULL, "[auth.rgwx] Translating new message for session '%s'...", sess_str);
     487               
     488                /* Add the Session-Id AVP as first AVP */
     489                CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
     490                value.os.data = (unsigned char *)sess_str;
     491                value.os.len = strlen(sess_str);
     492                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
     493                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
     494        }
     495       
    348496       
    349497        /* Add the appropriate command code & Auth-Application-Id */
     
    9081056                memcpy(req_auth, &rad_req->hdr->authenticator[0], 16);
    9091057               
    910                 CHECK_FCT( fd_sess_state_store( cs->sess_hdl, session, &req_auth ) );
     1058                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &req_auth ) );
    9111059        }
    9121060       
     
    9141062}
    9151063
    916 static int auth_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli )
     1064static int auth_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
    9171065{
    9181066        struct msg_hdr * hdr;
  • extensions/app_radgw/rgwx_debug.c

    r258 r356  
    7272
    7373/* Function called when a new RADIUS message is being converted to Diameter */
    74 static int debug_rad_req( struct rgwp_config * cs, struct session * session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
     74static int debug_rad_req( struct rgwp_config * cs, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
    7575{
    7676        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
     
    9999        }
    100100       
     101        if (!session || ! *session) {
     102                fd_log_debug(" Diameter session: NULL pointer\n");
     103        } else {
     104                char * str;
     105                CHECK_FCT( fd_sess_getsid(*session, &str) );
     106
     107                fd_log_debug(" Diameter session: %s\n", str);
     108        }
     109       
    101110        fd_log_debug("===========  Debug%s%s%s complete =============\n", cs ? " [" : "", cs ? (char *)cs : "", cs ? "]" : "");
    102111       
     
    105114
    106115/* This one, when Diameter answer is converted to RADIUS */
    107 static int debug_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli )
     116static int debug_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
    108117{
    109         TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
     118        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, diam_ans, rad_fw, cli, stateful);
    110119
    111120        fd_log_debug("------------- RADIUS/Diameter Answer Debug%s%s%s -------------\n", cs ? " [" : "", cs ? (char *)cs : "", cs ? "]" : "");
  • extensions/app_radgw/rgwx_echodrop.c

    r340 r356  
    119119
    120120/* Handle attributes from a RADIUS request as specified in the configuration */
    121 static int ed_rad_req( struct rgwp_config * cs, struct session * session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
     121static int ed_rad_req( struct rgwp_config * cs, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
    122122{
    123123        size_t nattr_used = 0;
     
    128128       
    129129        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
    130         CHECK_PARAMS(cs && rad_req);
     130        CHECK_PARAMS(cs && rad_req && session);
    131131       
    132132        /* For each attribute in the original message */
     
    217217        /* Save the echoed values in the session, if any */
    218218        if (!FD_IS_LIST_EMPTY(&echo_list)) {
    219                 CHECK_PARAMS(session);
     219                CHECK_PARAMS_DO(*session,
     220                        {
     221                                fd_log_debug(   "[echodrop.rgwx] The extension is configured to echo some attributes from this message, but no session object has been created for it (yet).\n"
     222                                                "  Please check your configuration file and include a session-generating extension BEFORE calling echodrop.rgwx to echo attributes.\n"
     223                                                "  Please use debug.rgwx to retrieve more information.\n" );
     224                                return EINVAL;
     225                        } );
    220226               
    221227                /* Move the values in a dynamically allocated list */
     
    225231               
    226232                /* Save the list in the session */
    227                 CHECK_FCT( fd_sess_state_store( cs->sess_hdl, session, &li ) );
     233                CHECK_FCT( fd_sess_state_store( cs->sess_hdl, *session, &li ) );
    228234        }
    229235       
     
    232238
    233239/* Process an answer: add the ECHO attributes back, if any */
    234 static int ed_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli )
     240static int ed_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
    235241{
    236242        int ret;
    237243        struct fd_list * list = NULL;
    238244       
    239         TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
     245        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, diam_ans, rad_fw, cli, stateful);
    240246        CHECK_PARAMS(cs);
    241247       
  • extensions/app_radgw/rgwx_sample.c

    r258 r356  
    6767
    6868/* This function is called on incoming RADIUS messages. It should handle (some) RADIUS data and store into the Diameter message. */
    69 static int sample_rad_req( struct rgwp_config * cs, struct session * session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
     69static int sample_rad_req( struct rgwp_config * cs, struct session ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
    7070{
    7171        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
     
    7676
    7777/* This function is called when a Diameter answer is coming back. It should remove the AVPs and add the attributes in the RADIUS message. */
    78 static int sample_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli )
     78static int sample_diam_ans( struct rgwp_config * cs, struct session * session, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli, int * stateful )
    7979{
    80         TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
     80        TRACE_ENTRY("%p %p %p %p %p %p", cs, session, diam_ans, rad_fw, cli, stateful);
    8181        CHECK_PARAMS(cs);
    8282        TRACE_DEBUG(INFO, "RADIUS/Diameter Sample plugin received a new Diameter answer.");
Note: See TracChangeset for help on using the changeset viewer.