nis-util  1.0.D108
lib/space/hosts.cc
Go to the documentation of this file.
00001 //
00002 // nis-util - NIS Administration Utilities
00003 // Copyright (C) 2001-2003, 2008, 2009, 2011, 2012 Peter Miller
00004 //
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 2 of the License, or (at
00008 // your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program. If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 #include <arpa/inet.h>
00020 #include <lib/ac/ctype.h>
00021 #include <netinet/in.h>
00022 #include <libexplain/realloc.h>
00023 
00024 #include <lib/configuration.h>
00025 #include <lib/space/hosts.h>
00026 
00027 
00028 space_hosts::~space_hosts()
00029 {
00030 }
00031 
00032 
00033 space_hosts::space_hosts(const rcstring &a_filename) :
00034     space(a_filename)
00035 {
00036     // This host's sysconf(HOST_NAME_MAX)-1 may be too generous for
00037     // all NIS clients.  Be conservative.
00038     cfg.set_builtin_long("hosts", ITEM_NAME_LENGTH_MAXIMUM, 63);
00039 
00040     discard_comments();
00041     discard_blank_lines();
00042 }
00043 
00044 
00045 space_hosts::pointer
00046 space_hosts::create(const rcstring &filename)
00047 {
00048     return pointer(new space_hosts(filename));
00049 }
00050 
00051 
00052 bool
00053 space_hosts::valid_ip_address(const rcstring &input, rcstring &output)
00054 {
00055     in_addr ipa;
00056     if (!inet_aton(input.c_str(), &ipa))
00057         return false;
00058     output = rcstring(inet_ntoa(ipa));
00059     return true;
00060 }
00061 
00062 
00063 bool
00064 space_hosts::valid_host_name(const rcstring &input, rcstring &output)
00065 {
00066     if (input.empty())
00067     {
00068         output = rcstring("_");
00069         return false;
00070     }
00071 
00072     enum { max_distance_between_dots = 63 };
00073 
00074     //
00075     // Temporary buffer to hold sanitised name.
00076     //
00077     static size_t bufmax;
00078     static char *buffer;
00079     while (bufmax < input.size())
00080     {
00081         bufmax = bufmax * 2 + 16;
00082         buffer = (char *)explain_realloc_or_die((void *)buffer, bufmax);
00083     }
00084     char *bp = buffer;
00085 
00086     //
00087     // Sanitize the name.
00088     //
00089     // FIXME: what is the BIND RFC (1035?),
00090     // and what does it say about names?
00091     //
00092     bool ok = true;
00093     const char *start = input.c_str();
00094     const char *ip = start;
00095     for (; *ip; ++ip)
00096     {
00097         int c = (unsigned char)*ip;
00098         if (c == '.')
00099         {
00100             if (!ip[1] || ip == start)
00101             {
00102                 c = '_';
00103                 ok = false;
00104             }
00105             else
00106             {
00107                 if (ip - start > max_distance_between_dots)
00108                 {
00109                     // move the output pointer back
00110                     bp += max_distance_between_dots + (start - ip);
00111                     ok = false;
00112                 }
00113 
00114                 // Can't have two dots in a row
00115                 start = ip + 1;
00116             }
00117         }
00118         else if (isupper(c))
00119             c = tolower(c);
00120         else if (isalnum(c))
00121             ;
00122         else if (c != '-' && c != '_')
00123         {
00124             c = '_';
00125             ok = false;
00126         }
00127         *bp++ = c;
00128     }
00129     if (ip - start > max_distance_between_dots)
00130     {
00131         // move the output pointer back
00132         bp += max_distance_between_dots + (start - ip);
00133         ok = false;
00134     }
00135     output = rcstring(buffer, bp - buffer);
00136     return ok;
00137 }
00138 
00139 
00140 space_hosts::record::pointer
00141 space_hosts::get(void)
00142 {
00143     for (;;)
00144     {
00145         source_location glocn;
00146         line_t line;
00147         if (!read_one_line(glocn, line))
00148         {
00149             last_rp.reset();
00150             return record::pointer();
00151         }
00152         if (line.size() < 2)
00153         {
00154             error
00155             (
00156                 glocn,
00157                 "too few fields (expected at least 2, given %ld)",
00158                 (long)line.size()
00159             );
00160             continue;
00161         }
00162 
00163         //
00164         // Check IP Address.
00165         //
00166         in_addr tmp_addr;
00167         if (!inet_aton(line[0].c_str(), &tmp_addr))
00168         {
00169             error(glocn, "IP address %s not valid", line[0].quote_c().c_str());
00170             continue;
00171         }
00172         rcstring temp(inet_ntoa(tmp_addr));
00173         if (temp != line[0])
00174         {
00175             error
00176             (
00177                 glocn,
00178                 "IP address %s not in correct format, use %s instead",
00179                 line[0].quote_c().c_str(),
00180                 temp.quote_c().c_str()
00181             );
00182             line[0] = temp;
00183         }
00184 
00185         //
00186         // Check names
00187         //
00188         record::names_t names;
00189         for
00190         (
00191             line_t::iterator it = line.begin() + 1;
00192             it != line.end();
00193             ++it
00194         )
00195         {
00196             rcstring canonical_name;
00197             if (!valid_host_name(*it, canonical_name))
00198             {
00199                 error
00200                 (
00201                     glocn,
00202                     "host name %s is not valid, suggest %s instead",
00203                     it->quote_c().c_str(),
00204                     canonical_name.quote_c().c_str()
00205                 );
00206             }
00207             else if (*it != canonical_name)
00208             {
00209                 error
00210                 (
00211                     glocn,
00212                     "host name %s not in correct format, use %s instead",
00213                     it->quote_c().c_str(),
00214                     canonical_name.quote_c().c_str()
00215                 );
00216             }
00217             names.push_back(canonical_name);
00218         }
00219 
00220         record::pointer rp = record::create(glocn, line[0], names);
00221 
00222         //
00223         // Check record ordering
00224         // (this finds common typographical errors)
00225         //
00226         if (last_rp && *rp < *last_rp)
00227         {
00228             error
00229             (
00230                 rp->get_source_location(),
00231                 "address %s out of order",
00232                 rp->get_ip_address().quote_c().c_str()
00233             );
00234             explain_sequence_errors();
00235         }
00236         last_rp = rp;
00237 
00238         //
00239         // return the record
00240         //
00241         return rp;
00242     }
00243 }
00244 
00245 
00246 space_hosts::record::~record()
00247 {
00248 }
00249 
00250 
00251 space_hosts::record::record(
00252     const source_location &a_locn,
00253     const rcstring &a_ip_address,
00254     const names_t &a_names
00255 ) :
00256     locn(a_locn),
00257     ip_address(a_ip_address),
00258     names(a_names),
00259     ip_address_binary(0)
00260 {
00261     in_addr tmp_addr;
00262     if (inet_aton(ip_address.c_str(), &tmp_addr))
00263         ip_address_binary = ntohl(tmp_addr.s_addr);
00264 }
00265 
00266 
00267 space_hosts::record::pointer
00268 space_hosts::record::create(const source_location &a_locn,
00269     const rcstring &a_ip_address, const names_t &a_names)
00270 {
00271     return pointer(new record(a_locn, a_ip_address, a_names));
00272 }
00273 
00274 
00275 rcstring
00276 space_hosts::record::representation(void)
00277     const
00278 {
00279     rcstring result = ip_address;
00280     for
00281     (
00282         std::vector<rcstring>::const_iterator it = names.begin();
00283         it != names.end();
00284         ++it
00285     )
00286     {
00287         result += " " + *it;
00288     }
00289     return result;
00290 }
00291 
00292 
00293 bool
00294 space_hosts::record::operator<(const record &rhs)
00295     const
00296 {
00297     return (ip_address_binary < rhs.ip_address_binary);
00298 }
00299 
00300 
00301 bool
00302 space_hosts::record::operator<=(const record &rhs)
00303     const
00304 {
00305     return (ip_address_binary <= rhs.ip_address_binary);
00306 }
00307 
00308 
00309 bool
00310 space_hosts::record::operator>(const record &rhs)
00311     const
00312 {
00313     return (ip_address_binary > rhs.ip_address_binary);
00314 }
00315 
00316 
00317 bool
00318 space_hosts::record::operator>=(const record &rhs)
00319     const
00320 {
00321     return (ip_address_binary >= rhs.ip_address_binary);
00322 }
00323 
00324 
00325 // vim: set ts=8 sw=4 et :