ipacl.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:12k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * ipacl.cxx
  3.  *
  4.  * PWLib application source file for rcsd
  5.  *
  6.  * Main program entry point.
  7.  *
  8.  * Copyright 1998 Equivalence Pty. Ltd.
  9.  *
  10.  * $Log: ipacl.cxx,v $
  11.  * Revision 1.7  1999/02/25 13:01:11  robertj
  12.  * Fixed subtle bug in GNU compiler not automatically casting IP address.
  13.  *
  14.  * Revision 1.6  1999/02/25 11:10:52  robertj
  15.  * Fixed count of non-hidden entries in config file.
  16.  *
  17.  * Revision 1.5  1999/02/25 05:05:15  robertj
  18.  * Added missing test for hidden entries not to be written to config file
  19.  *
  20.  * Revision 1.4  1999/02/08 08:05:39  robertj
  21.  * Changed semantics of IP access control list for empty list.
  22.  *
  23.  * Revision 1.3  1999/01/31 10:14:07  robertj
  24.  * Changed about dialog to be full company name
  25.  *
  26.  * Revision 1.2  1999/01/31 08:10:33  robertj
  27.  * Fixed PConfig file save, out by one error in array subscript.
  28.  *
  29.  * Revision 1.1  1999/01/31 00:59:26  robertj
  30.  * Added IP Access Control List class to PTLib Components
  31.  *
  32.  */
  33. #include <ptlib.h>
  34. #include <ptclib/ipacl.h>
  35. #define new PNEW
  36. PIpAccessControlEntry::PIpAccessControlEntry(PIPSocket::Address addr,
  37.                                              PIPSocket::Address msk,
  38.                                              BOOL allow)
  39.   : address(addr), mask(msk)
  40. {
  41.   allowed = allow;
  42.   hidden = FALSE;
  43. }
  44. PIpAccessControlEntry::PIpAccessControlEntry(const PString & description)
  45.   : address(0), mask(0xffffffff)
  46. {
  47.   Parse(description);
  48. }
  49. PIpAccessControlEntry & PIpAccessControlEntry::operator=(const PString & description)
  50. {
  51.   Parse(description);
  52.   return *this;
  53. }
  54. PIpAccessControlEntry & PIpAccessControlEntry::operator=(const char * description)
  55. {
  56.   Parse(description);
  57.   return *this;
  58. }
  59. PObject::Comparison PIpAccessControlEntry::Compare(const PObject & obj) const
  60. {
  61.   PAssert(obj.IsDescendant(Class()), PInvalidCast);
  62.   const PIpAccessControlEntry & other = (const PIpAccessControlEntry &)obj;
  63.   // The larger the mask value, th more specific the range, so earlier in list
  64.   if (mask > other.mask)
  65.     return LessThan;
  66.   if (mask < other.mask)
  67.     return GreaterThan;
  68.   if (!domain && !other.domain)
  69.     return domain.Compare(other.domain);
  70.   if (address > other.address)
  71.     return LessThan;
  72.   if (address < other.address)
  73.     return GreaterThan;
  74.   return EqualTo;
  75. }
  76. void PIpAccessControlEntry::PrintOn(ostream & strm) const
  77. {
  78.   if (!allowed)
  79.     strm << '-';
  80.   if (hidden)
  81.     strm << '@';
  82.   if (domain.IsEmpty())
  83.     strm << address;
  84.   else if (domain[0] != 'xff')
  85.     strm << domain;
  86.   else {
  87.     strm << "ALL";
  88.     return;
  89.   }
  90.   if (mask != 0 && mask != 0xffffffff)
  91.     strm << '/' << mask;
  92. }
  93. void PIpAccessControlEntry::ReadFrom(istream & strm)
  94. {
  95.   char buffer[200];
  96.   strm >> ws >> buffer;
  97.   Parse(buffer);
  98. }
  99. BOOL PIpAccessControlEntry::Parse(const PString & description)
  100. {
  101.   domain = PString();
  102.   address = 0;
  103.   if (description.IsEmpty())
  104.     return FALSE;
  105.   // Check for the allow/deny indication in first character of description
  106.   BOOL offset = 1;
  107.   if (description[0] == '-')
  108.     allowed = FALSE;
  109.   else {
  110.     allowed = TRUE;
  111.     if (description[0] != '+')
  112.       offset = 0;
  113.   }
  114.   // Check for indication entry is from the hosts.allow/hosts.deny file
  115.   hidden = FALSE;
  116.   if (description[offset] == '@') {
  117.     offset++;
  118.     hidden = TRUE;
  119.   }
  120.   if (description.Mid(offset) *= "all") {
  121.     domain = "xff";
  122.     mask = 0;
  123.     return TRUE;
  124.   }
  125.   PINDEX slash = description.Find('/', offset);
  126.   PString preSlash = description(offset, slash-1);
  127.   if (preSlash[0] == '.') {
  128.     // If has a leading dot then assume a domain, ignore anything after slash
  129.     domain = preSlash;
  130.     mask = 0;
  131.     return TRUE;
  132.   }
  133.   if (strspn(preSlash, "0123456789.") != (size_t)preSlash.GetLength()) {
  134.     // If is not all numbers and dots can't be an IP number so assume hostname
  135.     domain = preSlash;
  136.   }
  137.   else if (preSlash[preSlash.GetLength()-1] != '.') {
  138.     // Must be explicit IP number if doesn't end in dot
  139.     address = preSlash;
  140.   }
  141.   else {
  142.     // Must be partial IP number, count the dots!
  143.     PINDEX dot = preSlash.Find('.', preSlash.Find('.')+1);
  144.     if (dot == P_MAX_INDEX) {
  145.       // One dot
  146.       preSlash += "0.0.0";
  147.       mask = "255.0.0.0";
  148.     }
  149.     else if ((dot = preSlash.Find('.', dot+1)) == P_MAX_INDEX) {
  150.       // has two dots
  151.       preSlash += "0.0";
  152.       mask = "255.255.0.0";
  153.     }
  154.     else if (preSlash.Find('.', dot+1) == P_MAX_INDEX) {
  155.       // has three dots
  156.       preSlash += "0";
  157.       mask = "255.255.255.0";
  158.     }
  159.     else {
  160.       // Has more than three dots!
  161.       return FALSE;
  162.     }
  163.     address = preSlash;
  164.     return TRUE;
  165.   }
  166.   if (slash == P_MAX_INDEX) {
  167.     // No slash so assume a full mask
  168.     mask = 0xffffffff;
  169.     return TRUE;
  170.   }
  171.   PString postSlash = description.Mid(slash+1);
  172.   if (strspn(postSlash, "0123456789.") != (size_t)postSlash.GetLength()) {
  173.     domain = PString();
  174.     address = 0;
  175.     return FALSE;
  176.   }
  177.   if (postSlash.Find('.') != P_MAX_INDEX)
  178.     mask = postSlash;
  179.   else {
  180.     unsigned bits = postSlash.AsUnsigned();
  181.     if (bits >= 32)
  182.       mask = bits;
  183.     else
  184. #if PBYTE_ORDER==PLITTLE_ENDIAN
  185.       mask = 0xffffffff >> (32 - bits);
  186. #else
  187.       mask = 0xffffffff << (32 - bits);
  188. #endif
  189.   }
  190.   if (mask == 0)
  191.     domain = "xff";
  192.   address = (DWORD)address & (DWORD)mask;
  193.   return TRUE;
  194. }
  195. PString PIpAccessControlEntry::AsString() const
  196. {
  197.   PStringStream str;
  198.   str << *this;
  199.   return str;
  200. }
  201. BOOL PIpAccessControlEntry::IsValid()
  202. {
  203.   return address != 0 || !domain;
  204. }
  205. BOOL PIpAccessControlEntry::Match(PIPSocket::Address & addr)
  206. {
  207.   switch (domain[0]) {
  208.     case '' : // Must have address field set
  209.       break;
  210.     case '.' :  // Are a domain name
  211.       return PIPSocket::GetHostName(addr).Right(domain.GetLength()) *= domain;
  212.     case 'xff' :  // Match all
  213.       return TRUE;
  214.     default : // All else must be a hostname
  215.       if (!PIPSocket::GetHostAddress(domain, address))
  216.         return FALSE;
  217.   }
  218.   return (address & mask) == (addr & mask);
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////
  221. PIpAccessControlList::PIpAccessControlList()
  222. {
  223. }
  224. static BOOL ReadConfigFileLine(PTextFile & file, PString & line)
  225. {
  226.   line = PString();
  227.   do {
  228.     if (!file.ReadLine(line))
  229.       return FALSE;
  230.   } while (line.IsEmpty() || line[0] == '#');
  231.   PINDEX lastCharPos;
  232.   while (line[lastCharPos = line.GetLength()-1] == '\') {
  233.     PString str;
  234.     if (!file.ReadLine(str))
  235.       return FALSE;
  236.     line[lastCharPos] = ' ';
  237.     line += str;
  238.   }
  239.   return TRUE;
  240. }
  241. static void ParseConfigFileExcepts(const PString & str,
  242.                                    PStringList & entries,
  243.                                    PStringList & exceptions)
  244. {
  245.   PStringArray terms = str.Tokenise(' ', FALSE);
  246.   BOOL hadExcept = FALSE;
  247.   PINDEX d;
  248.   for (d = 0; d < terms.GetSize(); d++) {
  249.     if (terms[d] == "EXCEPT")
  250.       hadExcept = TRUE;
  251.     else if (hadExcept)
  252.       exceptions.AppendString(terms[d]);
  253.     else
  254.       entries.AppendString(terms[d]);
  255.   }
  256. }
  257. static BOOL SplitConfigFileLine(const PString & line, PString & daemons, PString & clients)
  258. {
  259.   PINDEX colon = line.Find(':');
  260.   if (colon == P_MAX_INDEX)
  261.     return FALSE;
  262.   daemons = line.Left(colon).Trim();
  263.   PINDEX other_colon = line.Find(':', ++colon);
  264.   clients = line(colon, other_colon-1).Trim();
  265.   return TRUE;
  266. }
  267. static BOOL IsDaemonInConfigFileLine(const PString & daemon, const PString & daemons)
  268. {
  269.   PStringList daemonsIn, daemonsOut;
  270.   ParseConfigFileExcepts(daemons, daemonsIn, daemonsOut);
  271.   for (PINDEX in = 0; in < daemonsIn.GetSize(); in++) {
  272.     if (daemonsIn[in] == "ALL" || daemonsIn[in] == daemon) {
  273.       PINDEX out;
  274.       for (out = 0; out < daemonsOut.GetSize(); out++) {
  275.         if (daemonsOut[out] == daemon)
  276.           break;
  277.       }
  278.       if (out >= daemonsOut.GetSize())
  279.         return TRUE;
  280.     }
  281.   }
  282.   return FALSE;
  283. }
  284. static BOOL ReadConfigFile(PTextFile & file,
  285.                            const PString & daemon,
  286.                            PStringList & clientsIn,
  287.                            PStringList & clientsOut)
  288. {
  289.   PString line;
  290.   while (ReadConfigFileLine(file, line)) {
  291.     PString daemons, clients;
  292.     if (SplitConfigFileLine(line, daemons, clients) &&
  293.         IsDaemonInConfigFileLine(daemon, daemons)) {
  294.       ParseConfigFileExcepts(clients, clientsIn, clientsOut);
  295.       return TRUE;
  296.     }
  297.   }
  298.   return FALSE;
  299. }
  300. BOOL PIpAccessControlList::InternalLoadHostsAccess(const PString & daemonName,
  301.                                                    const char * filename,
  302.                                                    BOOL allowance)
  303. {
  304.   PTextFile file;
  305.   if (!file.Open(PProcess::GetOSConfigDir() + filename, PFile::ReadOnly))
  306.     return TRUE;
  307.   BOOL ok = TRUE;
  308.   PStringList clientsIn;
  309.   PStringList clientsOut;
  310.   while (ReadConfigFile(file, daemonName, clientsIn, clientsOut)) {
  311.     PINDEX i;
  312.     for (i = 0; i < clientsOut.GetSize(); i++) {
  313.       if (!Add((allowance ? "-@" : "+@") + clientsOut[i]))
  314.         ok = FALSE;
  315.     }
  316.     for (i = 0; i < clientsIn.GetSize(); i++) {
  317.       if (!Add((allowance ? "+@" : "-@") + clientsIn[i]))
  318.         ok = FALSE;
  319.     }
  320.   }
  321.   return ok;
  322. }
  323. BOOL PIpAccessControlList::LoadHostsAccess(const char * daemonName)
  324. {
  325.   PString daemon;
  326.   if (daemonName != NULL)
  327.     daemon = daemonName;
  328.   else
  329.     daemon = PProcess::Current().GetName();
  330.   return InternalLoadHostsAccess(daemon, "hosts.allow", TRUE) &  // Really is a single &
  331.          InternalLoadHostsAccess(daemon, "hosts.deny", FALSE);
  332. }
  333. static const char DefaultConfigName[] = "IP Access Control List";
  334. BOOL PIpAccessControlList::Load(PConfig & cfg)
  335. {
  336.   return Load(cfg, DefaultConfigName);
  337. }
  338. BOOL PIpAccessControlList::Load(PConfig & cfg, const PString & baseName)
  339. {
  340.   BOOL ok = TRUE;
  341.   PINDEX count = cfg.GetInteger(baseName & "Array Size");
  342.   for (PINDEX i = 1; i <= count; i++) {
  343.     if (!Add(cfg.GetString(baseName & PString(PString::Unsigned, i))))
  344.       ok = FALSE;
  345.   }
  346.   return ok;
  347. }
  348. void PIpAccessControlList::Save(PConfig & cfg)
  349. {
  350.   Save(cfg, DefaultConfigName);
  351. }
  352. void PIpAccessControlList::Save(PConfig & cfg, const PString & baseName)
  353. {
  354.   PINDEX count = 0;
  355.   for (PINDEX i = 0; i < GetSize(); i++) {
  356.     PIpAccessControlEntry & entry = operator[](i);
  357.     if (!entry.IsHidden()) {
  358.       count++;
  359.       cfg.SetString(baseName & PString(PString::Unsigned, count), entry.AsString());
  360.     }
  361.   }
  362.   cfg.SetInteger(baseName & "Array Size", count);
  363. }
  364. BOOL PIpAccessControlList::Add(const PString & description)
  365. {
  366.   PIpAccessControlEntry entry(description);
  367.   if (!entry.IsValid())
  368.     return FALSE;
  369.   return InternalAddEntry(entry);
  370. }
  371. BOOL PIpAccessControlList::Add(PIPSocket::Address addr, PIPSocket::Address mask, BOOL allow)
  372. {
  373.   PIpAccessControlEntry entry(addr, mask, allow);
  374.   return InternalAddEntry(entry);
  375. }
  376. BOOL PIpAccessControlList::InternalAddEntry(PIpAccessControlEntry & entry)
  377. {
  378.   PINDEX idx = GetValuesIndex(entry);
  379.   if (idx == P_MAX_INDEX)
  380.     idx = Append(new PIpAccessControlEntry(entry));
  381.   return operator[](idx).IsAllowed() == entry.IsAllowed();
  382. }
  383. BOOL PIpAccessControlList::Remove(const PString & description)
  384. {
  385.   PIpAccessControlEntry entry(description);
  386.   if (!entry.IsValid())
  387.     return FALSE;
  388.   return InternalRemoveEntry(entry);
  389. }
  390. BOOL PIpAccessControlList::Remove(PIPSocket::Address addr, PIPSocket::Address mask)
  391. {
  392.   PIpAccessControlEntry entry(addr, mask, TRUE);
  393.   return InternalRemoveEntry(entry);
  394. }
  395. BOOL PIpAccessControlList::InternalRemoveEntry(PIpAccessControlEntry & entry)
  396. {
  397.   PINDEX idx = GetValuesIndex(entry);
  398.   if (idx == P_MAX_INDEX)
  399.     return FALSE;
  400.   RemoveAt(idx);
  401.   return TRUE;
  402. }
  403. BOOL PIpAccessControlList::IsAllowed(PIPSocket::Address address)
  404. {
  405.   PINDEX size = GetSize();
  406.   if (size == 0)
  407.     return TRUE;
  408.   for (PINDEX i = 0; i < size; i++) {
  409.     PIpAccessControlEntry & entry = operator[](i);
  410.     if (entry.Match(address))
  411.       return entry.IsAllowed();
  412.   }
  413.   return FALSE;
  414. }
  415. // End of File ///////////////////////////////////////////////////////////////