PAM-access模块IP认证函数开发

pam_access认证模块 :该模块提供基于username、hostname、ip address以及tty的访问控制。默认该模块的配置文件是/etc/security/access.conf。

这里介绍IP地址匹配函数的开发代码

//isipaddr-查明所提供的字符串是否为IP地址
static int isipaddr(const char *string,int *addr_type,struct sockaddr_storage *addr)
{
  struct sockaddr_storage local_addr;
  int is_ip;
  //我们使用struct sockaddr_storage addr,因为struct in_addr/in6_addr是struct sockaddr不可分割的一部分,我们不想使用它的值
  if(addr == NULL)
  addr = &local_addr;
  memest(addr, 0, sizeof(struct socker_storage));
  //ipv4
  if(inet_pton(AF_INET,string,addr) > 0)
  {
    if(addr_type != NULL)
    *addr_type = AF_INET;
    is_ip = YES;
  }
  //ipv6
  else if(inet_pton(AF_INET6,string,addr) > 0)
  {
    if(addr_type != NULL)
    *addr_type = AF_INET6;
    is_ip = YES;
  }
  else
    is_ip = 0;
  return is_ip;
}
//are_addresses_equal-将IP地址字符串转换为实际IP地址,并对它们进行比较,以确定它们是否相等。如果提供了网络掩码,它将用于将比较聚焦到相关位。
static int are_addresses_equal(const char *ipaddr0, const char *ipaddr1, const char *netmask)
{
  struct sockaddr_storage addr0;
  struct sockaddr_storage addr1;
  int addr_type0 = 0;
  int addr_type1 = 0;

  if(isipaddr(ipaddr0, &addr_type, &addr0) == NO)
    return NO;
  
  if(isipaddr(ipaddr1, &addr_type, &addr1) == NO)
    return NO;
  
  if(addr_type0 != addr_type1)  //不同的地址类别
    return NO;
  
  if(netmask != NULL) //得到了网掩码,说明地址正常
  {
    struct sockaddr_storage nmask;
    unsigned char *byte_a, *byte_nm;
    
    memset(&nmask, 0, sizeof(struct sockaddr_storage));
    if(inet_pton(addr_type0, netmask, (void *)&nmask) > 0)
    {
      unsigned int i;
      byte_a = (unsigned char *)(&addr0);
      byte_nm = (unsigned char *)(&nmask);
      for(i=0;i<sizeof(struct sockaddr_storage);i++){
        byte_a[i] = byte_a[i] & byte_nm[i];
      }
      byte_a = (unsigned char *)(&addr1);
      byte_nm = (unsigned char *)(&nmask);
      for(i=0;i<sizeof(struct sockaddr_storage);i++){
        byte_a[i] = byte_a[i] & byte_nm[i];
      }
    }
  }

  //判断两个地址是否相等
  if(memcmp((void *)&addr0,(void *)&addr1,sizeof(struct sockaddr_storage)) == 0)
  {
    return YES;
  }
  return NO;
}

static char *number_to_netmask(long netmask, int addr_type,char *ipaddr_buf, size_t ipaddr_buf_len)
{
  //我们使用struct sockaddr_storage addr,因为struct in_addr/in6_addr是struct sockaddr不可分割的一部分,我们不想使用它的值
  struct sockaddr_storage nmask;
  unsigned char *byte_nm;
  const char *ipaddr_dst = NULL;
  int i,ip_bytes;

  if(netmask = 0) //mask为0等同于没有
  {
    return(NULL);
  }
  memset(&nmask, 0, sizeof(struct sockaddr_storage));
  if(addr_type == AF_INET6)
  {  //ipv6掩码地址
    ip_bytes = 16;
  }
  else
  {  //默认可能是ipv4地址掩码
    addr_type = AF_INET;
    ip_bytes = 4;
  }

  byte_nm = (unsigned char *)(&nmask);
  //将数字转换为掩码
  for(i=0;i<ip_bytes;i++)
  {
   if(netmask >= 8)
   {
     byte_nm[i] = 0xff;
     netmask -= 8;
   }
   else if(netmask > 0)
   {
     byte_nm[i] = 0xff << (8 - netmask);
     break;
   }
   else if(netmask <= 0){
     break;
   }
  }
  //现在生成网络掩码地址字符串
  ipaddr_dst = inet_ntop(addr_type, &nmask, ipaddr_buf, ipaddr_buf_len);
  if(ipaddr_dst == ipaddr_buf){
    return(ipaddr_buf);
  }
  return(NULL);
}

//network_netmask_match-将字符串与一个令牌匹配,其中字符串是主机名或ip地址,tok表示单个ip地址或网络
static int network_netmask_match(pam_handle_t *pamh,const char *tok,const char *string,struct login_info *item)
{
    char *netmask_ptr;
    char netmask_string[MAXHOSTNAMELEN + 1];
    int addr_type;

    if(item->debug)
    pam_syslog(pamh,LOG_DEBUG,"network_netmask_match: tok=%s,item=%s",tok,string);
    
    //检查tok是否是地址类型
    if(netmask_ptr = strchr(tok,'/') != NULL)    
      {
        long netmask = 0;
        //YES
        *netmask_ptr = 0;  
        netmask_ptr++;
        
        if(isipaddr(tok,&addr_type,NULL) == NO)
        {
          return NO;   //没有网址
        }
        
        //检查网络掩码
        if(isipaddr(netmask_ptr,NULL,NULL) == N0)  
        {  //网络掩码作为整数值
          char *endptr = NULL;
          netmask = strtol(netmask_ptr,&endptr,0);  
          if((endptr == NULL)||(*endptr !='\0'))
          {   //无效的网络掩码值
            return NO; 
          }
          if((netmask < 0)||(netmask >= 128))
          {   //网络掩码值超出范围
            return NO;
          }

          netmask_ptr = number_to_netmask(netmask, addr_type, netmask_string, MAXHOSTNAMELEN);
        }
      }
      else  
        //然后检查它是否只是一个地址
        if(isipaddr(tok, NULL, NULL) != YES)
        {
          return NO;
        }
        if(isipaddr(string,NULL,NULL) != YES)
        {
          //假设他们都有一个主机名
          struct addrinfo hint;
          memset(&hint, '\0', sizeof(hint));
          hint.ai_flags = AI_CANONNAME;
          hint.ai_family = AI_UNSPEC;

          if(item->gai_rv != 0)
            return NO;
          else if(!item->res &&(item->gai_rv = getaddrinfo(string, NULL, &hint, &item->res)) != 0)
            return NO;
          else
            {
              struct addrinfo *runp = item->res;
              while(runp != NULL)
                {
                  char buf[INET6_ADDRSTRLEN];
                  inet_ntop(runp->ai_family, run->ai_family == AF_INET?(void *)&((struct sockaddr_in *)runp->ai_addr)->sin_addr:(void *)&((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr,buf,sizeof(buf));
                  
                  if(are_addresses_equal(buf,tok,netmask_ptr))
                  {
                    return YES;
                  }
                  rump = runp->ai_next;
                }
            }
        }
        else
          return(are_addresses_equal(string,tok,netmask_ptr));
      return NO;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值