nis-util  1.0.D108
lib/space/networks.cc
Go to the documentation of this file.
00001 //
00002 // nis-util - NIS Administration Utilities
00003 // Copyright (C) 2002, 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 <lib/ac/string.h>
00022 #include <netinet/in.h>
00023 
00024 #include <lib/net_utils.h>
00025 #include <lib/space/networks.h>
00026 #include <lib/rcstring/accumulator.h>
00027 
00028 
00029 space_networks::~space_networks()
00030 {
00031 }
00032 
00033 
00034 space_networks::space_networks(const rcstring &a_filename) :
00035     space(a_filename),
00036     last_addr(0)
00037 {
00038     discard_comments();
00039     discard_blank_lines();
00040 }
00041 
00042 
00043 space_networks::pointer
00044 space_networks::create(const rcstring &a_filename)
00045 {
00046     return pointer(new space_networks(a_filename));
00047 }
00048 
00049 
00050 bool
00051 space_networks::is_ok_name(const rcstring &input)
00052 {
00053     rcstring dummy;
00054     return is_ok_name(input, dummy);
00055 }
00056 
00057 
00058 bool
00059 space_networks::is_ok_name(const rcstring &input, rcstring &output)
00060 {
00061     const char *cp = input.c_str();
00062     const char *end = cp + (input.size() < 40 ? input.size() : 40);
00063     rcstring_accumulator acc;
00064     while (cp < end)
00065     {
00066         unsigned char c = *cp++;
00067         assert(c != '\0');
00068         switch (c)
00069         {
00070         case '0': case '1': case '2': case '3': case '4':
00071         case '5': case '6': case '7': case '8': case '9':
00072         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
00073         case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
00074         case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
00075         case 'v': case 'w': case 'x': case 'y': case 'z':
00076         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
00077         case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
00078         case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
00079         case 'V': case 'W': case 'X': case 'Y': case 'Z':
00080         case '_': case'-':
00081             acc.push_back(c);
00082             break;
00083 
00084         default:
00085             acc.push_back('_');
00086             break;
00087         }
00088     }
00089     output = acc.mkstr();
00090     return (input == output);
00091 }
00092 
00093 
00094 space_networks::record::pointer
00095 space_networks::get(void)
00096 {
00097     for (;;)
00098     {
00099         source_location line_locn;
00100         line_t line;
00101         if (!read_one_line(line_locn, line))
00102             return record::pointer();
00103         if (line.size() < 2)
00104         {
00105             error
00106             (
00107                 line_locn,
00108                 "too few fields (expected 2, given %ld)",
00109                 (long)line.size()
00110             );
00111             continue;
00112         }
00113 
00114         //
00115         // Check the network name
00116         //
00117         rcstring rec_name = line[0];
00118         {
00119             rcstring suggest;
00120             if (!is_ok_name(rec_name, suggest))
00121             {
00122                 error
00123                 (
00124                     line_locn,
00125                     "network name %s not valid, suggest %s instead",
00126                     rec_name.quote_c().c_str(),
00127                     suggest.quote_c().c_str()
00128                 );
00129                 continue;
00130             }
00131         }
00132 
00133         //
00134         // Check the network number.
00135         //
00136         rcstring rec_number = line[1];
00137         in_addr tmp_addr;
00138         if (!inet_aton(rec_number.c_str(), &tmp_addr))
00139         {
00140             error
00141             (
00142                 line_locn,
00143                 "network number %s not valid",
00144                 rec_number.quote_c().c_str()
00145             );
00146             continue;
00147         }
00148         rcstring temp(inet_ntoa(tmp_addr));
00149         if (temp != rec_number)
00150         {
00151             error
00152             (
00153                 line_locn,
00154                 "network number %s not in correct format, use %s instead",
00155                 rec_number.quote_c().c_str(),
00156                 temp.quote_c().c_str()
00157             );
00158         }
00159         rec_number = temp;
00160         unsigned long rec_number_binary = ntohl(tmp_addr.s_addr);
00161 
00162         //
00163         // Make sure there are at least 2 bits not occupied by network
00164         // number, otherwise there are not bits for hosts.
00165         //
00166         if (rec_number_binary & 3)
00167         {
00168             unsigned long suggest = rec_number_binary & ~3;
00169             rcstring suggest_str = string_from_network_number(suggest);
00170             error
00171             (
00172                 line_locn,
00173                 "network %s has no room for any hosts, suggest %s instead",
00174                 rec_number.quote_c().c_str(),
00175                 suggest_str.quote_c().c_str()
00176             );
00177             rec_number = suggest_str;
00178             rec_number_binary = suggest;
00179         }
00180 
00181         //
00182         // Check that it is class A, B or C.
00183         // Any other class is invalid.
00184         //
00185         int net_class = network_class_from_number(rec_number_binary);
00186         if (net_class > 'C')
00187         {
00188             error
00189             (
00190                 line_locn,
00191                 "networks of class %c are reserved",
00192                 net_class
00193             );
00194         }
00195 
00196         //
00197         // Check record ordering
00198         //
00199         if (last_addr > rec_number_binary)
00200         {
00201             error
00202             (
00203                 line_locn,
00204                 "address %s out of order",
00205                 rec_number.quote_c().c_str()
00206             );
00207             explain_sequence_errors();
00208         }
00209         last_addr = rec_number_binary;
00210 
00211         //
00212         // Check the network aliases
00213         //
00214         record::aliases_t rec_aliases;
00215         for
00216         (
00217             line_t::const_iterator it = line.begin() + 2;
00218             it != line.end();
00219             ++it
00220         )
00221         {
00222             rcstring suggest;
00223             if (!is_ok_name(*it, suggest))
00224             {
00225                 error
00226                 (
00227                     line_locn,
00228                     "network alias %s not valid, suggest %s instead",
00229                     it->quote_c().c_str(),
00230                     suggest.quote_c().c_str()
00231                 );
00232             }
00233             rec_aliases.push_back(*it);
00234         }
00235 
00236         //
00237         // build the record, and return it to the caller.
00238         //
00239         return record::create(line_locn, rec_name, rec_number, rec_aliases);
00240     }
00241 }
00242 
00243 
00244 space_networks::record::~record()
00245 {
00246 }
00247 
00248 
00249 space_networks::record::record(
00250     const source_location &a_locn,
00251     const rcstring &a_name,
00252     const rcstring &a_number,
00253     const aliases_t &a_aliases
00254 ) :
00255     locn(a_locn),
00256     name(a_name),
00257     number(a_number),
00258     aliases(a_aliases)
00259 {
00260 }
00261 
00262 
00263 space_networks::record::pointer
00264 space_networks::record::create(const source_location &a_locn,
00265     const rcstring &a_name, const rcstring &a_number,
00266     const aliases_t &a_aliases)
00267 {
00268     return pointer(new record(a_locn, a_name, a_number, a_aliases));
00269 }
00270 
00271 
00272 unsigned long
00273 space_networks::record::get_number_binary(void)
00274     const
00275 {
00276     return network_number_from_string(number);
00277 }
00278 
00279 
00280 rcstring
00281 space_networks::record::representation(void)
00282     const
00283 {
00284     rcstring_accumulator acc;
00285     acc.push_back(name);
00286     acc.push_back(' ');
00287     acc.push_back(number);
00288     for
00289     (
00290         aliases_t::const_iterator it = aliases.begin();
00291         it != aliases.end();
00292         ++it
00293     )
00294     {
00295         acc.push_back(' ');
00296         acc.push_back(*it);
00297     }
00298     return acc.mkstr();
00299 }
00300 
00301 
00302 // vim: set ts=8 sw=4 et :