nis-util
1.0.D108
|
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 :