Navigation


Changeset 356:e203fc0c95e3 in freeDiameter for extensions/app_radgw/rgwx_auth.c


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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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;
Note: See TracChangeset for help on using the changeset viewer.