nis-util  1.0.D108
lib/space/netid.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 <lib/ac/string.h>
00020 
00021 #include <lib/rcstring/accumulator.h>
00022 #include <lib/space/netid.h>
00023 
00024 
00025 space_netid::~space_netid()
00026 {
00027 }
00028 
00029 
00030 space_netid::space_netid(const rcstring &a_filename) :
00031     space(a_filename),
00032     last_uid(-1)
00033 {
00034     // discard_comments(); can't, because of netid of the form "a.b#c"
00035     discard_blank_lines();
00036 }
00037 
00038 
00039 space_netid::pointer
00040 space_netid::create(const rcstring &a_filename)
00041 {
00042     return pointer(new space_netid(a_filename));
00043 }
00044 
00045 
00046 space_netid::record::pointer
00047 space_netid::get(void)
00048 {
00049     for (;;)
00050     {
00051         source_location line_locn;
00052         line_t line;
00053         if (!read_one_line(line_locn, line))
00054         {
00055             last_uid = -1;
00056             return record::pointer();
00057         }
00058 
00059         //
00060         // Check that the record is in one of two valid formats.
00061         //
00062         //   unix.<uid>@<domain> <uid>:<gid>,<gid>...
00063         //   unix.<host>#<domain> 0:<host>
00064         //              ^
00065         //              `-- conflicts with comments?!?
00066         //
00067         // In the first format, it isn't essential for the two <uid>
00068         // fields to be the same.  This is becase in the case where we
00069         // are mapping a foreign ID into a local user, they probably
00070         // won't match.
00071         //
00072         // In the second format, it's hard to figure out what mapping a
00073         // foreign host's permissions to a local host's permissions means.
00074         // It certainly doesn't sound especially desirable.
00075         //
00076         if (line.size() < 2)
00077         {
00078             error
00079             (
00080                 line_locn,
00081                 "too few fields (expeced 2, given %d)",
00082                 (int)line.size()
00083             );
00084             continue;
00085         }
00086         if (line.size() > 2)
00087         {
00088             error
00089             (
00090                 line_locn,
00091                 "too many fields (expected 2, given %ld)",
00092                 (long)line.size()
00093             );
00094         }
00095 
00096         //
00097         // Pull apart the first word.
00098         //
00099         // unix.{rec_id}@{rec_domain}
00100         //
00101         rcstring rec_uid1;
00102         rcstring rec_domain;
00103         bool host_rec = false;
00104         {
00105             rcstring first = line[0];
00106             if (!first.starts_with("unix."))
00107             {
00108                 error
00109                 (
00110                     line_locn,
00111                     "netid name %s not valid, must start with \"unix.\"",
00112                     line[0].quote_c().c_str()
00113                 );
00114                 continue;
00115             }
00116             first = first.substr(5, first.size() - 5);
00117 
00118             const char *at = strchr(first.c_str(), '@');
00119             if (at)
00120             {
00121                 rcstring first1(first.c_str(), at - first.c_str());
00122                 ++at;
00123                 rcstring first2(at);
00124                 long first1_bin = -1;
00125                 if (!first1.to_long(first1_bin) || first1_bin < 0)
00126                 {
00127                     error
00128                     (
00129                         line_locn,
00130                         "netid name %s not valid, uid %s not valid",
00131                         line[0].quote_c().c_str(),
00132                         first1.quote_c().c_str()
00133                     );
00134                     continue;
00135                 }
00136                 // normalise
00137                 first1 = rcstring::format("%ld", first1_bin);
00138 
00139                 if (first1_bin < last_uid)
00140                 {
00141                     error(line_locn, "user id %ld out of order", first1_bin);
00142                     explain_sequence_errors();
00143                 }
00144                 last_uid = first1_bin;
00145 
00146                 rec_uid1 = first1;
00147                 rec_domain = first2;
00148             }
00149             else
00150             {
00151                 const char *hash = strchr(first.c_str(), '#');
00152                 if (!hash)
00153                 {
00154                     error
00155                     (
00156                         line_locn,
00157                         "netid name %s not valid",
00158                         line[0].quote_c().c_str()
00159                     );
00160                     continue;
00161                 }
00162                 host_rec = true;
00163                 rcstring first1(first.c_str(), hash - first.c_str());
00164                 ++hash;
00165                 rcstring first2(hash);
00166 
00167                 long first1_bin = -1;
00168                 if (first1.to_long(first1_bin))
00169                 {
00170                     error
00171                     (
00172                         line_locn,
00173                         "netid name %s not valid, host name %s not valid",
00174                         line[0].quote_c().c_str(),
00175                         first1.quote_c().c_str()
00176                     );
00177                 }
00178                 rec_uid1 = first1;
00179                 rec_domain = first2;
00180             }
00181         }
00182 
00183         //
00184         // Pull apart the second word.
00185         //
00186         // {uid}:{gid},{gid}...
00187         // 0:{host},{host},...
00188         //
00189         rcstring rec_uid2;
00190         record::gids_t rec_gids;
00191         {
00192             rcstring second = line[1];
00193             const char *colon = strchr(second.c_str(), ':');
00194             if (!colon)
00195             {
00196                 error
00197                 (
00198                     line_locn,
00199                     "netid value %s not valid, no '@' or '#' separator",
00200                     line[1].quote_c().c_str()
00201                 );
00202                 continue;
00203             }
00204             rcstring second1(second.c_str(), colon - second.c_str());
00205             long second1_bin = -1;
00206             if (!second1.to_long(second1_bin) || second1_bin < 0)
00207             {
00208                 error
00209                 (
00210                     line_locn,
00211                     "netid value %s not valid, "
00212                         "user id %s not a positive number",
00213                     line[1].quote_c().c_str(),
00214                     second1.quote_c().c_str()
00215                 );
00216                 continue;
00217             }
00218             if (host_rec && second1_bin != 0)
00219             {
00220                 error
00221                 (
00222                     line_locn,
00223                     "netid value %s not valid, user id must be \"0\", not %s",
00224                     second.quote_c().c_str(),
00225                     second1.quote_c().c_str()
00226                 );
00227             }
00228             second1 = rcstring::format("%ld", second1_bin); // normalise
00229             ++colon;
00230             rcstring second2(colon, second.c_str() + second.size() - colon);
00231 
00232             rec_uid2 = second1;
00233             rec_gids = second2.break_up(",", false);
00234             bool gids_ok = true;
00235             for
00236             (
00237                 record::gids_t::iterator git = rec_gids.begin();
00238                 git != rec_gids.end();
00239                 ++git
00240             )
00241             {
00242                 long value = -1;
00243                 if (!git->to_long(value) || value < 0)
00244                 {
00245                     if (!host_rec)
00246                     {
00247                         error
00248                         (
00249                             line_locn,
00250                             "netid value %s not valid, "
00251                                 "group id %s not a positive number",
00252                             second.quote_c().c_str(),
00253                             git->quote_c().c_str()
00254                         );
00255                         gids_ok = false;
00256                     }
00257                 }
00258                 else
00259                 {
00260                     if (host_rec)
00261                     {
00262                         error
00263                         (
00264                             line_locn,
00265                             "netid value %s not valid, host name %s not valid",
00266                             second.quote_c().c_str(),
00267                             git->quote_c().c_str()
00268                         );
00269                         gids_ok = false;
00270                     }
00271                     else
00272                     {
00273                         // normalise
00274                         *git = rcstring::format("%ld", value);
00275                     }
00276                 }
00277             }
00278             if (!gids_ok)
00279                 continue;
00280         }
00281 
00282         //
00283         // Got a record.
00284         //
00285         record::pointer rp =
00286             space_netid::record::create
00287             (
00288                 line_locn,
00289                 rec_uid1,
00290                 rec_domain,
00291                 rec_uid2,
00292                 rec_gids
00293             );
00294 
00295         //
00296         // check the line length
00297         //
00298         if (rp->representation().size() >= 512)
00299         {
00300             error
00301             (
00302                 rp->get_source_location(),
00303                 "line too long (NIS limits records to 511 bytes)"
00304             );
00305         }
00306 
00307         //
00308         // report success
00309         //
00310         return rp;
00311     }
00312 }
00313 
00314 
00315 space_netid::record::~record()
00316 {
00317 }
00318 
00319 
00320 space_netid::record::record(
00321     const source_location &a_locn,
00322     const rcstring &a_uid1,
00323     const rcstring &a_domain,
00324     const rcstring &a_uid2,
00325     const gids_t &a_gids
00326 ) :
00327     locn(a_locn),
00328     uid1(a_uid1),
00329     domain(a_domain),
00330     uid2(a_uid2),
00331     gids(a_gids)
00332 {
00333 }
00334 
00335 
00336 space_netid::record::pointer
00337 space_netid::record::create(const source_location &a_locn,
00338     const rcstring &a_uid1, const rcstring &a_domain, const rcstring &a_uid2,
00339     const gids_t &a_gids)
00340 {
00341     return pointer(new record(a_locn, a_uid1, a_domain, a_uid2, a_gids));
00342 }
00343 
00344 
00345 rcstring
00346 space_netid::record::name(void)
00347     const
00348 {
00349     long dummy;
00350     if (uid2 == "0" && !uid1.to_long(dummy))
00351         return ("unix." + uid1 + "#" + domain);
00352     return ("unix." + uid1 + "@" + domain);
00353 }
00354 
00355 
00356 rcstring
00357 space_netid::record::representation(void)
00358     const
00359 {
00360     rcstring_accumulator acc;
00361     acc.push_back("unix.");
00362     acc.push_back(uid1);
00363     acc.push_back(is_host_kind() ? '#' : '@');
00364     acc.push_back(domain);
00365     acc.push_back(' ');
00366     acc.push_back(uid2);
00367     acc.push_back(':');
00368     for (gids_t::const_iterator it = gids.begin(); it != gids.end(); ++it)
00369     {
00370         if (it != gids.begin())
00371             acc.push_back(',');
00372         acc.push_back(*it);
00373     }
00374     return acc.mkstr();
00375 }
00376 
00377 
00378 bool
00379 space_netid::record::is_host_kind(void)
00380     const
00381 {
00382     long dummy;
00383     return !uid1.to_long(dummy);
00384 }
00385 
00386 
00387 void
00388 space_netid::record::append(const rcstring &arg)
00389 {
00390     for (gids_t::const_iterator it = gids.begin(); it != gids.end(); ++it)
00391     {
00392         if (*it == arg)
00393             return;
00394     }
00395     gids.push_back(arg);
00396 }
00397 
00398 
00399 // vim: set ts=8 sw=4 et :