/* * Add User-Name attribute */ static inline int add_user_name(struct sip_msg* rq, void* rh, VALUE_PAIR** send) { struct sip_uri puri; str* user, *realm; str user_name; struct to_body* from; user = cred_user(rq); /* try to take it from credentials */ realm = cred_realm(rq); if (!user || !realm) { if (rq->from && (from = get_from(rq)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "ERROR:acc:add_user_name: Bad From URI\n"); return -1; } user = &puri.user; realm = &puri.host; } else { DBG("acc:add_user_name: Neither digest nor From found, mandatory attribute User-Name not added\n"); return -1; } } user_name.len = user->len + 1 + realm->len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR:acc:add_user_name: no memory\n"); return -1; } memcpy(user_name.s, user->s, user->len); user_name.s[user->len] = '@'; memcpy(user_name.s + user->len + 1, realm->s, realm->len); if (!rc_avpair_add(rh, send, ATTRID(attrs[A_USER_NAME].v), user_name.s, user_name.len, VENDOR(attrs[A_USER_NAME].v))) { LOG(L_ERR, "ERROR:acc:add_user_name: Failed to add User-Name attribute\n"); pkg_free(user_name.s); return -1; } pkg_free(user_name.s); return 0; }
/* create an array of str's for accounting using a formatting string; * this is the heart of the accounting module -- it prints whatever * requested in a way, that can be used for syslog, radius, * sql, whatsoever * tm sip_msg_clones does not clone (shmmem-zed) parsed fields, other then Via1,2. Such fields clone now or use from rq_rp */ static int fmt2strar(char *fmt, /* what would you like to account ? */ struct sip_msg *rq, /* accounted message */ str* ouri, /* Outbound Request-URI */ struct hdr_field *to, unsigned int code, time_t req_time) /* Timestamp of the request */ { int cnt; struct to_body* from, *pto; str *cr, *at; struct cseq_body *cseq; cnt = 0; /* we don't care about parsing here; either the function * was called from script, in which case the wrapping function * is supposed to parse, or from reply processing in which case * TM should have preparsed from REQUEST_IN callback; what's not * here is replaced with NA */ while(*fmt) { if (cnt == ALL_LOG_FMT_LEN) { LOG(L_ERR, "ERROR:acc:fmt2strar: Formatting string is too long\n"); return 0; } switch(*fmt) { case 'a': /* attr */ at = print_attrs(avps, avps_n, 0); if (!at) { vals[cnt].nul = 1; } else { vals[cnt].val.str_val = *at; } break; case 'c': /* sip_callid */ if (rq->callid && rq->callid->body.len) { vals[cnt].val.str_val = rq->callid->body; } else { vals[cnt].nul = 1; } break; case 'd': /* to_tag */ if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) { vals[cnt].val.str_val = pto->tag_value; } else { vals[cnt].nul = 1; } break; case 'f': /* sip_from */ if (rq->from && rq->from->body.len) { vals[cnt].val.str_val = rq->from->body; } else { vals[cnt].nul = 1; } break; case 'g': /* flags */ vals[cnt].val.int_val = rq->flags; break; case 'i': /* inbound_ruri */ vals[cnt].val.str_val = rq->first_line.u.request.uri; break; case 'm': /* sip_method */ vals[cnt].val.str_val = rq->first_line.u.request.method; break; case 'n': /* sip_cseq */ if (rq->cseq && (cseq = get_cseq(rq)) && cseq->number.len) { str2int(&cseq->number, (unsigned int*)&vals[cnt].val.int_val); } else { vals[cnt].nul = 1; } break; case 'o': /* outbound_ruri */ vals[cnt].val.str_val = *ouri; break; case 'p': vals[cnt].val.int_val = rq->rcv.src_ip.u.addr32[0]; break; break; case 'r': /* from_tag */ if (rq->from && (from = get_from(rq)) && from->tag_value.len) { vals[cnt].val.str_val = from->tag_value; } else { vals[cnt].nul = 1; } break; case 't': /* sip_to */ if (to && to->body.len) vals[cnt].val.str_val = to->body; else vals[cnt].nul = 1; break; case 'u': /* digest_username */ cr = cred_user(rq); if (cr) vals[cnt].val.str_val = *cr; else vals[cnt].nul = 1; break; case 'x': /* request_timestamp */ vals[cnt].val.time_val = req_time; break; case 'D': /* to_did */ vals[cnt].nul = 1; break; case 'F': /* from_uri */ if (rq->from && (from = get_from(rq)) && from->uri.len) { vals[cnt].val.str_val = from->uri; } else vals[cnt].nul = 1; break; case 'I': /* from_uid */ if (get_from_uid(&vals[cnt].val.str_val, rq) < 0) { vals[cnt].nul = 1; } break; case 'M': /* from_did */ vals[cnt].nul = 1; break; case 'P': /* source_port */ vals[cnt].val.int_val = rq->rcv.src_port; break; case 'R': /* digest_realm */ cr = cred_realm(rq); if (cr) vals[cnt].val.str_val = *cr; else vals[cnt].nul = 1; break; case 'S': /* sip_status */ if (code > 0) vals[cnt].val.int_val = code; else vals[cnt].nul = 1; break; case 'T': /* to_uri */ if (rq->to && (pto = get_to(rq)) && pto->uri.len) vals[cnt].val.str_val = pto->uri; else vals[cnt].nul = 1; break; case 'U': /* to_uid */ if (get_to_uid(&vals[cnt].val.str_val, rq) < 0) { vals[cnt].nul = 1; } break; case 'X': /* response_timestamp */ vals[cnt].val.time_val = time(0); break; default: LOG(L_CRIT, "BUG:acc:fmt2strar: unknown char: %c\n", *fmt); return 0; } /* switch (*fmt) */ fmt++; cnt++; } /* while (*fmt) */ return cnt; }
int acc_diam_request( struct sip_msg *rq, struct hdr_field *to, str *phrase ) { str* val_arr[ALL_LOG_FMT_LEN+1]; str atr_arr[ALL_LOG_FMT_LEN+1]; int attr_cnt; AAAMessage *send = NULL; AAA_AVP *avp; int i; int dummy_len; str* user; str* realm; str user_name; str value; str *uri; struct sip_uri puri; struct to_body* from; int ret, free_user_name; int status; char tmp[2]; unsigned int mid; if (skip_cancel(rq)) return 1; attr_cnt=fmt2strar( DIAM_ACC_FMT, rq, to, phrase, &dummy_len, &dummy_len, val_arr, atr_arr); if (attr_cnt!=(sizeof(DIAM_ACC_FMT)-1)) { LOG(L_ERR, "ERROR: acc_diam_request: fmt2strar failed\n"); return -1; } if ( (send=AAAInMessage(ACCOUNTING_REQUEST, AAA_APP_NASREQ))==NULL) { LOG(L_ERR, "ERROR: acc_diam_request: new AAA message not created\n"); return -1; } /* AVP_ACCOUNTIG_RECORD_TYPE */ if( (status = diam_status(rq, phrase))<0) { LOG(L_ERR, "ERROR: acc_diam_request: status unknown\n"); goto error; } tmp[0] = status+'0'; tmp[1] = 0; if( (avp=AAACreateAVP(AVP_Accounting_Record_Type, 0, 0, tmp, 1, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP_MSGID AVP */ DBG("**ACC***** m_id=%d\n", rq->id); mid = rq->id; if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid), sizeof(mid), AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR, M_NAME":diameter_authorize(): no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, M_NAME":diameter_authorize(): avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP Service AVP */ if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING, SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP_STATUS avp */ if( (avp=AAACreateAVP(AVP_SIP_STATUS, 0, 0, phrase->s, phrase->len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP_METHOD avp */ value = rq->first_line.u.request.method; if( (avp=AAACreateAVP(AVP_SIP_METHOD, 0, 0, value.s, value.len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* Handle AVP_USER_NAME as a special case */ free_user_name = 0; user=cred_user(rq); /* try to take it from credentials */ if (user) { realm = cred_realm(rq); if (realm) { user_name.len = user->len+1+realm->len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_diam_request: no memory\n"); goto error; } memcpy(user_name.s, user->s, user->len); user_name.s[user->len] = '@'; memcpy(user_name.s+user->len+1, realm->s, realm->len); free_user_name = 1; } else { user_name.len = user->len; user_name.s = user->s; } } else { /* from from uri */ if (rq->from && (from=get_from(rq)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "ERROR: acc_diam_request: Bad From URI\n"); goto error; } user_name.len = puri.user.len+1+puri.host.len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_diam_request: no memory\n"); goto error; } memcpy(user_name.s, puri.user.s, puri.user.len); user_name.s[puri.user.len] = '@'; memcpy(user_name.s+puri.user.len+1, puri.host.s, puri.host.len); free_user_name = 1; } else { user_name.len = na.len; user_name.s = na.s; } } if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, user_name.len, free_user_name?AVP_FREE_DATA:AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); if(free_user_name) pkg_free(user_name.s); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* Remaining attributes from diam_attr vector */ for(i=0; i<attr_cnt; i++) { if((avp=AAACreateAVP(diam_attr[i], 0,0, val_arr[i]->s, val_arr[i]->len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } } if (get_uri(rq, &uri) < 0) { LOG(L_ERR, "ERROR: acc_diam_request: From/To URI not found\n"); goto error; } if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, "ERROR: acc_diam_request: Error parsing From/To URI\n"); goto error; } /* Destination-Realm AVP */ if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s, puri.host.len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* prepare the message to be sent over the network */ if(AAABuildMsgBuffer(send) != AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: message buffer not created\n"); goto error; } if(sockfd==AAA_NO_CONNECTION) { sockfd = init_mytcp(diameter_client_host, diameter_client_port); if(sockfd==AAA_NO_CONNECTION) { LOG(L_ERR, M_NAME":acc_diam_request: failed to reconnect" " to Diameter client\n"); goto error; } } /* send the message to the DIAMETER client */ ret = tcp_send_recv(sockfd, send->buf.s, send->buf.len, rb, rq->id); if(ret == AAA_CONN_CLOSED) { LOG(L_NOTICE, M_NAME":acc_diam_request: connection to Diameter" " client closed.It will be reopened by the next request\n"); close(sockfd); sockfd = AAA_NO_CONNECTION; goto error; } if(ret != ACC_SUCCESS) /* a transmission error occurred */ { LOG(L_ERR, M_NAME":acc_diam_request: message sending to the" " DIAMETER backend authorization server failed\n"); goto error; } AAAFreeMessage(&send); return 1; error: AAAFreeMessage(&send); return -1; }
int acc_rad_request( struct sip_msg *rq, struct hdr_field *to, str *phrase ) { str* val_arr[ALL_LOG_FMT_LEN+1]; str atr_arr[ALL_LOG_FMT_LEN+1]; int attr_cnt; VALUE_PAIR *send; UINT4 av_type; int i; int dummy_len; str* user; str* realm; str user_name; struct sip_uri puri; struct to_body* from; #ifdef _OBSO char nullcode="00000"; char ccode[6]; char *c; #endif send=NULL; if (skip_cancel(rq)) return 1; attr_cnt=fmt2strar( RAD_ACC_FMT, rq, to, phrase, &dummy_len, &dummy_len, val_arr, atr_arr); if (attr_cnt!=(sizeof(RAD_ACC_FMT)-1)) { LOG(L_ERR, "ERROR: acc_rad_request: fmt2strar failed\n"); goto error; } av_type=rad_status(rq, phrase); if (!rc_avpair_add(rh, &send, attrs[A_ACCT_STATUS_TYPE].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add STATUS_TYPE\n"); goto error; } av_type=vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add STATUS_TYPE\n"); goto error; } av_type=phrase2code(phrase); /* status=integer */ /* if (phrase.len<3) c=nullcode; else { memcpy(ccode, phrase.s, 3); ccode[3]=0;c=nullcode;} */ if (!rc_avpair_add(rh, &send, attrs[A_SIP_RESPONSE_CODE].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add RESPONSE_CODE\n"); goto error; } av_type=rq->REQ_METHOD; if (!rc_avpair_add(rh, &send, attrs[A_SIP_METHOD].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add SIP_METHOD\n"); goto error; } /* Handle User-Name as a special case */ user=cred_user(rq); /* try to take it from credentials */ if (user) { realm = cred_realm(rq); if (realm) { user_name.len = user->len+1+realm->len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_rad_request: no memory\n"); goto error; } memcpy(user_name.s, user->s, user->len); user_name.s[user->len] = '@'; memcpy(user_name.s+user->len+1, realm->s, realm->len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); pkg_free(user_name.s); goto error; } pkg_free(user_name.s); } else { user_name.len = user->len; user_name.s = user->s; if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); goto error; } } } else { /* from from uri */ if (rq->from && (from=get_from(rq)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "ERROR: acc_rad_request: Bad From URI\n"); goto error; } user_name.len = puri.user.len+1+puri.host.len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_rad_request: no memory\n"); goto error; } memcpy(user_name.s, puri.user.s, puri.user.len); user_name.s[puri.user.len] = '@'; memcpy(user_name.s+puri.user.len+1, puri.host.s, puri.host.len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); pkg_free(user_name.s); goto error; } pkg_free(user_name.s); } else { user_name.len = na.len; user_name.s = na.s; if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); goto error; } } } /* Remaining attributes from rad_attr vector */ for(i=0; i<attr_cnt; i++) { if (!rc_avpair_add(rh, &send, attrs[rad_attr[i]].v, val_arr[i]->s,val_arr[i]->len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %s\n", attrs[rad_attr[i]].n ); goto error; } } if (rc_acct(rh, SIP_PORT, send)!=OK_RC) { LOG(L_ERR, "ERROR: acc_rad_request: radius-ing failed\n"); goto error; } rc_avpair_free(send); return 1; error: rc_avpair_free(send); return -1; }
/* create an array of str's for accounting using a formatting string; * this is the heart of the accounting module -- it prints whatever * requested in a way, that can be used for syslog, radius, * sql, whatsoever * tm sip_msg_clones does not clone (shmmem-zed) parsed fields, other then Via1,2. Such fields clone now or use from rq_rp */ static int fmt2rad(char *fmt, struct sip_msg *rq, str* ouri, struct hdr_field *to, unsigned int code, VALUE_PAIR** send, time_t req_time) /* Timestamp of the request */ { static unsigned int cseq_num, src_port, src_ip; static time_t rq_time, rs_time; int cnt; struct to_body* from, *pto; str val, *cr, *at; struct cseq_body *cseq; struct attr* attr; int dir; cnt = 0; dir = -2; /* we don't care about parsing here; either the function * was called from script, in which case the wrapping function * is supposed to parse, or from reply processing in which case * TM should have preparsed from REQUEST_IN callback. */ while(*fmt) { if (cnt == ALL_LOG_FMT_LEN) { LOG(L_ERR, "ERROR:acc:fmt2rad: Formatting string is too long\n"); return 0; } attr = 0; switch(*fmt) { case 'a': /* attr */ at = print_attrs(avps, avps_n, 0); if (at) { attr = &attrs[A_SER_ATTR]; val = *at; } break; case 'c': /* sip_callid */ if (rq->callid && rq->callid->body.len) { attr = &attrs[A_ACCT_SESSION_ID]; val = rq->callid->body; } break; case 'd': /* to_tag */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) { attr = &attrs[A_SIP_TO_TAG]; val = pto->tag_value; } } else { if (rq->from && (from = get_from(rq)) && from->tag_value.len) { attr = &attrs[A_SIP_TO_TAG]; val = from->tag_value; } } break; case 'f': /* sip_from */ if (rq->from && rq->from->body.len) { attr = &attrs[A_SER_FROM]; val = rq->from->body; } break; case 'g': /* flags */ attr = &attrs[A_SER_FLAGS]; val.s = (char*)&rq->flags; val.len = sizeof(unsigned int); break; case 'i': /* inbound_ruri */ attr = &attrs[A_SER_ORIGINAL_REQUEST_ID]; val = rq->first_line.u.request.uri; break; case 'm': /* sip_method */ attr = &attrs[A_SIP_METHOD]; val = rq->first_line.u.request.method; break; case 'n': /* sip_cseq */ if (rq->cseq && (cseq = get_cseq(rq)) && cseq->number.len) { attr = &attrs[A_SIP_CSEQ]; str2int(&cseq->number, &cseq_num); val.s = (char*)&cseq_num; val.len = sizeof(unsigned int); } break; case 'o': /* outbound_ruri */ attr = &attrs[A_SIP_TRANSLATED_REQUEST_ID]; val = *ouri; break; case 'p': /* Source IP address */ attr = &attrs[A_SIP_SOURCE_IP_ADDRESS]; src_ip = ntohl(rq->rcv.src_ip.u.addr32[0]); val.s = (char*)&src_ip; val.len = sizeof(src_ip); break; case 'r': /* from_tag */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (rq->from && (from = get_from(rq)) && from->tag_value.len) { attr = &attrs[A_SIP_FROM_TAG]; val = from->tag_value; } } else { if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) { attr = &attrs[A_SIP_FROM_TAG]; val = pto->tag_value; } } break; case 's': /* server_id */ attr = &attrs[A_SER_SERVER_ID]; val.s = (char*)&server_id; val.len = sizeof(int); break; case 't': /* sip_to */ if (to && to->body.len) { attr = &attrs[A_SER_TO]; val = to->body; } break; case 'u': /* digest_username */ cr = cred_user(rq); if (cr) { attr = &attrs[A_SER_DIGEST_USERNAME]; val = *cr; } break; case 'x': /* request_timestamp */ attr = &attrs[A_SER_REQUEST_TIMESTAMP]; rq_time = req_time; val.s = (char*)&rq_time; val.len = sizeof(time_t); break; case 'D': /* to_did */ break; case 'F': /* from_uri */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (rq->from && (from = get_from(rq)) && from->uri.len) { attr = &attrs[A_CALLING_STATION_ID]; val = from->uri; } } else { if (rq->to && (pto = get_to(rq)) && pto->uri.len) { attr = &attrs[A_CALLING_STATION_ID]; val = pto->uri; } } break; case 'I': /* from_uid */ if (get_from_uid(&val, rq) < 0) { attr = &attrs[A_SER_FROM_UID]; } break; case 'M': /* from_did */ break; case 'P': /* Source port */ attr = &attrs[A_SIP_SOURCE_PORT]; src_port = rq->rcv.src_port; val.s = (char*)&src_port; val.len = sizeof(unsigned int); break; case 'R': /* digest_realm */ cr = cred_realm(rq); if (cr) { attr = &attrs[A_SER_DIGEST_REALM]; val = *cr; } break; case 'S': /* sip_status */ attr = &attrs[A_SIP_RESPONSE_CODE]; val.s = (char*)&code; val.len = sizeof(unsigned int); break; case 'T': /* to_uri */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (rq->to && (pto = get_to(rq)) && pto->uri.len) { attr = &attrs[A_CALLED_STATION_ID]; val = pto->uri; } } else { if (rq->from && (from = get_from(rq)) && from->uri.len) { attr = &attrs[A_CALLED_STATION_ID]; val = from->uri; } } break; case 'U': /* to_uid */ if (get_from_uid(&val, rq) < 0) { attr = &attrs[A_SER_TO_UID]; } break; case 'X': /* response_timestamp */ attr = &attrs[A_SER_RESPONSE_TIMESTAMP]; rs_time = time(0); val.s = (char*)&rs_time; val.len = sizeof(time_t); break; default: LOG(L_CRIT, "BUG:acc:fmt2rad: unknown char: %c\n", *fmt); return -1; } /* switch (*fmt) */ if (attr) { if (!rc_avpair_add(rh, send, ATTRID(attr->v), val.s, val.len, VENDOR(attr->v))) { LOG(L_ERR, "ERROR:acc:fmt2rad: Failed to add attribute %s\n", attr->n); return -1; } } fmt++; cnt++; } /* while (*fmt) */ return 0; }