Changeset 356:e203fc0c95e3 in freeDiameter
- Timestamp:
- Jul 1, 2010, 3:47:34 PM (13 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- extensions/app_radgw
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
extensions/app_radgw/rgw.h
r271 r356 68 68 void rgw_msg_dump(struct rgw_radius_msg_meta * msg); 69 69 int 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);70 int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam); 71 71 int rgw_msg_init(void); 72 72 … … 117 117 void rgw_plg_start_cache(void); 118 118 int 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 );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, int * stateful); 120 120 void rgw_plg_fini(void); 121 121 -
extensions/app_radgw/rgw_common.h
r333 r356 72 72 73 73 /* 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; 76 77 ret -1: stop processing this message 77 78 ret -2: reply the content of rad_ans to the RADIUS client immediatly 78 ret >0: critical error (errno), log and exit.79 79 */ 80 80 81 81 /* 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 ); 83 83 /* 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 85 86 } rgwp_descriptor; 86 87 -
extensions/app_radgw/rgw_msg.c
r278 r356 137 137 } 138 138 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;142 139 static struct dict_object * cache_orig_host = NULL; 143 140 static struct dict_object * cache_orig_realm = NULL; … … 146 143 { 147 144 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) );151 145 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &cache_orig_host, ENOENT) ); 152 146 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) ); … … 154 148 } 155 149 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 */ 151 int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam) 158 152 { 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 171 153 char * fqdn; 172 154 char * realm; 173 char * sess_str = NULL;174 155 175 156 struct avp *avp = NULL; 176 157 union avp_value avp_val; 177 158 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) ); 246 161 247 162 /* Get information on this peer */ 248 163 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) ); 249 164 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 265 165 /* Create an empty Diameter message so that extensions can store their AVPs */ 266 166 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 }328 167 329 168 /* Add the Origin-Host as next AVP */ -
extensions/app_radgw/rgw_plugins.c
r271 r356 349 349 if (plg->descriptor->rgwp_rad_req) { 350 350 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); 352 352 if (ret) 353 353 break; … … 391 391 392 392 /* 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 )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, int * stateful) 394 394 { 395 395 int ret = 0; 396 396 struct fd_list * head = NULL, *li; 397 397 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 */ 400 402 401 403 /* Get the list of extensions of the RADIUS request */ … … 407 409 for (li = head->next; li != head; li = li->next) { 408 410 struct plg_descr * plg = ((struct plg_accel_item *) li)->plg; 411 int locstateful = 0; 409 412 410 413 if (plg->descriptor->rgwp_diam_ans) { 411 414 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); 413 416 if (ret) 414 417 break; 418 *stateful |= locstateful; 415 419 } else { 416 420 TRACE_DEBUG(ANNOYING, "Skipping extension '%s' (NULL callback)", plg->descriptor->rgwp_name); -
extensions/app_radgw/rgw_worker.c
r278 r356 130 130 131 131 /* 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 } ); 132 142 133 143 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 } );144 144 145 145 /* Pass the message to the list of registered plugins */ … … 158 158 continue; 159 159 } ); 160 if (msg == NULL) { 160 if (msg == NULL) { /* Error or RADIUS answer locally generated */ 161 161 rgw_clients_dispose(&cli); 162 162 if (diam_msg) { … … 164 164 diam_msg = NULL; 165 165 } 166 if (session) {167 CHECK_FCT_DO( fd_sess_destroy(&session), );168 }169 166 continue; /* the message was handled already */ 170 167 } … … 172 169 pb = 0; 173 170 174 /* Check the created Diameter message */171 /* Check the created Diameter message -- it will be invalid if no callback has handled the RADIUS message */ 175 172 if ((diam_msg == NULL) || ( fd_msg_parse_rules(diam_msg, fd_g_config->cnf_dict, NULL) ) ) { 176 173 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", 178 175 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? */ 180 177 pb++; 181 178 } … … 189 186 msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code)); 190 187 } 191 192 /* Check the session is correct (for debug) */193 ASSERT(session != NULL);194 188 195 189 if (pb) { … … 253 247 struct avp_hdr *ahdr; 254 248 int pb = 0; 249 int keepsession=0; 255 250 256 251 TRACE_ENTRY("%p %p", pa, ans); … … 261 256 262 257 /* 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 ); 264 259 265 260 if (*ans != NULL) { … … 293 288 294 289 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); 296 291 } 297 292 } … … 303 298 304 299 out: 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 } 307 304 308 305 /* Clear the Diameter message */ -
extensions/app_radgw/rgwx_acct.c
r296 r356 285 285 286 286 /* 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 )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 ) 288 288 { 289 289 int idx; … … 300 300 struct avp ** avp_tun = NULL, *avp = NULL; 301 301 302 const char * prefix = "Diameter/"; 303 size_t pref_len; 304 char * si = NULL; 305 size_t si_len = 0; 306 302 307 TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli); 303 308 CHECK_PARAMS(rad_req && (rad_req->hdr->code == RADIUS_CODE_ACCOUNTING_REQUEST) && rad_ans && diam_fw && *diam_fw); 309 310 pref_len = strlen(prefix); 304 311 305 312 /* … … 309 316 port or the NAS does not distinguish among its ports. 310 317 */ 318 /* We also enforce that the message contains a CLASS attribute with Diameter/ prefix containing the Session-Id. */ 311 319 for (idx = 0; idx < rad_req->attr_used; idx++) { 312 320 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]); … … 342 350 | v[3] ; 343 351 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 344 371 } 345 372 } … … 418 445 } 419 446 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 420 467 /* Add the command code */ 421 468 { … … 1092 1139 } 1093 1140 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 ) ); 1095 1142 } 1096 1143 … … 1128 1175 } 1129 1176 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 )1177 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, int * stateful ) 1131 1178 { 1132 1179 struct sess_state * st = NULL; -
extensions/app_radgw/rgwx_auth.c
r296 r356 71 71 struct dict_object * CHAP_Ident; /* CHAP-Ident */ 72 72 struct dict_object * CHAP_Response; /* CHAP-Response */ 73 struct dict_object * Destination_Host; /* Destination-Host */ 74 struct dict_object * Destination_Realm; /* Destination-Realm */ 73 75 struct dict_object * Connect_Info; /* Connect-Info */ 74 76 struct dict_object * EAP_Payload; /* EAP-Payload */ … … 154 156 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CHAP-Response", &new->dict.CHAP_Response, ENOENT) ); 155 157 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) ); 156 160 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "EAP-Payload", &new->dict.EAP_Payload, ENOENT) ); 157 161 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &new->dict.Error_Message, ENOENT) ); … … 222 226 223 227 /* 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 )228 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 ) 225 229 { 226 230 int idx; … … 230 234 int got_eap = 0; 231 235 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; 232 246 uint32_t status_type; 233 247 size_t nattr_used = 0; … … 236 250 237 251 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); 239 255 240 256 /* … … 269 285 and associated with the session state. 270 286 -> sub_echo_drop should handle the Proxy-State attribute (conf issue) 271 272 - If the RADIUS request contained a State attribute and the273 prefix of the data is "Diameter/", the data following the274 prefix contains the Diameter Origin-Host/Origin-Realm/Session-275 Id. If no such attributes are present and the RADIUS command276 is an Access-Request, a new Session-Id is created. The277 Session-Id is included in the Session-Id AVP.278 -> done in rgw_msg_create_base.279 287 280 288 - The Diameter Origin-Host and Origin-Realm AVPs MUST be created … … 305 313 */ 306 314 307 /* Check basic information is there */315 /* Check basic information is there, and also retrieve some attribute information */ 308 316 for (idx = 0; idx < rad_req->attr_used; idx++) { 309 317 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 310 321 switch (attr->type) { 311 322 case RADIUS_ATTR_NAS_IP_ADDRESS: … … 327 338 got_passwd += 1; 328 339 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 329 384 } 330 385 } … … 346 401 return EINVAL; 347 402 } 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 348 496 349 497 /* Add the appropriate command code & Auth-Application-Id */ … … 908 1056 memcpy(req_auth, &rad_req->hdr->authenticator[0], 16); 909 1057 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 ) ); 911 1059 } 912 1060 … … 914 1062 } 915 1063 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 )1064 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, int * stateful ) 917 1065 { 918 1066 struct msg_hdr * hdr; -
extensions/app_radgw/rgwx_debug.c
r258 r356 72 72 73 73 /* 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 )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 ) 75 75 { 76 76 TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli); … … 99 99 } 100 100 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 101 110 fd_log_debug("=========== Debug%s%s%s complete =============\n", cs ? " [" : "", cs ? (char *)cs : "", cs ? "]" : ""); 102 111 … … 105 114 106 115 /* 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 )116 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, int * stateful ) 108 117 { 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); 110 119 111 120 fd_log_debug("------------- RADIUS/Diameter Answer Debug%s%s%s -------------\n", cs ? " [" : "", cs ? (char *)cs : "", cs ? "]" : ""); -
extensions/app_radgw/rgwx_echodrop.c
r340 r356 119 119 120 120 /* 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 )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 ) 122 122 { 123 123 size_t nattr_used = 0; … … 128 128 129 129 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); 131 131 132 132 /* For each attribute in the original message */ … … 217 217 /* Save the echoed values in the session, if any */ 218 218 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 } ); 220 226 221 227 /* Move the values in a dynamically allocated list */ … … 225 231 226 232 /* 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 ) ); 228 234 } 229 235 … … 232 238 233 239 /* 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 )240 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, int * stateful ) 235 241 { 236 242 int ret; 237 243 struct fd_list * list = NULL; 238 244 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); 240 246 CHECK_PARAMS(cs); 241 247 -
extensions/app_radgw/rgwx_sample.c
r258 r356 67 67 68 68 /* 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 )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 ) 70 70 { 71 71 TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli); … … 76 76 77 77 /* 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 )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, int * stateful ) 79 79 { 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); 81 81 CHECK_PARAMS(cs); 82 82 TRACE_DEBUG(INFO, "RADIUS/Diameter Sample plugin received a new Diameter answer.");
Note: See TracChangeset
for help on using the changeset viewer.