🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.dcom.sys.cisco
Article #81

Re: Need help with TACACS server code on HP

#81
From: Vikas Aggarwal
Date: Wed, 05 Aug 1992 11:57
1200 lines
31140 bytes
>        tacacsd[13581]: ioctl(FIONBIO): Invalid argument

Funny thing is that it compiled okay...

Anyway, the same kind of functionality can be achieved using the 'recvfrom'
call. My version of xtacacsd is considerably different than perhaps the one
on ftp.cisco.com, so you will have to adapt the following code extract.


 -vikas                                                     (609) 258-2403
 vikas@jvnc.net	                                  ...rutgers!jvncnet!vikas
--------------------------------------------------------------------------


    else	/* if not standalone, under inetd */
    {
	s = 0;
/*	if (ioctl(s, FIONBIO, &blockon) < 0) 
 *	{
 *	    syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
 *	    exit(1);
 *	}
 */
    }


    /*
     * For 4.3BSD machines, this routine sets the file the pw routines use
     * to the given argument. We emulate it for others.
     */

    setpwent() ;			/* open/rewind default /etc/passwd */

    if (wtmpfile != NULL)
      if ((wtmpf = fopen(wtmpfile, "a+")) == NULL)
	fprintf(stderr, "\nCan't open wtmp file \"%s\"", wtmpfile);

    signal (SIGALRM, onalarm);
    lastmsgtime = time(NULL) ;
    alarm(TIMEOUT);

    for ( ; ; )		/* forever */
    {
	fromlen = sizeof(from);
	if (!stand)
	  s = 0 ;
	c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
	if (c <= 0)
	{
	    if (errno == EINTR && stand)
	      continue ;
	    if (errno == EINTR && c == 0)	/* under inetd */
	      continue ;

	    syslog(LOG_ERR, "recvfrom: %m\n");
	    exit(1);				/* some error */
	}
	
	sigblock(1<<SIGALRM) ;			/* block ALARM's */
	lastmsgtime = time(NULL) ;

	if (logging) 
	{
	    if (nonameserver == 0)
	      hp = gethostbyaddr(&from.sin_addr, sizeof (struct in_addr), AF_INET);
	    else
	      hp = NULL ;
	    syslog(LOG_INFO, "main: validation request from %s [%s]",
		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr),
		   (char *)inet_ntoa(from.sin_addr));
#ifdef DEBUG
	    fprintf(stderr, "main: logged validation request\r\n");
#endif
	    
	}	/* end: if logging */
	
	tp = (tacacstype *)buf;
	
	if (tp->version == TA_VERSION)
	  old_process(s, &from, tp);
	else if (tp->version == XTA_VERSION)
	  new_process(s, &from, tp);
	else if (logging)
	  syslog(LOG_INFO,
		 "main: illegal version specified: %d\n", tp->version);
	
	sigsetmask(0) ;				/* allow all signals */

    }		/* end: forever */

    /* NOT REACHED */
    exit(0);

} 		/* end: main */


/*+		onalarm
 * Exit after MAXIDLE secs of inactivity
 */
onalarm()
{
    if (!stand)
      if (time(NULL) - lastmsgtime >= MAXIDLE)
      {
	  if (debug)
	    syslog(LOG_DEBUG,
		   "Inactive for %d secs, tired of hanging around...",
		   MAXIDLE) ;
	  exit (0);
      }

    alarm(TIMEOUT) ;				/* reset alarm */
}			/* onalarm()  */


/*+ pw_verify:
 *
 * 	Verify the provided name/password.
 *	Checks the password supplied by the user in all the supplied passwd
 * filenames (only /etc/passwd if none supplied). The supplied filenames are
 * in 'pwfile'.
 *
 * To prevent password anomalies, does not accept if the password field 
 * is blank in the passwd file (like netmon or nicol). Also, do not accept
 * if the uid is '0'.
 *
 *	Return's 1 if password OK, else '0' and NULLS the 'pw' struct
 */

int pw_verify (name, passwd, ppw)
#ifdef SYSV
    char name[SOME_ARBITRARILY_LARGE_NUMBER];
    char passwd[SOME_ARBITRARILY_LARGE_NUMBER];
#else    
    char *name, *passwd;
#endif
    struct passwd **ppw;

{
    int i = 0 ;
    struct passwd *pw;
    
 nextpwf:			/* for a loop */

#ifdef DEBUG
    fprintf(stderr, "pw_verify: calling setpwent\r\n");
#endif

    if (*pwfile != NULL)
      if (pwfile[i] != NULL)
      {
	  endpwent() ;		/* closes present passwd file */
	  setpwfile(pwfile[i]);	/* changes the current password file */
      }

    setpwent();			/* rewinds  current password file */

#ifdef DEBUG
    fprintf(stderr, "pw_verify: returned from setpwent\r\n");
#endif      
    pw = getpwnam(name);
#ifdef DEBUG
    fprintf(stderr, "pw_verify: returned %x from getpwnam\r\n", pw);
#endif      

#ifdef DEBUG		/* Warning- this prints out the users passwd */
    if (pw)
	fprintf(stderr, "password: user %8.8s, password %13.13s\r\n",
		pw->pw_name, pw->pw_passwd);
#endif

    if (debug && logging && pw)
      syslog(LOG_INFO, "pw_verify: Match for %s found in file %s\n", 
	     pw->pw_name, *pwfile ? pwfile[i] : "/etc/passwd") ;

    /* Verify the entry. No access to uid '0' or blank passwords  */

    if (pw != NULL && *passwd != '\0' && *pw->pw_passwd != '\0' && pw->pw_uid != 0)
    {
#ifdef SYSV
	strcpy(passwd, (char *)crypt(passwd, pw->pw_passwd));
#else
	passwd = (char *)crypt(passwd, pw->pw_passwd);
#endif	
#ifdef DEBUG
	fprintf(stderr, "encrypted: real %s, query %s\r\n",
		pw->pw_passwd, passwd);
#endif
	if (logging && debug)
	  syslog(LOG_DEBUG, "pw_verify: encrypted real %s, query %s\n", 
		 pw->pw_passwd, passwd);
	*ppw = pw;
	if (strcmp(passwd, pw->pw_passwd) == 0)
	    return(1);					/* Okay */
    }

    if (pwfile[++i] != NULL)		/* more passwd files */
      goto nextpwf ;			/* ...and match yet not found */

    /*
     * Here only if no matching password found 
     */
    if (logging)
      syslog(LOG_INFO, "pw_verify: password match failed for user '%s'\n",
	     name);
    *ppw = NULL;			/* set pw to NULL */
    return(0);				/* No match in passwd files */

} 		/* end: pw_verify */



/*+ old_process:
 *
 *    	Perform necessary stuff to do a query. Return ANSWER
 */

void old_process(s, client, tp)
    int s;
    struct sockaddr_in *client;
    tacacstype *tp;
{
#ifdef SYSV
    char name[SOME_ARBITRARILY_LARGE_NUMBER];
    char passwd[SOME_ARBITRARILY_LARGE_NUMBER];
#else    
    char *name, *passwd;
#endif
    struct passwd *pw;
    int expired;
#ifdef TOLOWER
    register char *p ;
    register i ;

    p = (char *)(tp + 1);			/* move past header */
    for (i = 0; i < tp->namelen; ++i, ++p)	/* reduce name to lower case */
      *p = tolower(*p) ;
#endif	/* TOLOWER */

    querytime = time(NULL);

#ifdef DEBUG
    fprintf(stderr, "old_process: starting\r\n");
    fprintf(stderr, "old_process: namelen %d, pwdlen %d\r\n",
	    tp->namelen, tp->pwlen);
#endif
#ifndef SYSV    
    name = (char *)malloc(tp->namelen+1); 
#ifdef DEBUG
    fprintf(stderr, "old_process: malloc returned (name)\r\n");
    if (name == NULL)
      fprintf(stderr, "old_process: malloc failed on name (%d bytes)\r\n",
	    tp->namelen+1);
#endif      
    passwd = (char *)malloc(tp->pwlen+1);
#ifdef DEBUG
    if (passwd == NULL)
      fprintf(stderr, "old_process: malloc failed on passwd (%d bytes)\r\n",
	      tp->pwlen+1);
#endif      
    if (name == NULL || passwd == NULL)
	return;
#endif /* not SYSV */



    strncpy(name, (char *)(tp + 1), tp->namelen);
    name[tp->namelen] = '\0';
    strncpy(passwd, (char *)(tp + 1) + tp->namelen, tp->pwlen);
    if (tp->pwlen > PASSWD_LENGTH)
	tp->pwlen = PASSWD_LENGTH;
    passwd[tp->pwlen] = '\0';

#ifdef DEBUG
    fprintf(stderr, "packet: %s %s\r\n", (char *)(tp + 1),
	    (char *)(tp + 1) + tp->namelen);
    fprintf(stderr, "local:  %s %s\r\n", name, passwd);
#endif

    /* Assume failure */

    tp->oresponse = TA_A_REJECTED;
    tp->oreason = TA_A_DENIED;
    if (pw_verify(name, passwd, &pw)) 		/* verify the password */
    {
	tp->oresponse = TA_A_ACCEPTED;
	tp->oreason = TA_A_NONE;
	
	/*
	 * Now check the expiration time.
	 */
	
	expired = check_expiration(pw->pw_shell);
	if (expired == 2)
	{
	    tp->oresponse = TA_A_DENIED;
	    tp->oreason = TA_A_EXPIRING;
	} 
	else if (expired == 1)
	  tp->oreason = TA_A_EXPIRING;

	/*
	 * Now check the GID. The GID can control a lot,,,
	 */

	if (pw != NULL && check_gid (pw) != 0)		/* deny */
	{
	    tp->oresponse = TA_A_DENIED;
	    tp->oreason = TA_A_DENIED;

	}

    }

#ifdef DEBUG
    fprintf(stderr, "old_process: logging query result\r\n");
#endif

    if (logging) 
    {
	if (pw != NULL)
	  syslog(LOG_INFO, "old_process: login query for %s (%.10s ..) %s\n",
		 name, pw->pw_gecos,
		 tp->oresponse == TA_A_ACCEPTED ? "accepted" : "rejected");
	else
	  syslog(LOG_NOTICE, "old_process: login query for %s %s\n", name,
		 tp->oresponse == TA_A_ACCEPTED ? "accepted" : "rejected");
    }

    tp->type = TA_ANSWER;

    if (quiet && tp->oresponse != TA_A_ACCEPTED)	/* don't respond */
    {
	if (logging)
	  syslog(LOG_INFO, "old_process: not sending DENIED since quiet\n");
    }
    else
    {
#ifdef DEBUG
	fprintf(stderr, "old_process: sending query result to client\r\n");
#endif
	if (sendto(s, buf, sizeof(tacacstype), 0, client,
		   sizeof(struct sockaddr_in)) != sizeof(tacacstype))
	  syslog(LOG_ERR, "write: %m\n");
    }
#ifndef SYSV
    free(name);
    free(passwd);
#endif    
#ifdef DEBUG
    fprintf(stderr, "old_process: done\r\n");
#endif

} 		/* end:  old_process */




/*+ new_process:
 *
 * 	Perform necessary stuff to do a query operation. Return ANSWER.
 */

void new_process (s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;
{
#ifdef TOLOWER
    register char *p ;
    register i ;

    p = ((char *)tp) + XTACACSSIZE;		/* move past header */
    for (i = 0; i < tp->namelen; ++i, ++p)	/* reduce name to lower case */
      *p = tolower(*p) ;
#endif	/* TOLOWER */

#ifdef DEBUG
    fprintf(stderr, "new_process: start\r\n");
    if (logging)
      syslog(LOG_DEBUG, "new_process: Querytype %d for '%.*s'", tp->type,
	     tp->namelen, ((char *)tp) + XTACACSSIZE ) ;
#endif

  querytime = time(NULL);

  switch (tp->type) 
  {
     case XTA_SLIPADDR:
     case XTA_LOGIN:
                	xlogin(s, client, tp);
                	break;
      case XTA_CONNECT: 
			xconnect(s, client, tp);
                	break;
      case XTA_ENABLE: 
			xenable(s, client, tp);
			break;
      case XTA_LOGOUT:
			xlogout(s, client, tp);
			break;
      case XTA_RELOAD:
			xreload(s, client, tp);
			break;
      case XTA_SLIPON:
			xslipon(s, client, tp);
			break;
      case XTA_SLIPOFF:
			xslipoff(s, client, tp);
			break;
      default:
	if (logging)
	  syslog(LOG_INFO, "new_process: illegal type specified: %d",tp->type);

   }	/* end switch */
}	/* end new_process */




/*+ check_expiration:
 * 
 *	Returns 0 if OK, 1 if warning, 2 if expired
 */

int check_expiration(date)
     char *date;
{
    long day, month, year, leaps, now, expiration, warning;
    char monthstr[10];

    /* If no date or a shell, let it pass.  (Backward compatability.) */

    if (!date || (strlen(date) == 0) || (*date == '/'))
	return(0);
    
    /* Parse date string.  Fail it upon error.  */

    if (sscanf(date, "%s %d %d", monthstr, &day, &year) != 3)
      return(2);

    /* Compute the expiration date in days.  */

    for (month = 0; month < 12; month++)
	if (strncmp(monthstr, monthname[month], 3) == 0)
	    break;
    if (month > 11)
	return(2);
    leaps = (year-1969)/4 + (((year % 4) == 0) && (month > 2));
    expiration = (((year-1970)*365) + days_ere_month[month] + (day-1) + leaps);
    warning = expiration - WARNING_PERIOD;

    /*
     * Get the current time (to the day)
     */
    now = querytime/SEC_IN_DAY;
    
    if (now > expiration)
	return(2);
    if (now > warning)
	return(1);
    return(0);

} 	/* end: check_expiration() */



/*
 * check_gid:
 *
 * Checks the pw->gid field. See discussion above on what all the GID
 * can/is used for.
 * Ignores #logins if the last digit is zero.
 * Looks in the UTMP file (not the WTMP file)
 *
 * Returns '0' if OK.
 */

check_gid(pw)
     struct passwd *pw ;
{
    int lgid, ugid, gid, current_logins = 0;
    int status = 0 ;	    	/* Return status, set to OK */
    struct utmp entry ;
    register FILE *f ;		/* for the utmp file  */

    gid = (int)pw->pw_gid ;
    bzero(&entry, sizeof entry);

#ifdef L_DENY_GID
#ifdef U_DENY_GID

    lgid = L_DENY_GID ; ugid = U_DENY_GID ;
    if (gid >= lgid && gid <= ugid)
      status = 1 ;			/* deny permission */

    if (logging)
    {
	if (status)
	  syslog (LOG_INFO, "check_gid: gid %d matches DENY_GID\n", gid) ;
	else if (debug)
	  syslog (LOG_DEBUG,
		  "check_gid: Checking 'DENY' limits for gid %d (%d <> %d)\n",
		  gid, lgid, ugid) ;
    }
#endif	/* U_DENY_GID */
#endif	/* L_DENY_GID */

    if (status)
      return (status) ;

#ifdef  L_NUMLOGINS_GID
#ifdef  U_NUMLOGINS_GID

    lgid = L_NUMLOGINS_GID ; ugid = U_NUMLOGINS_GID ;

    if (gid >= lgid && gid <= ugid)	/* check for number of logins */
      if ((gid = pw->pw_gid % 10))	/* grab the last digit, ignore 0 */
      {
	  /*
	   * Now find out the number of logins in the utmp file
	   */

	  if ((f = fopen(utmpfile, "r")) == NULL)
	  {
	      syslog(LOG_ERR, "check_gid: Cannot open utmp file- %s\n",
		     utmpfile);
	      return (1);		/* Cannot open file, deny */
	  }

	  while (fread((char *)&entry, sizeof(entry), 1, f) == 1) 
	  {
	      if (strcmp(entry.ut_name, pw->pw_name))	/* no match */
		continue;
	      else
		++current_logins ;
	  }
	  fclose (f);

#ifdef DEBUG
	  fprintf(stderr, "check_gid: current logins= %d, allowed= %d\n",
		  current_logins, gid);
#endif

	  if ( current_logins > gid )
	    status = 2 ;		/* Exceeded logins */

	  if (logging && (status || debug))
	    syslog(LOG_INFO,
		   "check_gid: current logins= %d, allowed= %d",
		   current_logins, gid);
      }
#endif /*  U_NUMLOGINS_GID */
#endif /*  L_NUMLOGINS_GID */

    return (status) ;

}		/* end: check_gid() */


#ifndef BSD43

/*+ setpwfile:
 *
 * Hack to get around the default for the pw routines using /etc/passwd
 */

#include <sys/stat.h>

void setpwfile (file)
    char *file;

{

    FILE *f;
    struct stat pwbuf, fbuf;
    int i;
    char *c;

    if (stat("/etc/passwd", &pwbuf) < 0) {
	syslog(LOG_ERR, "setpwfile (stat): %m\n");
	exit(1);
    }

    setpwent();				/* open /etc/passwd */

    /*
     * This loop assumes that the stdio file buffers are contiguous
     * which isn't true for 4.3, but then we won't be here.
     */

    for (f = stderr + 1; f < stdin + getdtablesize(); f++)
        if (f->_flag & (_IOREAD|_IOWRT|_IORW) &&
	    fstat(fileno(f), &fbuf) >= 0 &&
	    pwbuf.st_dev == fbuf.st_dev &&
	    pwbuf.st_ino == fbuf.st_ino) {
	    freopen(file, "r", f);
	    fprintf(stderr, "hit at %d\n", fileno(f));
	    return;
	}

    syslog(LOG_ERR, "setpwfile: couldn't find /etc/passwd to replace");
    exit(1);
}
#endif	/* BSD43 */


#ifdef SYSV
getdtablesize()
{
  return(_NFILE);
}
#endif



/*+ wtmp_entry:
 *
 * Updates the main 'wtmpfile' and also the terminal server specific ones.
 * Since this is also called by 'slipOn' and 'slipOff' with line types
 * of SLIP_TTY, put those entries in the 'WTMP.slip' file.
 *
 * For other names, it updates a wtmp file of the form 'WTMP.hostname'
 *
 */

void wtmp_entry (line, name, host)
     char *line ;			/* Incoming line for user */
     char *name;			/* User's login name */
     char *host ;			/* The name/ip of the host */
{
    char wfile[BUFSIZ] ;		/* alternate file to update */
    FILE *wf ;
    struct utmp entry;

    if (wtmpf == NULL)			/* main wtmp file should exist */
	return;

    bzero(&entry, sizeof entry);

    if (strlen(line) < sizeof entry.ut_line)
	strcpy(entry.ut_line, line);
    else bcopy(line, entry.ut_line, sizeof entry.ut_line);

    if (strlen(name) < sizeof entry.ut_name)
	strcpy(entry.ut_name, name);
    else bcopy(name, entry.ut_name, sizeof entry.ut_name);

    if (strlen(host) < sizeof entry.ut_host)
	strcpy(entry.ut_host, host);
    else bcopy(host, entry.ut_host, sizeof entry.ut_host);

    entry.ut_time = querytime;

#ifdef DEBUG1
    fprintf(stderr, "\nwtmp: %s, %s %s %d", line, name, host, querytime);
#endif


    if (fwrite(&entry, sizeof entry, 1, wtmpf) != 1) {
	syslog(LOG_ERR, "wtmp_entry: couldn't write wtmp file- %s", 
	       wtmpfile);
    }
    else
      fflush(wtmpf);


    if (wtmpfile != NULL)		/* The 'prefix' for alternate file */
      strcat(strcpy(wfile, wtmpfile), ".") ;

    /*
     * Check and update the 'slip' wtmp file if line type is SLIP_TTY
     */
    if (strncmp(line, SLIP_TTY, strlen(SLIP_TTY)) == 0)
      strcat(wfile, "slip") ;		/* create unique '.slip' file */

    else				/* create a sensible filename */
    {
	if (*host < '0' || *host > '9')		/* Not an IP address,,, */
	  strncat(wfile, host, strcspn(host, ".")) ;	/* only header */
	else
	  strncat(wfile, host, strlen(host)) ;

	wfile[sizeof(wfile)] = '\0';		/* terminating NULL */
    }

    if ((wf = fopen(wfile, "a+")) == NULL)
    {
	syslog(LOG_ERR, "wtmp_entry: couldn't open wtmp- %s", wfile);
	return ;
    }

    if (fwrite(&entry, sizeof entry, 1, wf) != 1)
      syslog(LOG_ERR, "wtmp_entry: couldn't write wtmp file- %s", wfile);
    else
    {
	fflush(wf);		/* close the alternate wtmp file */
	fclose(wf) ;
    }

}	/* end: wtmp_entry */


/*+ xlogin:
 *
 * 	Called by new_process(). Checks password of user against all the
 * password files. Routine very similar to the 'old_process()' function.
 * Calls wtmp_entry() to make an entry in the wtmp file.
 */

void xlogin (s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;
{

#ifdef SYSV
    char name[SOME_ARBITRARILY_LARGE_NUMBER];
    char passwd[SOME_ARBITRARILY_LARGE_NUMBER];
#else    
    char *name, *passwd;
#endif
    struct passwd *pw;
    int expired;
    char linename[20];

#ifdef DEBUG
    fprintf(stderr, "xlogin: starting\r\n");
    fprintf(stderr, "xlogin: namelen %d, pwdlen %d\r\n",
	    tp->namelen, tp->pwlen);
#endif
#ifndef SYSV    
    name = (char *)malloc(tp->namelen+1); 
#ifdef DEBUG
    fprintf(stderr, "xlogin: malloc returned (name)\r\n");
    if (name == NULL)
      fprintf(stderr, "xlogin: malloc failed on name (%d bytes)\r\n",
	    tp->namelen+1);
#endif      
    passwd = (char *)malloc(tp->pwlen+1);
#ifdef DEBUG
    if (passwd == NULL)
      fprintf(stderr, "xlogin: malloc failed on passwd (%d bytes)\r\n",
	    tp->pwlen+1);
#endif      

    /*  If no name or no passwd for LOGIN queries, just return */
    if ((name == NULL || passwd == NULL) && (tp->type == XTA_LOGIN))
      return;

#endif /* not SYSV */
    strncpy(name, ((char *)tp) + XTACACSSIZE, tp->namelen);
    name[tp->namelen] = '\0';
    strncpy(passwd, ((char *)tp) + XTACACSSIZE + tp->namelen, tp->pwlen);
    if (tp->pwlen > PASSWD_LENGTH)
      tp->pwlen = PASSWD_LENGTH;
    passwd[tp->pwlen] = '\0';
    sprintf(linename, "%s%o", TS_TTY, tp->lport);

    /*
     * If IP address is default on the terminal servers, then the 'username'
     * will be 'default' for SLIP mode. Set to default for  XTA_SLIP and 
     * reject for XTA_LOGIN.
     */
    if ((strncmp(name,"default",7) == 0) && (tp->type == XTA_SLIPADDR))
      strcpy(passwd, DEFAULTS_IP_PASSWORD);

    if ((strncmp(name,"default",7) == 0) && (tp->type == XTA_LOGIN))
      strcpy(passwd, "*") ;		/* Junk password */

#ifdef DEBUG
    fprintf(stderr, "packet: %s %s\r\n", (char *)(tp + 1),
	    (char *)(tp + 1) + tp->namelen);
    fprintf(stderr, "local:  %s %s\r\n", name, passwd);
#endif
#ifdef DEBUG1
    fprintf(stderr, "\nxlogin: user '%s' on %s, host %s", name, linename,
	    hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));	    
#endif

    /* Assume failure */

    tp->response = TA_A_REJECTED;
    tp->reason = TA_A_DENIED;
    if (pw_verify(name, passwd, &pw)) 
      {
	tp->response = XTA_A_ACCEPTED;
	tp->reason = XTA_A_NONE;
	tp->uuid = pw->pw_uid;
	tp->accesslist = pw->pw_gid;
	tp->flags = xta_getflags(pw->pw_gecos);

	/* Now check the expiration time.  */

	expired = check_expiration(pw->pw_shell);
	if (expired == 2) 
          {
	    tp->response = TA_A_DENIED;
	    tp->reason = TA_A_EXPIRING;
          }
         else
           if (expired == 1)
	     tp->reason = TA_A_EXPIRING;

	 /* Check the GID. */

	if (pw != NULL && check_gid (pw) != 0)		/* deny */
	{
	    tp->response = TA_A_DENIED;
	    tp->reason = TA_A_DENIED;
	}

      }

#ifdef DEBUG
    fprintf(stderr, "xlogin: logging query result\r\n");
#endif
    if (tp->response == TA_A_ACCEPTED && tp->type == XTA_LOGIN)
      wtmp_entry(linename, name,
		 hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr)) ;

    if (logging && tp->type == XTA_LOGIN)
    {
	if (pw != NULL)
	    syslog(LOG_INFO, "xlogin: query from %s %s for %s (%.10s..) %s\n", 
		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr), 
		   linename, name, pw->pw_gecos,
		tp->response == TA_A_ACCEPTED ? "accepted" : "rejected");
	else
	    syslog(LOG_NOTICE, "xlogin: query from %s %s for %s %s\n",
		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr),
		   linename, name,
		   tp->response == TA_A_ACCEPTED ? "accepted" : "rejected");
    }
    if (logging && tp->type == XTA_SLIPADDR) {
	if (pw != NULL)
	    syslog(LOG_INFO,
		   "xlogin: slipaddress from %s %s for %s (%.10s) %s\n", 
		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr), 
		   linename, name, pw->pw_gecos,
		   tp->response == TA_A_ACCEPTED ? "accepted" : "rejected");
	else
	    syslog(LOG_NOTICE, "xlogin: slipaddress from %s %s for %s %s\n",
		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr),
		   linename, name,
		   tp->response == TA_A_ACCEPTED ? "accepted" : "rejected");
    }
    tp->type = TA_ANSWER;
    if (quiet && tp->response != TA_A_ACCEPTED)	/* dont respond */
    {
	if (logging)
	  syslog(LOG_INFO, "xlogin: not sending DENIED since quiet\n");
    }
    else
    {
#ifdef DEBUG
	fprintf(stderr, "xlogin: sending query result to client\r\n");
#endif
	if (sendto(s, buf, sizeof(xtacacstype), 0, client,
		   sizeof(struct sockaddr_in)) != sizeof(xtacacstype))
	  syslog(LOG_ERR, "write: %m\n");
    }

#ifndef SYSV
    free(name);
    free(passwd);
#endif    
#ifdef DEBUG
    fprintf(stderr, "xlogin: done\r\n");
#endif

}		/* end: xlogin()  */



/*+ xconnect:
 *
 *	Called when user connects to a specific host & port.
 */

void xconnect(s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;
{
    struct hostent *hp1;
    char linename[20];
    char *name = ((char *)tp) + XTACACSSIZE;

    name[tp->namelen] = 0;
    sprintf(linename, "%s%o", TS_TTY, tp->lport);
    if ( nonameserver == 0 )
      hp1 = gethostbyaddr(&tp->dhost, sizeof (struct in_addr), AF_INET);
    else
      hp1 = NULL ;

#ifdef DEBUG1
    fprintf(stderr, "\nxconnect: user %.*s(%d) to %s:%d", tp->namelen,
	    ((char *)tp) + XTACACSSIZE, tp->uuid,
	    hp1 ? hp1->h_name : (char *)inet_ntoa(tp->dhost), tp->dport);
#endif
    
    if (logging)
	syslog(LOG_INFO, "xconnect: from %s [%s] %s for %s (%d) to %s:%d\n",
	       hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr),
	       (char *)inet_ntoa(from.sin_addr),
	       linename, name, tp->uuid,
	       hp1 ? hp1->h_name : (char *)inet_ntoa(tp->dhost),
	       tp->dport);
    replyok (s, client, tp);

} 	/* end: xconnect() */



/*+ xenable:
 *
 * 	
 */

void xenable (s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;
{
#ifdef SYSV
    char name[SOME_ARBITRARILY_LARGE_NUMBER];
    char passwd[SOME_ARBITRARILY_LARGE_NUMBER];
#else    
    char *name, *passwd;
#endif
    struct passwd *pw;
    int expired;
    char linename[20];

#ifndef SYSV    
    name = (char *)malloc(tp->namelen+1); 
    passwd = (char *)malloc(tp->pwlen+1);
    if (name == NULL || passwd == NULL)
	return;
#endif /* not SYSV */
    
    sprintf(linename, "%s%o", TS_TTY, tp->lport);
    strncpy(name, (char *)(tp + 1), tp->namelen);
    name[tp->namelen] = '\0';
    strncpy(passwd, (char *)(tp + 1) + tp->namelen, tp->pwlen);
    if (tp->pwlen > PASSWD_LENGTH)
      tp->pwlen = PASSWD_LENGTH;
    passwd[tp->pwlen] = '\0';

#ifdef DEBUG1
    fprintf(stderr, "\nxenable: user %s on %s, host %s", name, linename,
	    hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));	    
#endif

    /*
     * Assume failure
     */

    tp->response = TA_A_REJECTED;
    tp->reason = TA_A_DENIED;
    if (pw_verify("$enable$", passwd, &pw)) 
      {
	tp->response = XTA_A_ACCEPTED;
	tp->reason = XTA_A_NONE;
	tp->uuid = pw->pw_uid;
	tp->accesslist = pw->pw_gid;
	tp->flags = xta_getflags(pw->pw_gecos);

	/* Now check the expiration time.  */

	expired = check_expiration(pw->pw_shell);
	if (expired == 2)
	{
	    tp->response = TA_A_DENIED;
	    tp->reason = TA_A_EXPIRING;
	}
         else if (expired == 1)
	   tp->reason = TA_A_EXPIRING;

	 /* Now check the GID. */

	if (pw != NULL && check_gid (pw) != 0)		/* deny */
	{
	    tp->response = TA_A_DENIED;
	    tp->reason = TA_A_DENIED;

	}

      }

    tp->type = TA_ANSWER;
    if (logging)
	    syslog(LOG_INFO, "xenable: from %s %s for %s %s\n", 
		   hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr), 
		   linename, name,
		tp->response == TA_A_ACCEPTED ? "accepted" : "rejected");
    if (sendto(s, buf, sizeof(xtacacstype), 0, client,
	sizeof(struct sockaddr_in)) != sizeof(xtacacstype))
	syslog(LOG_ERR, "write: %m\n");

#ifndef SYSV
    free(name);
    free(passwd);
#endif    

} 		/* end: xenable()  */



/* xlogout:
 *
 * Called when the user logs out.
 */

void xlogout (s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;
{
    char *name = ((char *)tp) + XTACACSSIZE;
    char linename[20];
    char *reason;

    switch(tp->reason) {
      case XTA_R_IDLE:
	reason = "Idle-timeout";
	break;
      case XTA_R_DROP:
	reason = "Carrier-Drop";
	break;
      case XTA_R_BAD:
	reason = "Bad-Passwords";
	break;
      case XTA_R_QUIT:
	reason = "";
	break;
      default:
	reason = "Unknown-reason";
	break;
    }

    name[tp->namelen] = 0;

#ifdef DEBUG1
    fprintf(stderr, "\nxlogout:  user %s(%d) line %o %s", name, tp->uuid,
	    tp->lport, reason);
#endif
    sprintf(linename, "%s%o", TS_TTY, tp->lport);
    if (logging)
	syslog(LOG_INFO, "xlogout: from %s %s, user %s(%d) %s\n",
	       hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr), linename,
	       name, tp->uuid, reason);
    wtmp_entry(linename, "",
	       hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr)) ;
    replyok (s, client, tp);

}		/* end: xlogout() */


/*+ xreload:
 *
 *	Called when a terminal server is rebooted. It calls wtmp_entry
 * to make an entry similar to the one made when a system reboots. Needed
 * for accounting 'ac'
 */

void xreload(s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;

{
#ifdef DEBUG1
    fprintf(stderr, "\nxreload: host %s",
	    hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
#endif
    if (logging)
	syslog(LOG_NOTICE, "xreload: system reload from %s\n",
	       hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
    wtmp_entry("~", "", hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr)) ;
    replyok (s, client, tp);

}	/* end: xreload */


/*+ xslipon:
 *
 *	Called when a user invokes 'slip'. Makes an entry in wtmp with
 * a tty name of SLIP_TTY and host is the selected SLIP address.
 */

void xslipon(s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;

{
    struct hostent *hp1;
    char linename[20];
    char *name = ((char *)tp) + XTACACSSIZE;

    name[tp->namelen] = 0;
    sprintf(linename, "%s%o", SLIP_TTY, tp->lport);	/* name of line */

    if (nonameserver == 0)
      hp1 = gethostbyaddr(&tp->dhost, sizeof (struct in_addr), AF_INET);
    else 
      hp1 = NULL ;

#ifdef DEBUG1
    fprintf(stderr, "\nxslipon:  user %.*s(%d) on %s slip address %s",
	    tp->namelen, ((char *)tp) + XTACACSSIZE, tp->uuid, linename, 
	    hp1 ? hp1->h_name : (char *)inet_ntoa(&tp->dhost));

#endif
    wtmp_entry(linename, name, (char *)inet_ntoa(&tp->dhost));
    if (logging)
	syslog(LOG_INFO, "xslipon: from %s [%s] (%s) for %s(%d) address %s\n",
	       hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr),
	       (char *)inet_ntoa(from.sin_addr),
	       linename, name, tp->uuid,
	       hp1 ? hp1->h_name : (char *)inet_ntoa(&tp->dhost));

    replyok (s, client, tp);

}		/* end: xslipon */


/*+ xslipoff:
 *
 * 	Called when slip turned off by user. Entry logged in wtmp file
 * with host of the selected SLIP address.
 */

void xslipoff(s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;

{
    struct hostent *hp1;
    char linename[20];
    char *name;

    sprintf(linename, "%s%o", SLIP_TTY, tp->lport);

    if (nonameserver == 0 )
      hp1 = gethostbyaddr(&tp->dhost, sizeof (struct in_addr), AF_INET);
    else 
      hp1 = NULL ;

#ifdef DEBUG1
    fprintf(stderr, "\nxslipoff:  user %.*s(%d) on %s slip address %s",
	    tp->namelen, ((char *)tp) + XTACACSSIZE, tp->uuid, linename,
	    hp1 ? hp1->h_name : (char *)inet_ntoa(&tp->dhost));

#endif
    wtmp_entry(linename, "",  (char *)inet_ntoa(&tp->dhost));
    name = (char *) (((char *)tp) + XTACACSSIZE);
    name[tp->namelen] = 0;    if (logging)
    if (logging)
	syslog(LOG_INFO, "xslipoff: from %s [%s] (%s) for %s(%d) address %s\n",
	       hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr),
	       (char *)inet_ntoa(from.sin_addr),
	       linename, name, tp->uuid,
	       hp1 ? hp1->h_name : (char *)inet_ntoa(&tp->dhost));

    replyok (s, client, tp);

}		/* end: xslipoff() */


xta_getflags (string)
    char * string;
{
    return(0);
}

/*+ replyok:
 *
 *	This function sends an "ok" reply to client (for things like reload,
 * logout). Called by xslipoff()
 *
 */

void replyok (s, client, tp)
    int s;
    struct sockaddr_in *client;
    xtacacstype *tp;

{
    tp->response = XTA_A_ACCEPTED;
    tp->reason = XTA_A_NONE;
    tp->type = TA_ANSWER;
    if (sendto(s, buf, sizeof(xtacacstype), 0, client,
	       sizeof(struct sockaddr_in)) != sizeof(xtacacstype))
      syslog(LOG_ERR, "write: %m\n");

}	/* end: replyok() */
Technical Details
Message-ID: <9208051157.AA24851@nisc.jvnc.net>
Path: arc1-ca.pugleaf.net!sparky!uunet!stanford.edu!agate!boulder!recnews

Show Full Headers
Complete Article Headers
Newsgroups: comp.dcom.sys.cisco
Path: arc1-ca.pugleaf.net!sparky!uunet!stanford.edu!agate!boulder!recnews
From: aggarwal@nisc.jvnc.net (Vikas Aggarwal)
Subject: Re: Need help with TACACS server code on HP
In-Reply-To: <920804090019.25600634@CCV.NERSC.GOV>; from "MACKANIC@CCV.NERSC.GOV" at Aug 4, 92 9:00 am
Message-ID: <9208051157.AA24851@nisc.jvnc.net>
Sender: news@colorado.edu
Date: 5 Aug 92 7:57:02 EDT
X-Mailer: ELM [version 2.3 PL11]
Lines: 1200