示例#1
0
/*
 * 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;
}
示例#2
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;
}
示例#3
0
文件: acc.c 项目: OPSF/uClinux
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;
}
示例#4
0
文件: acc.c 项目: OPSF/uClinux
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;
}
示例#5
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 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;
}