nis-util
1.0.D108
|
00001 // 00002 // nis-util - NIS Administration Utilities 00003 // Copyright (C) 2001, 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/errno.h> 00020 #include <lib/ac/string.h> 00021 #include <lib/ac/sys/types.h> 00022 #include <lib/ac/sys/stat.h> 00023 #include <lib/ac/unistd.h> 00024 #include <libexplain/lstat.h> 00025 00026 #include <lib/colon/group/slurp.h> 00027 #include <lib/colon/passwd/slurp/check.h> 00028 #include <lib/path_join.h> 00029 00030 00031 colon_passwd_slurp_check::~colon_passwd_slurp_check() 00032 { 00033 } 00034 00035 00036 colon_passwd_slurp_check::colon_passwd_slurp_check( 00037 const rcstring &a_filename, 00038 const colon_group_slurp::pointer &a_group 00039 ) : 00040 colon_passwd_slurp(a_filename), 00041 group(a_group) 00042 { 00043 } 00044 00045 00046 colon_passwd_slurp_check::pointer 00047 colon_passwd_slurp_check::create(const rcstring &a_filename, 00048 const colon_group_slurp::pointer &a_group) 00049 { 00050 return pointer(new colon_passwd_slurp_check(a_filename, a_group)); 00051 } 00052 00053 00054 bool 00055 colon_passwd_slurp_check::process(const record::pointer &rp) 00056 { 00057 // Do all the base class's processing first. 00058 if (!colon_passwd_slurp::process(rp)) 00059 return false; 00060 00061 // 00062 // Check the GID field 00063 // 00064 { 00065 const colon_group::record::pointer gp = 00066 group->query_by_gid(rp->get_gid()); 00067 if (!gp) 00068 { 00069 error 00070 ( 00071 rp->get_source_location(), 00072 "user %s: group id %s unknown", 00073 rp->get_name().quote_c().c_str(), 00074 rp->get_gid().quote_c().c_str() 00075 ); 00076 return false; 00077 } 00078 00079 if (!gp->get_use_instead().empty()) 00080 { 00081 const colon_group::record::pointer gp2 = 00082 group->query_by_name(gp->get_use_instead()); 00083 if (gp2) 00084 { 00085 error 00086 ( 00087 rp->get_source_location(), 00088 "user %s: default group %s (gid %s) is not suitable, " 00089 "use group %s (gid %s) instead", 00090 rp->get_name().quote_c().c_str(), 00091 gp->get_name().quote_c().c_str(), 00092 rp->get_gid().c_str(), 00093 gp2->get_name().quote_c().c_str(), 00094 gp2->get_gid().c_str() 00095 ); 00096 } 00097 else 00098 { 00099 error 00100 ( 00101 rp->get_source_location(), 00102 "user %s: default group %s (gid %s) is not suitable, " 00103 "use group %s instead", 00104 rp->get_name().quote_c().c_str(), 00105 gp->get_name().quote_c().c_str(), 00106 rp->get_gid().c_str(), 00107 gp->get_use_instead().quote_c().c_str() 00108 ); 00109 } 00110 return false; 00111 } 00112 else if (gp->is_members_only()) 00113 { 00114 // 00115 // Groups marked "MEMBERS-ONLY" may only be used by the user 00116 // of the same name, or group members. 00117 // 00118 if 00119 ( 00120 gp->get_name() != rp->get_name() 00121 && 00122 !gp->is_member(rp->get_name()) 00123 ) 00124 { 00125 error 00126 ( 00127 rp->get_source_location(), 00128 "user %s: default group %s (gid %s) is reserved, and may " 00129 "not be used as this user's default group", 00130 rp->get_name().quote_c().c_str(), 00131 gp->get_name().quote_c().c_str(), 00132 rp->get_gid().c_str() 00133 ); 00134 return false; 00135 } 00136 } 00137 } 00138 00139 // 00140 // Check full name field. 00141 // 00142 00143 // 00144 // Check home directory 00145 // 00146 // FIXME: make sure the home directory is in an automount map. 00147 // 00148 if (!check_home(rp)) 00149 return false; 00150 00151 // 00152 // Check shell. 00153 // 00154 // FIXME: check against the /etc/shell file (or some similar 00155 // command line argument). 00156 00157 // 00158 // Looks good so far. 00159 // 00160 return true; 00161 } 00162 00163 00164 bool 00165 colon_passwd_slurp_check::check_home(const record::pointer &rp) 00166 { 00167 // Note: this makes the bold assumption that the server building 00168 // the NIS maps is itself using those same NIS maps. 00169 // Otherwise this check is always going to fail. 00170 00171 struct stat st; 00172 if (lstat(rp->get_home().c_str(), &st) < 0) 00173 { 00174 if (errno != ENOENT) 00175 { 00176 error 00177 ( 00178 rp->get_source_location(), 00179 "%s", 00180 explain_lstat(rp->get_home().c_str(), &st) 00181 ); 00182 } 00183 #if 1 00184 return false; 00185 #else 00186 // make a fake ok status 00187 memset(&st, 0, sizeof(st)); 00188 st.st_mode = S_IFDIR | 02755; 00189 st.st_uid = rp->get_uid_binary(); 00190 st.st_gid = rp->get_gid_binary(); 00191 #endif 00192 } 00193 00194 if (S_ISLNK(st.st_mode)) 00195 { 00196 // Note: The sun automounter uses symbolic links when it automounts 00197 // a file system, fromthe use point to the actual mount point. 00198 // This is especially true when the auto mount is actually 00199 // local to the NIS client using the passwd map. 00200 // Thus, symbolic links usually mean a mistake. 00201 00202 rcstring link_destination; 00203 { 00204 char buffer[2000]; 00205 int n = readlink(rp->get_home().c_str(), buffer, sizeof(buffer)); 00206 if (n <= 0) 00207 { 00208 error 00209 ( 00210 rp->get_source_location(), 00211 "user %s home directory %s may not be a symbolic link", 00212 rp->get_name().quote_c().c_str(), 00213 rp->get_home().quote_c().c_str() 00214 ); 00215 return false; 00216 } 00217 link_destination = rcstring(buffer, n); 00218 } 00219 00220 rcstring suggest; 00221 if (link_destination.front() == '/') 00222 suggest = link_destination; 00223 else 00224 { 00225 rcstring dir = rp->get_home().dirname(); 00226 suggest = path_join(dir, link_destination); 00227 } 00228 error 00229 ( 00230 rp->get_source_location(), 00231 "user %s home directory %s may not be a symbolic link, " 00232 "suggest %s instead", 00233 rp->get_name().quote_c().c_str(), 00234 rp->get_home().quote_c().c_str(), 00235 suggest.quote_c().c_str() 00236 ); 00237 return false; 00238 } 00239 if (!S_ISDIR(st.st_mode)) 00240 { 00241 error 00242 ( 00243 rp->get_source_location(), 00244 "user %s home directory %s must be a directory", 00245 rp->get_name().quote_c().c_str(), 00246 rp->get_home().c_str() 00247 ); 00248 return false; 00249 } 00250 00251 if ((st.st_mode & 05733) != 00711) 00252 { 00253 error 00254 ( 00255 rp->get_source_location(), 00256 "user %s home directory %s is mode %#o, it should be 02755, " 00257 "suggest...", 00258 rp->get_name().quote_c().c_str(), 00259 rp->get_home().c_str(), 00260 (st.st_mode & 07777) 00261 ); 00262 error 00263 ( 00264 rp->get_source_location(), 00265 "sudo chmod %#o %s", 00266 ((st.st_mode & 02755) | 00711), 00267 rp->get_home().quote_shell().c_str() 00268 ); 00269 } 00270 00271 { 00272 long uid = rp->get_uid_binary(); 00273 if (uid >= 0) 00274 { 00275 if ((long)st.st_uid != uid) 00276 { 00277 rcstring old_uid; 00278 record::pointer oup = query_by_uid(st.st_uid); 00279 if (oup) 00280 old_uid = oup->get_uid(); 00281 else 00282 old_uid = rcstring::format("%ld", (long)st.st_uid); 00283 00284 rcstring new_owner = rp->get_name(); 00285 long gid = rp->get_gid_binary(); 00286 if (gid >= 0) 00287 { 00288 if (gid != (long)st.st_gid) 00289 { 00290 colon_group::record::pointer grp = 00291 group->query_by_gid(rp->get_gid()); 00292 if (grp) 00293 new_owner += "." + grp->get_name(); 00294 else 00295 new_owner += rcstring::format(".%ld", gid); 00296 } 00297 } 00298 00299 warning 00300 ( 00301 rp->get_source_location(), 00302 "user %s home directory %s is owned by %s, it " 00303 "should be %s, suggest...", 00304 rp->get_name().quote_c().c_str(), 00305 rp->get_home().quote_c().c_str(), 00306 old_uid.quote_c().c_str(), 00307 rp->get_name().quote_c().c_str() 00308 ); 00309 warning 00310 ( 00311 rp->get_source_location(), 00312 "sudo chown %s %s", 00313 new_owner.quote_shell().c_str(), 00314 rp->get_home().quote_shell().c_str() 00315 ); 00316 return false; 00317 } 00318 } 00319 } 00320 00321 { 00322 long gid = rp->get_gid_binary(); 00323 if (gid >= 0) 00324 { 00325 if ((long)st.st_gid != gid) 00326 { 00327 // determine the name of the old group 00328 rcstring old_group; 00329 { 00330 colon_group::record::pointer grp = 00331 group->query_by_gid(st.st_gid); 00332 if (grp) 00333 old_group = grp->get_name(); 00334 else 00335 old_group = rcstring::format("%ld", (long)st.st_gid); 00336 } 00337 00338 // determine the name of the new group 00339 rcstring new_group; 00340 { 00341 colon_group::record::pointer grp = 00342 group->query_by_gid(rp->get_gid()); 00343 if (grp) 00344 new_group = grp->get_name(); 00345 else 00346 new_group = rp->get_gid(); 00347 } 00348 00349 warning 00350 ( 00351 rp->get_source_location(), 00352 "user %s home directory \"%s\" is group %s, it " 00353 "should be %s, suggest...", 00354 rp->get_name().quote_c().c_str(), 00355 rp->get_home().quote_c().c_str(), 00356 old_group.quote_c().c_str(), 00357 new_group.quote_c().c_str() 00358 ); 00359 warning 00360 ( 00361 rp->get_source_location(), 00362 "sudo chgrp %s %s", 00363 new_group.quote_shell().c_str(), 00364 rp->get_home().quote_shell().c_str() 00365 ); 00366 } 00367 } 00368 } 00369 00370 return true; 00371 } 00372 00373 00374 // vim: set ts=8 sw=4 et :