IPv6 code for pam_radius-1.3.17

kentaro aoki kentaro.aoki at gmail.com
Fri Jul 18 10:36:10 CEST 2008


Hi,

I make the patch of ipv6 for pam_radius-1.3.17.
Please use, if very well.

Thank you.

Kentaro Aoki


The config file is following.

/etc/raddb/server
127.0.0.1:1645 secret 1
127.0.0.1 secret 1
[::1]:1645 secret 1
::1 secret 1


The patch  is following.

diff -c pam_radius-1.3.17/pam_radius_auth.c
pam_radius-1.3.17-ipv6/pam_radius_auth.c
*** pam_radius-1.3.17/pam_radius_auth.c	2007-03-26 18:36:13.000000000 +0900
--- pam_radius-1.3.17-ipv6/pam_radius_auth.c	2008-07-18 16:14:08.000000000 +0900
***************
*** 27,32 ****
--- 27,33 ----
   * 1.3.15 - Implement retry option, miscellanous bug fixes.
   * 1.3.16 - Miscellaneous fixes (see CVS for history)
   * 1.3.17 - Security fixes
+  * 1.3.17-ipv6 - Added ipv6 code by Kentaro Aoki <kentaro.aoki at gmail.com>
   *
   *
   *   This program is free software; you can redistribute it and/or modify
***************
*** 252,257 ****
--- 253,315 ----
    return(ntohl(*(UINT4 *)hp->h_addr));
  }

+ int dup_addrinfo(struct addrinfo **pptr_dup_addrinfo, struct
addrinfo *ptr_addrinfo)
+ {
+ 	int result = 0;
+ 	struct addrinfo *ptr_tmp_addrinfo;
+ 	struct addrinfo *ptr_tmp_dup_addrinfo = NULL;;
+ 	struct addrinfo *ptr_tmp_cur_addrinfo = NULL;;
+
+ 	*pptr_dup_addrinfo = NULL;
+ 	for (ptr_tmp_addrinfo = ptr_addrinfo; ptr_tmp_addrinfo != NULL;
ptr_tmp_addrinfo = ptr_tmp_addrinfo->ai_next) {
+ 		ptr_tmp_dup_addrinfo = malloc(sizeof(struct addrinfo));
+ 		if (ptr_tmp_dup_addrinfo == NULL) {
+ 			continue;
+ 		}
+ 		memset(ptr_tmp_dup_addrinfo, 0, sizeof(struct addrinfo));
+
+ 		if (ptr_tmp_addrinfo->ai_addr == NULL ||
ptr_tmp_addrinfo->ai_addrlen <= 0) {
+ 			ptr_tmp_dup_addrinfo->ai_addr = NULL;
+ 		} else {
+ 			ptr_tmp_dup_addrinfo->ai_addr = malloc(ptr_tmp_addrinfo->ai_addrlen);
+ 			memcpy(ptr_tmp_dup_addrinfo->ai_addr, ptr_tmp_addrinfo->ai_addr,
ptr_tmp_addrinfo->ai_addrlen);
+ 		}
+ 		ptr_tmp_dup_addrinfo->ai_addrlen = ptr_tmp_addrinfo->ai_addrlen;
+ 		if (ptr_tmp_addrinfo->ai_canonname != NULL) {
+ 			ptr_tmp_dup_addrinfo->ai_canonname =
strdup(ptr_tmp_addrinfo->ai_canonname);
+ 		} else {
+ 			ptr_tmp_dup_addrinfo->ai_canonname = NULL;
+ 		}
+ 		ptr_tmp_dup_addrinfo->ai_family = ptr_tmp_addrinfo->ai_family;
+ 		ptr_tmp_dup_addrinfo->ai_flags = ptr_tmp_addrinfo->ai_flags;
+ 		ptr_tmp_dup_addrinfo->ai_protocol = ptr_tmp_addrinfo->ai_protocol;
+ 		ptr_tmp_dup_addrinfo->ai_socktype = ptr_tmp_addrinfo->ai_socktype;
+ 		ptr_tmp_dup_addrinfo->ai_next = NULL;
+ 		
+ 		if (*pptr_dup_addrinfo == NULL) {
+ 			*pptr_dup_addrinfo = ptr_tmp_dup_addrinfo;
+ 		} else {
+ 			ptr_tmp_cur_addrinfo->ai_next = ptr_tmp_dup_addrinfo;
+ 		}
+ 		ptr_tmp_cur_addrinfo = ptr_tmp_dup_addrinfo;
+ 	}
+ 	return result;
+ }
+
+ void free_addrinfo(struct addrinfo **pptr_addrinfo)
+ {
+ 	if (*pptr_addrinfo != NULL) {
+ 		if ((*pptr_addrinfo)->ai_addr != NULL) {
+ 			free((*pptr_addrinfo)->ai_addr);
+ 		}
+ 		if ((*pptr_addrinfo)->ai_canonname != NULL) {
+ 			free((*pptr_addrinfo)->ai_canonname);
+ 		}
+ 		free(*pptr_addrinfo);
+ 		*pptr_addrinfo = NULL;
+ 	}
+ }
+
  /*
   * take server->hostname, and convert it to server->ip and server->port
   */
***************
*** 260,314 ****
  {
    char *p;
    int ctrl = 1; /* for DPRINT */
!
!   if ((p = strchr(server->hostname, ':')) != NULL) {
!     *(p++) = '\0';		/* split the port off from the host name */
    }
!
!   if ((server->ip.s_addr = get_ipaddr(server->hostname)) == ((UINT4)0)) {
!     DPRINT(LOG_DEBUG, "DEBUG: get_ipaddr(%s) returned 0.\n",
server->hostname);
!     return PAM_AUTHINFO_UNAVAIL;
    }
!
!   /*
!    *  If the server port hasn't already been defined, go get it.
!    */
!   if (!server->port) {
!     if (p && isdigit(*p)) {	/* the port looks like it's a number */
!       unsigned int i = atoi(p) & 0xffff;
!
!       if (!server->accounting) {
! 	server->port = htons((u_short) i);
!       } else {
! 	server->port = htons((u_short) (i + 1));
!       }
!     } else {			/* the port looks like it's a name */
!       struct servent *svp;
!
!       if (p) {			/* maybe it's not "radius" */
! 	svp = getservbyname (p, "udp");
! 	/* quotes allow distinction from above, lest p be radius or radacct */
! 	DPRINT(LOG_DEBUG, "DEBUG: getservbyname('%s', udp) returned %d.\n", p, svp);
! 	*(--p) = ':';		/* be sure to put the delimiter back */
!       } else {
! 	if (!server->accounting) {
! 	  svp = getservbyname ("radius", "udp");
! 	  DPRINT(LOG_DEBUG, "DEBUG: getservbyname(radius, udp) returned %d.\n", svp);
! 	} else {
! 	  svp = getservbyname ("radacct", "udp");
! 	  DPRINT(LOG_DEBUG, "DEBUG: getservbyname(radacct, udp) returned
%d.\n", svp);
! 	}
!       }
!
!       if (svp == (struct servent *) 0) {
! 	/* debugging above... */
! 	return PAM_AUTHINFO_UNAVAIL;
!       }
!
!       server->port = svp->s_port;
!     }
    }
!
    return PAM_SUCCESS;
  }

--- 318,372 ----
  {
    char *p;
    int ctrl = 1; /* for DPRINT */
!   char *ptr_host = NULL;
!   char *ptr_service = NULL;
!   char *ptr_hostname;
!   int i;
!   struct addrinfo hintsaddr;
!   struct addrinfo *peeraddrs;
!
!   ptr_hostname = strdup(server->hostname);
!   ptr_host = ptr_hostname;
!   /* If the host name may be catenated ipv6-string with port, go get it. */
!   if (*ptr_host == '[') {
! 	  ptr_host ++;
! 	  p = strchr(ptr_host, ']');
! 	  *(p++) = '\0';		/* split the port off from the host name */
! 	  ptr_service = strchr(p, ':');
! 	  ptr_service++;
!   } else {
!       /* Checks the host name for ipv6. */
! 	  i = 0;
! 	  for (p = ptr_host; *p != '\0'; p ++) {
! 		  if (*p == ':') {
! 			  i ++;
! 		  }
! 	  }
! 	  /* If the host name may be ipv4-string, go get it. */
! 	  if (i < 2) {
! 		  if ((ptr_service = strchr(ptr_host, ':')) != NULL) {
! 		    *(ptr_service++) = '\0';		/* split the port off from the host name */
! 		  }
! 	  }
    }
!   if (ptr_service == NULL) {
! 	  if (!server->accounting) {
! 		  ptr_service = "radius";
! 	  } else {
! 		  ptr_service = "radacct";
! 	  }
    }
!
!   /* Resolves host with service. */
!   memset(&hintsaddr, 0, sizeof(struct addrinfo));
!   hintsaddr.ai_family = AF_UNSPEC;
!   hintsaddr.ai_socktype = SOCK_DGRAM;
!   if ((i = getaddrinfo(ptr_host, ptr_service, &hintsaddr, &peeraddrs)) != 0) {
! 	  DPRINT(LOG_DEBUG, "DEBUG: getaddrinfo(%s, %s) returned %d.\n",
ptr_host, ptr_service, i);
! 	  return PAM_AUTHINFO_UNAVAIL;
    }
!   dup_addrinfo(&server->addressinfo, peeraddrs);
!   free(ptr_hostname);
    return PAM_SUCCESS;
  }

***************
*** 641,647 ****
        server->hostname = strdup(hostname);
        server->secret = strdup(secret);
        server->accounting = accounting;
!       server->port = 0;

        if ((timeout < 1) || (timeout > 60)) {
  	server->timeout = 3;
--- 699,705 ----
        server->hostname = strdup(hostname);
        server->secret = strdup(secret);
        server->accounting = accounting;
!       server->addressinfo = NULL;

        if ((timeout < 1) || (timeout > 60)) {
  	server->timeout = 3;
***************
*** 699,705 ****
  build_radius_packet(AUTH_HDR *request, CONST char *user, CONST char
*password, radius_conf_t *conf)
  {
    char hostname[256];
!   UINT4 ipaddr;

    hostname[0] = '\0';
    gethostname(hostname, sizeof(hostname) - 1);
--- 757,765 ----
  build_radius_packet(AUTH_HDR *request, CONST char *user, CONST char
*password, radius_conf_t *conf)
  {
    char hostname[256];
!   struct addrinfo hintsaddr;
!   struct addrinfo *peeraddrs;
!   struct addrinfo *peeraddr;

    hostname[0] = '\0';
    gethostname(hostname, sizeof(hostname) - 1);
***************
*** 725,746 ****
      add_password(request, PW_PASSWORD, "", conf->server->secret);
    }

!   /* the packet is from localhost if on localhost, to make configs easier */
!   if ((conf->server->ip.s_addr == ntohl(0x7f000001)) || (!hostname[0])) {
!     ipaddr = 0x7f000001;
!   } else {
!     struct hostent *hp;
!
!     if ((hp = gethostbyname(hostname)) == (struct hostent *) NULL) {
!       ipaddr = 0x00000000;	/* no client IP address */
!     } else {
!       ipaddr = ntohl(*(UINT4 *) hp->h_addr); /* use the first one available */
!     }
    }

    /* If we can't find an IP address, then don't add one */
!   if (ipaddr) {
!     add_int_attribute(request, PW_NAS_IP_ADDRESS, ipaddr);
    }

    /* There's always a NAS identifier */
--- 785,814 ----
      add_password(request, PW_PASSWORD, "", conf->server->secret);
    }

!   if (hostname[0] == '\0') {
! 	  strncpy(hostname, "127.0.0.1", sizeof(hostname));
    }

    /* If we can't find an IP address, then don't add one */
!   if (hostname[0] != '\0') {
! 	  hintsaddr.ai_family = AF_UNSPEC;
! 	  hintsaddr.ai_socktype = SOCK_DGRAM;
! 	  if (getaddrinfo(hostname, NULL, &hintsaddr, &peeraddrs) == 0) {
! 		  for (peeraddr = peeraddrs; peeraddr != NULL; peeraddr =
peeraddr->ai_next) {
! 			  switch (peeraddr->ai_family) {
! 			  case AF_INET:
! 				  add_attribute(request, PW_NAS_IP_ADDRESS,
! 						  (unsigned char *)&((struct sockaddr_in
*)peeraddr->ai_addr)->sin_addr, 4);
! 				  break;
! 			  case AF_INET6:
! 				  add_attribute(request, PW_NAS_IPV6_ADDRESS,
! 						  (unsigned char *)&((struct sockaddr_in6
*)peeraddr->ai_addr)->sin6_addr, 16);
! 				  break;
! 			  default:
! 				  break;
! 			  }
! 		  }
! 	  }
    }

    /* There's always a NAS identifier */
***************
*** 766,780 ****
  talk_radius(radius_conf_t *conf, AUTH_HDR *request, AUTH_HDR *response,
              char *password, char *old_password, int tries)
  {
!   int salen, total_length;
    fd_set set;
    struct timeval tv;
    time_t now, end;
    int rcode;
!   struct sockaddr saremote;
!   struct sockaddr_in *s_in = (struct sockaddr_in *) &saremote;
    radius_server_t *server = conf->server;
!   int ok;
    int server_tries;
    int retval;

--- 834,849 ----
  talk_radius(radius_conf_t *conf, AUTH_HDR *request, AUTH_HDR *response,
              char *password, char *old_password, int tries)
  {
!   int total_length;
    fd_set set;
    struct timeval tv;
    time_t now, end;
    int rcode;
!   struct addrinfo *cur_addrinfo;
!   struct sockaddr_in6 saremote;
!   socklen_t salen = sizeof(struct sockaddr_in6);
    radius_server_t *server = conf->server;
!   int ok = TRUE;
    int server_tries;
    int retval;

***************
*** 804,957 ****
      }

      /* set up per-server IP && port configuration */
-     memset ((char *) s_in, '\0', sizeof(struct sockaddr));
-     s_in->sin_family = AF_INET;
-     s_in->sin_addr.s_addr = htonl(server->ip.s_addr);
-     s_in->sin_port = server->port;
      total_length = ntohs(request->length);

      if (!password) { 		/* make an RFC 2139 p6 request authenticator */
        get_accounting_vector(request, server);
      }

!     server_tries = tries;
! send:
!     /* send the packet */
!     if (sendto(conf->sockfd, (char *) request, total_length, 0,
! 	       &saremote, sizeof(struct sockaddr_in)) < 0) {
!       _pam_log(LOG_ERR, "Error sending RADIUS packet to server %s: %s",
! 	       server->hostname, strerror(errno));
!       ok = FALSE;
!       goto next;		/* skip to the next server */
!     }
!
!     /* ************************************************************ */
!     /* Wait for the response, and verify it. */
!     salen = sizeof(struct sockaddr);
!     tv.tv_sec = server->timeout; /* wait for the specified time */
!     tv.tv_usec = 0;
!     FD_ZERO(&set);		/* clear out the set */
!     FD_SET(conf->sockfd, &set);	/* wait only for the RADIUS UDP socket */
!
!     time(&now);
!     end = now + tv.tv_sec;
!
!     /* loop, waiting for the select to return data */
!     ok = TRUE;
!     while (ok) {
!
!       rcode = select(conf->sockfd + 1, &set, NULL, NULL, &tv);
!
!       /* select timed out */
!       if (rcode == 0) {
! 	_pam_log(LOG_ERR, "RADIUS server %s failed to respond",
! 		 server->hostname);
! 	if (--server_tries)
! 	  goto send;
! 	ok = FALSE;
! 	break;			/* exit from the select loop */
!       } else if (rcode < 0) {
!
! 	/* select had an error */
! 	if (errno == EINTR) {	/* we were interrupted */
! 	  time(&now);
! 	
! 	  if (now > end) {
! 	    _pam_log(LOG_ERR, "RADIUS server %s failed to respond",
! 		     server->hostname);
! 	    if (--server_tries)
! 	      goto send;
! 	    ok = FALSE;
! 	    break;			/* exit from the select loop */
! 	  }
! 	
! 	  tv.tv_sec = end - now;
! 	  if (tv.tv_sec == 0) {	/* keep waiting */
! 	    tv.tv_sec = 1;
! 	  }
!
! 	} else {		/* not an interrupt, it was a real error */
! 	  _pam_log(LOG_ERR, "Error waiting for response from RADIUS server %s: %s",
! 		   server->hostname, strerror(errno));
! 	  ok = FALSE;
! 	  break;
  	}
!
! 	/* the select returned OK */
!       } else if (FD_ISSET(conf->sockfd, &set)) {
!
! 	/* try to receive some data */
! 	if ((total_length = recvfrom(conf->sockfd, (char *) response,
! 				     BUFFER_SIZE,
! 				     0, &saremote, &salen)) < 0) {
! 	  _pam_log(LOG_ERR, "error reading RADIUS packet from server %s: %s",
! 		   server->hostname, strerror(errno));
! 	  ok = FALSE;
! 	  break;
!
! 	  /* there's data, see if it's valid */
! 	} else {
! 	  char *p = server->secret;
! 	
! 	  if ((ntohs(response->length) != total_length) ||
! 	      (ntohs(response->length) > BUFFER_SIZE)) {
! 	    _pam_log(LOG_ERR, "RADIUS packet from server %s is corrupted",
! 		     server->hostname);
! 	    ok = FALSE;
! 	    break;
! 	  }
!
! 	  /* Check if we have the data OK.  We should also check request->id */
!
! 	  if (password) {
! 	    if (old_password) {
  #ifdef LIVINGSTON_PASSWORD_VERIFY_BUG_FIXED
! 	      p = old_password;	/* what it should be */
! #else
! 	      p = "";		/* what it really is */
! #endif
! 	    }
! 	    /*
! 	     * RFC 2139 p.6 says not do do this, but the Livingston 1.16
! 	     * server disagrees.  If the user says he wants the bug, give in.
! 	     */
! 	  } else {		/* authentication request */
! 	    if (conf->accounting_bug) {
! 	      p = "";
! 	    }
! 	  }
! 	
! 	  if (!verify_packet(p, response, request)) {
! 	    _pam_log(LOG_ERR, "packet from RADIUS server %s fails
verification: The shared secret is probably incorrect.",
! 		     server->hostname);
! 	    ok = FALSE;
! 	    break;
! 	  }
!
! 	  /*
! 	   * Check that the response ID matches the request ID.
! 	   */
! 	  if (response->id != request->id) {
! 	    _pam_log(LOG_WARNING, "Response packet ID %d does not match the
request packet ID %d: verification of packet fails", response->id,
request->id);
! 	      ok = FALSE;
! 	    break;
! 	  }
! 	}
! 	
! 	/*
! 	 * Whew!  The select is done.  It hasn't timed out, or errored out.
! 	 * It's our descriptor.  We've got some data.  It's the right size.
! 	 * The packet is valid.
! 	 * NOW, we can skip out of the select loop, and process the packet
! 	 */
! 	break;
!       }
!       /* otherwise, we've got data on another descriptor, keep select'ing */
!     }

      /* go to the next server if this one didn't respond */
    next:
!     if (!ok) {
        radius_server_t *old;	/* forget about this server */

        old = server;
--- 873,1058 ----
      }

      /* set up per-server IP && port configuration */
      total_length = ntohs(request->length);

      if (!password) { 		/* make an RFC 2139 p6 request authenticator */
        get_accounting_vector(request, server);
      }

! 	for (cur_addrinfo = server->addressinfo
! 			; cur_addrinfo != NULL
! 			; cur_addrinfo = cur_addrinfo->ai_next) {
! 		
! 		struct sockaddr_in peer_sockaddr;
! 		struct sockaddr_in6 peer_sockaddr6;
! 		const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
! 		u_short local_port;
! 		struct sockaddr *sockaddr_ptr;
! 		int sockaddr_len;
! 		int sockfd;
! 		
! 		ok = TRUE;
! 		if (cur_addrinfo->ai_family != AF_INET && cur_addrinfo->ai_family
!= AF_INET6) {
! 			ok = FALSE;
! 			continue;
! 		}
! 		/* send the packet */
! 		sockfd = socket(cur_addrinfo->ai_family,
! 				cur_addrinfo->ai_socktype,
! 				cur_addrinfo->ai_protocol);
! 		if (sockfd < 0) {
! 			ok = FALSE;
! 			continue;
! 		}
!
! 		/*
! 		 *  Use our process ID as a local port for RADIUS.
! 		 */
! 		local_port = (getpid() & 0x7fff) + 1024;
! 		do {
! 			local_port++;
! 			if (cur_addrinfo->ai_family == AF_INET) {
! 				peer_sockaddr.sin_family = cur_addrinfo->ai_family;
! 				peer_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
! 				peer_sockaddr.sin_port = htons(local_port);
! 				sockaddr_ptr = (struct sockaddr *)&peer_sockaddr;
! 				sockaddr_len = sizeof(struct sockaddr_in);
! 			} else if (cur_addrinfo->ai_family == AF_INET6) {
! 				peer_sockaddr6.sin6_family = cur_addrinfo->ai_family;
! 				peer_sockaddr6.sin6_addr = in6addr_any;
! 				peer_sockaddr6.sin6_port = htons(local_port);
! 				sockaddr_ptr = (struct sockaddr *)&peer_sockaddr6;
! 				sockaddr_len = sizeof(struct sockaddr_in6);
! 			} else {
! 				continue;
! 			}
! 		} while ((bind(sockfd, sockaddr_ptr, sockaddr_len) < 0) &&
! 			   (local_port < 64000));		
! 		if (local_port >= 64000) {
! 			close(sockfd);
! 			_pam_log(LOG_ERR, "No open port we could bind to.");
! 			continue;
! 		}
!
! 		if (sendto(sockfd, (char *) request, total_length, 0,
! 				cur_addrinfo->ai_addr, cur_addrinfo->ai_addrlen) < 0) {
! 			_pam_log(LOG_ERR, "Error sending RADIUS packet to server %s: %s",
! 					server->hostname, strerror(errno));
! 			close(sockfd);
! 			continue;
! 		}
! 	    server_tries = tries;
! 		do {
! 		    tv.tv_sec = server->timeout; /* wait for the specified time */
! 		    tv.tv_usec = 0;
! 		    FD_ZERO(&set);		/* clear out the set */
! 		    FD_SET(sockfd, &set);	/* wait only for the RADIUS UDP socket */
! 		    rcode = select(sockfd + 1, &set, NULL, NULL, &tv);
! 		    /* select timed out */
! 		    if (rcode == 0) {
! 		    	_pam_log(LOG_ERR, "RADIUS server %s failed to respond(time
out %d(sec))",
! 		    			server->hostname, server->timeout);
! 		    	if (--server_tries) {
! 		    		continue;
! 		    	}
! 		    	ok = FALSE;
! 		    	break;			/* exit from the select loop */
! 		    } else if (rcode < 0) {
! 		    	/* select had an error */
! 		    	if (errno == EINTR) {	/* we were interrupted */
! 		    		time(&now);
! 		    		if (now > end) {
! 		    			_pam_log(LOG_ERR, "RADIUS server %s failed to respond",
! 		    				server->hostname);
! 		    			if (--server_tries) {
! 		    				continue;
! 		    			}
! 		    			ok = FALSE;
! 		    			break;			/* exit from the select loop */
! 		    		}
! 		    		tv.tv_sec = end - now;
! 		    		if (tv.tv_sec == 0) {	/* keep waiting */
! 		    			tv.tv_sec = 1;
! 		    		}
! 		    	} else {		/* not an interrupt, it was a real error */
! 		    		_pam_log(LOG_ERR, "Error waiting for response from RADIUS
server %s: %s",
! 		    				server->hostname, strerror(errno));
! 		    		ok = FALSE;
! 		    		break;
! 		    	}
! 		    	/* the select returned OK */
! 		    } else if (FD_ISSET(sockfd, &set)) {
! 		    	/* try to receive some data */
! 		    	if ((total_length = recvfrom(sockfd, (char *) response,
BUFFER_SIZE, 0, (struct sockaddr *)&saremote, &salen)) < 0) {
! 		    	  _pam_log(LOG_ERR, "error reading RADIUS packet from server %s: %s",
! 		    		   server->hostname, strerror(errno));
! 		    	  ok = FALSE;
! 		    	  break;
! 		    	  /* there's data, see if it's valid */
! 		    	}
! 		    }
! 		} while (0);
! 		close(sockfd);
! 		if (ok != FALSE) {
! 			break;
! 		}
  	}
! 	do {
! 		if (ok == TRUE) {
! 			char *p = server->secret;
! 			if ((ntohs(response->length) != total_length) ||
! 					(ntohs(response->length) > BUFFER_SIZE)) {
! 				_pam_log(LOG_ERR, "RADIUS packet from server %s is corrupted",
! 						server->hostname);
! 				ok = FALSE;
! 				break;
! 			}
! 			/* Check if we have the data OK.  We should also check request->id */
! 			if (password) {
! 				if (old_password) {
  #ifdef LIVINGSTON_PASSWORD_VERIFY_BUG_FIXED
! 					p = old_password;	/* what it should be */
! #else  next:

+ 					p = "";		/* what it really is */
+ #endif
+ 				}
+ 				/*
+ 				 * RFC 2139 p.6 says not do do this, but the Livingston 1.16
+ 				 * server disagrees.  If the user says he wants the bug, give in.
+ 				 */
+ 			} else {		/* authentication request */
+ 				if (conf->accounting_bug) {
+ 					p = "";
+ 				}
+ 			}
+ 			if (!verify_packet(p, response, request)) {
+ 				_pam_log(LOG_ERR, "packet from RADIUS server %s fails
verification: The shared secret is probably incorrect.",
+ 						server->hostname);
+ 				ok = FALSE;
+ 				break;
+ 			}
+ 			/*
+ 			 * Check that the response ID matches the request ID.
+ 			 */
+ 			if (response->id != request->id) {
+ 				_pam_log(LOG_WARNING, "Response packet ID %d does not match the
request packet ID %d: verification of packet fails", response->id,
request->id);
+ 				ok = FALSE;
+ 				break;
+ 			}
+ 			/*
+ 			 * Whew!  The select is done.  It hasn't timed out, or errored out.
+ 			 * It's our descriptor.  We've got some data.  It's the right size.
+ 			 * The packet is valid.
+ 			 * NOW, we can skip out of the select loop, and process the packet
+ 			 */
+ 			break;
+ 		}
+ 		/* otherwise, we've got data on another descriptor, keep select'ing */
+ 	} while (0);
      /* go to the next server if this one didn't respond */
    next:
!     if (ok == FALSE) {
        radius_server_t *old;	/* forget about this server */

        old = server;
***************
*** 960,965 ****
--- 1061,1067 ----

        _pam_forget(old->secret);
        free(old->hostname);
+       free_addrinfo(&old->addressinfo);
        free(old);

        if (server) {		/* if there's more servers to check */
***************
*** 1137,1143 ****

    if(password) {
      password = strdup(password);
-     DPRINT(LOG_DEBUG, "Got password %s", password);
    }

    /* no previous password: maybe get one from the user */
--- 1239,1244 ----
diff -c pam_radius-1.3.17/pam_radius_auth.conf
pam_radius-1.3.17-ipv6/pam_radius_auth.conf
*** pam_radius-1.3.17/pam_radius_auth.conf	2000-07-11 04:18:42.000000000 +0900
--- pam_radius-1.3.17-ipv6/pam_radius_auth.conf	2008-07-18
16:36:15.000000000 +0900
***************
*** 8,14 ****
  #  lines.  Blank lines or lines beginning with '#' are treated as
  #  comments, and are ignored.  The fields are:
  #
! #  server[:port] secret [timeout]
  #
  #  the port name or number is optional.  The default port name is
  #  "radius", and is looked up from /etc/services The timeout field is
--- 8,17 ----
  #  lines.  Blank lines or lines beginning with '#' are treated as
  #  comments, and are ignored.  The fields are:
  #
! #  hostname-server[:port] secret [timeout]
! #  ipv4-server[:port] secret [timeout]
! #  ipv6-server secret [timeout]
! #  \[ipv6-server\]:port secret [timeout]
  #
  #  the port name or number is optional.  The default port name is
  #  "radius", and is looked up from /etc/services The timeout field is
***************
*** 23,28 ****
--- 26,35 ----
  #  deciding that the server has failed to respond.
  #
  # server[:port]	shared_secret      timeout (s)
+ # ex.
+ # ::1	secret	1
+ # [::1]:1645	secret	1
+
  127.0.0.1	secret             1
  other-server    other-secret       3

diff -c pam_radius-1.3.17/pam_radius_auth.h
pam_radius-1.3.17-ipv6/pam_radius_auth.h
*** pam_radius-1.3.17/pam_radius_auth.h	2007-03-26 14:35:31.000000000 +0900
--- pam_radius-1.3.17-ipv6/pam_radius_auth.h	2008-07-18 16:14:19.000000000 +0900
***************
*** 36,43 ****

  typedef struct radius_server_t {
    struct radius_server_t *next;
!   struct in_addr ip;
!   u_short port;
    char *hostname;
    char *secret;
    int timeout;
--- 36,42 ----

  typedef struct radius_server_t {
    struct radius_server_t *next;
!   struct addrinfo *addressinfo;
    char *hostname;
    char *secret;
    int timeout;
diff -c pam_radius-1.3.17/radius.h pam_radius-1.3.17-ipv6/radius.h
*** pam_radius-1.3.17/radius.h	2000-08-23 00:24:47.000000000 +0900
--- pam_radius-1.3.17-ipv6/radius.h	2008-07-18 16:07:34.000000000 +0900
***************
*** 125,130 ****
--- 125,131 ----
  #define PW_LOGIN_LAT_PORT               63      /* string */
  #define PW_PROMPT                       64      /* integer */

+ #define PW_NAS_IPV6_ADDRESS				95		/* address */
  /*
   *	INTEGER TRANSLATIONS
   */



More information about the Freeradius-Devel mailing list