Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 08 Jul 1998 16:15:10 +0100
From:      Damian Hamill <damian@cablenet.net>
To:        Terry Lambert <tlambert@primenet.com>, freebsd-isp@FreeBSD.ORG
Subject:   Re: SASL References
Message-ID:  <35A38CFE.FCF07ABF@cablenet.net>
References:  <199807071823.LAA18971@usr01.primenet.com>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------F0E7820B0AA8AE204326DE3B
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Terry Lambert wrote:
> 

> > We experimented with DDNS for some time with our radius server doing
> > the updates but in the end we patched sendmail to get the address of a
> > customer's host from a database that the radius server maintained.
> >
> > The patches to both the radius server and to sendmail are simple.
> 
> Are they available for reference?

I'll include some attachements below.  They will need work to integrate
into your mail server but you will get the idea. 

The sendmail diff file is against version 8.9b3.  Both files contain
references to some other functions which you can replace with your own
versions (or download my Vdb package from the MySQL site and it's
mirrors).

> 
> In general, the reason I was leaning toward pottung the code in the
> radiusd, instead of in the radiusd and the mail server, is to reduce
> the number of changes.  There are a *lot* of third party mail servers
> out there (surprising as that seems).

We did it as an internal requirement and we were only using sendmail.
It has meant tracking new releases of sendmail but it hasn't been too
difficult.  We were going to patch the mail server anyway to stop it
trying to connect to hosts that were offline.  It was just a little bit
more work to get the IP address from an SQL table.

> 
> What problems were you thinking of, in particular?  Unless you had
> a malfunction, there's really little reason that the DNS database
> couldn't be the "database maintained by the radius server".

I found the dynamic DNS to be unreliable and the version of bind that
we are using would fall over if a secondary forwarded it an update
query.  It was much less work patching sendmail than it was to get the
dynamic DNS working.  

If a delete doesn't happen then when another host gets the same IP
address it will start to get the previous hosts email.  Remember the
DNS updates (and the Radius accounting requests) are via UDP, an
unreliable protocol.  Using SQL (via TCP or Domain socket) the whole
process is much reliable.  What's more if a delete is missed then the
DNS mapping will hang around, unless you periodically restart your name
server (which I ended up doing - at which point I realised it was the
wrong way to solve the problem).

regards
damian

-- 
*    Damian Hamill   M.D.       damian@cablenet.net
* CableNet & The Landscape Channel
* http://www.cablenet.net/   http://www.landscapetv.com/
--------------F0E7820B0AA8AE204326DE3B
Content-Type: text/plain; charset=us-ascii; name="sendmail-daemon.c.diffs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sendmail-daemon.c.diffs"

810,814d809
< /*-- Cablenet Begin *********/
< 	u_long  al, dl;
< 	char    qbuf[1024], *fldv[1], login[64], domain[256], hostbuf[32], *p;
< 	extern SOCKADDR dummy_ip;
< /*-- Cablenet End *********/
829,903d823
< /*-- Cablenet Begin *********/
< 	/* if we can find it in the online database then set up host to the
< 	   char representation of the IP address 
< 	   break the host into login and domain parts
< 	   if the domain isn't our domain then carry on as normal
< 	 */
< 
< 	strcpy(domain, LowerStr(host));
< 
< 	if (tTd(16, 1))
< 	    syslog(LOG_INFO,"makeconnection: to %s ",domain);
< 
< 	if ((p = strchr(domain, '.')) != NULL) {
< 	    *p = '\0';
< 
< 	    strcpy(login, domain);
< 
< 	    strcpy(domain, p +1);
< 
< 	    if (domain[strlen(domain) -1] == '.')
< 		domain[strlen(domain) -1] = '\0';
< 
< 	} else
< 	    domain[0] = '\0';
< 
< 	if ( domain[0] && strcmp(domain, dflt_domain) == 0) {
< 	  int    num;
< 
< 	    /* if this is a local domain then they must be in the online
< 	       database to continue */
< 
< 	    /* connect to the dns sql engine */
< 
< 	    if (dnshandle < 0) {
< 		if ((dnshandle = ConnectSql(dns_host, dns_dbase)) < 0) {
< 
< 		    /* the only way to handle this is to post an error to 
< 		       syslog and fail */
< 
< 		    syslog( LOG_ERR, "couldn't open dns database for %s", 
< 			   Vusrmsg );
< 
< 		    return EX_TEMPFAIL;
< 		} 
< 	    }
< 
< 	    sprintf(qbuf, 
< 		    "select ipaddr from online where login = '%s'", 
< 		    login );
< 
< 	    num = 1;
< 	    if ( VdbQuery(dnshandle, qbuf) == 0 &&
< 		VdbFirstRec(dnshandle, &fldv[0], &num ) == 0)
< 	    {
< 		sprintf(hostbuf, "[%s]", fldv[0] );
< 
< 		if (tTd(16, 1))
< 		    syslog(LOG_INFO,
< 			   "found IP address %s for %s from online table\n",
< 			   hostbuf, host );
< 
< 		host = hostbuf;
< 
< 		DisconnectSql();
< 
< 	    } else {
< 
< 		DisconnectSql();
< 
< 		return EX_TEMPFAIL;
< 	    }
< 
< 	}
< /*-- Cablenet End *********/
< 
1009,1037d928
< 
< /*-- Cablenet Begin *********/
< 	/* if this is the dummy IP address for the ISP 
< 	   then just return fail */
< 	
< 	/* compare dummy_ip_address with
< 	   the address we are going to connect to */
< 
< 	al = addr.sin.sin_addr.s_addr;
< 	dl = dummy_ip.sin.sin_addr.s_addr;
< 
< #ifdef IPv6
< #ifdef NETINET
< 	if ( bcmp(&dummy_ip.sin.sin_addr.s_addr, 
< 		  &addr.sin.sin_addr.s_addr,
< 		  sizeof (addr.sin.sin_addr.s_addr)) == 0) 
< #else
< 	if ( bcmp(&dummy_ip.sa.sa_data,
< 		  &addr.sa.sa_data,
< 		  sizeof (addr.sa.sa_data)) == 0) 
< 
< #endif
< #else
< 	if ( al == dl)
< #endif
< 	{
< 	    return (EX_TEMPFAIL);
< 	}
< /*-- Cablenet End *********/

--------------F0E7820B0AA8AE204326DE3B
Content-Type: text/plain; charset=us-ascii; name="radacct.extra"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="radacct.extra"


/****************
include in acct.c
**********/

int
CableNetStart(char *login, char *ipaddr, time_t t)
{
    char    qbuf[512], msg[512], sbuf[1024], *fldv[3];
    int     num, child_pid;

    /* connect to the dns sql engine */
    if (dnshandle < 0) {
	if ((dnshandle = ConnectSql(dns_host, dns_dbase)) < 0) {

	    sprintf(msg, "CableNetStart can't connect to dns\n");
	    log_err(msg);
	    syslog(LOG_ERR, "CableNetStart can't connect to dns\n");
	
	    return -1;

	}
    }

    /* remove any old entry from the online table */
    /* make sure no records are hanging around for any old ip address */

    sprintf(qbuf, "delete from online where ipaddr = '%s' or login = '%s'",
	    ipaddr,login );

    if (VdbQuery(dnshandle, qbuf) < 0) {
	DisconnectSql();
	return -1;
    }

    sprintf(qbuf, "insert into online (login,ipaddr,start) values('%s','%s',%ld)",
	    login, ipaddr, t );
    
    if (VdbQuery(dnshandle, qbuf) < 0) {
	syslog( LOG_ERR, "error inserting into database >>%s<< [%s]", 
	       qbuf, Vdbmsg);

	DisconnectSql();
	return -1;
    }

finish_ok:
    
    DEBUG("login user %s ipaddr: %s\n", login, ipaddr );

    syslog(LOG_NOTICE, "login user %s ipaddr: %s\n", login, ipaddr );

    /* now do things like punt the mail to the user */
    /* fork a child to do the work */

    child_pid = fork();
    if(child_pid < 0) {
	sprintf(msg, "Fork failed for %s [%s]", login, ipaddr );
	log_err(msg);
    }


    if (child_pid == 0) {
	/* This is the child, do the work */
	sprintf(sbuf, "%s/bin/logonuser %s %s", csms_base, login, ipaddr);

	system(sbuf);

	exit(0);
    }

    return 0;
}


int
CableNetStop(char *login, char *ipaddr, int inoct, 
	     int outoct, time_t t, int session_time)
{
    char    qbuf[512], msg[512], *fldv[1];
    char    sbuf[1024];
    int     num;

    /* connect to the accounts sql engine */
    if (accthandle < 0) {
	if ((accthandle = ConnectSql(acct_host, acct_dbase)) < 0) {

	    sprintf(msg, "CableNetStop can't connect to acct\n");
	    log_err(msg);
	  
	    return -1;
	}
    }

    DEBUG("logoff user %s\n", login );

    /* connect to the dns sql engine */
    if (dnshandle < 0) {
	if ((dnshandle = ConnectSql(dns_host, dns_dbase)) < 0) {
		
	    sprintf(msg, "CableNetStop can't connect to dns\n");
	    log_err(msg);
	    
	    return -1;
	}
    }

    sprintf(qbuf, "delete from online where ipaddr = '%s'", ipaddr );

    if (VdbQuery(dnshandle, qbuf) < 0) {
	DisconnectSql();
	return -1;
    }

    DisconnectSql();

    return 0;
}


int
DoCableNetAccounting(authreq)
AUTH_REQ	*authreq;
{
    char    login[64], ipaddrbuf[64];
    int     session_time = 0, status_type = 0, in_octets = 0;
    int     out_octets = 0;
    time_t  t;
    VALUE_PAIR	*pair;

    t = time((time_t *)NULL);

    /*
        Acct-Status-Type = Stop
        Acct-Session-Time = 304
        Acct-Authentic = RADIUS
        Acct-Input-Octets = 4877
        Acct-Output-Octets = 1174
        Acct-Delay-Time = 357

        User-Service-Type = Framed-User

        Framed-Protocol = PPP
	Framed-Address = <ipaddr>

        User-Name = "snor"

	*/

    login[0] = '0';
    ipaddrbuf[0] = '\0';

    pair = authreq->request;
    while(pair != (VALUE_PAIR *)NULL) {

	switch(pair->type) {

	case PW_TYPE_STRING:
	    if (strncmp(pair->name, "User-Name", 9) == 0) {
		strncpy(login, pair->strvalue, 63);
		StripLTBlanks(login);
	    }
	
	    break;
			
	case PW_TYPE_INTEGER:
	    if (strncmp(pair->name, "Acct-Session-Time", 16) == 0) {

		session_time = pair->lvalue;
		t -= session_time;

	    } else if (strncmp(pair->name, "Acct-Status-Type", 16) == 0) {

		status_type = pair->lvalue;

	    } else if (strncmp(pair->name, "Acct-Input-Octets", 16) == 0) {

		in_octets = pair->lvalue;

	    } else if (strncmp(pair->name, "Acct-Output-Octets", 16) == 0) {

		out_octets = pair->lvalue;

	    } else if (strncmp(pair->name, "Acct-Delay-Time", 15) == 0) {

		t -= pair->lvalue;

	    }

	    break;

	case PW_TYPE_IPADDR:
	    if (strncmp(pair->name,"Framed-Address",14) == 0) { 
		ipaddr2str(ipaddrbuf, pair->lvalue);
	    }
	    break;

	}


	pair = pair->next;
    }
	
    if ( login[0] == '\0' || ipaddrbuf[0] == '\0')
	return -1;

    switch (status_type) {

    case PW_STATUS_START:
	CableNetStart(login,ipaddrbuf,t);
	break;
    case PW_STATUS_STOP:
	CableNetStop(login,ipaddrbuf,in_octets,
			    out_octets, t, session_time);
	break;
    }

    return 0;
}


/********************
   in rad_accounting() 
**********/


	if((namepair == (VALUE_PAIR *)NULL) || 
	   (strlen(namepair->strvalue) <= 0)) {
		sprintf(msg, "Accounting: from %s - No User Name\n",
			ip_hostname(authreq->ipaddr));
		log_err(msg);
		pairfree(authreq->request);
		memset(authreq, 0, sizeof(AUTH_REQ));
		free(authreq);
		return;
	}

+    	/* try to save this accounting information for CableNet users */
+	DoCableNetAccounting(authreq);
+
	/*
	 * Create a directory for this client.
	 */
	sprintf(buffer, "%s/%s", radacct_dir, clientname);
	mkdir(buffer, 0755);

	/*
	 * Write Detail file.
	 */
	sprintf(buffer, "%s/%s/detail", radacct_dir, clientname);

--------------F0E7820B0AA8AE204326DE3B--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-isp" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?35A38CFE.FCF07ABF>