KIO
kacl.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2005 - 2007 Till Adam <adam@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 // $Id: kacl.cpp 424977 2005-06-13 15:13:22Z tilladam $ 00020 00021 #include "kacl.h" 00022 00023 #include <config-acl.h> 00024 00025 #include <sys/types.h> 00026 #include <pwd.h> 00027 #include <grp.h> 00028 #include <sys/stat.h> 00029 #ifdef HAVE_POSIX_ACL 00030 #include <sys/acl.h> 00031 #include <acl/libacl.h> 00032 #endif 00033 #include <QHash> 00034 00035 #include <kdebug.h> 00036 00037 #include <QList> 00038 #include <QPair> 00039 00040 00041 class KACL::KACLPrivate { 00042 public: 00043 KACLPrivate() : m_acl( 0 ) {} 00044 #ifdef HAVE_POSIX_ACL 00045 KACLPrivate( acl_t acl ) 00046 : m_acl( acl ) {} 00047 ~KACLPrivate() { if ( m_acl ) acl_free( m_acl ); } 00048 #endif 00049 // helpers 00050 #ifdef HAVE_POSIX_ACL 00051 bool setMaskPermissions( unsigned short v ); 00052 QString getUserName( uid_t uid ) const; 00053 QString getGroupName( gid_t gid ) const; 00054 bool setAllUsersOrGroups( const QList< QPair<QString, unsigned short> > &list, acl_tag_t type ); 00055 bool setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type ); 00056 00057 acl_t m_acl; 00058 #else 00059 int m_acl; 00060 #endif 00061 mutable QHash<uid_t, QString> m_usercache; 00062 mutable QHash<gid_t, QString> m_groupcache; 00063 }; 00064 00065 KACL::KACL( const QString &aclString ) 00066 : d( new KACLPrivate ) 00067 { 00068 setACL( aclString ); 00069 } 00070 00071 KACL::KACL( mode_t basePermissions ) 00072 #ifdef HAVE_POSIX_ACL 00073 : d( new KACLPrivate( acl_from_mode( basePermissions ) ) ) 00074 #else 00075 : d( new KACLPrivate ) 00076 #endif 00077 { 00078 #ifndef HAVE_POSIX_ACL 00079 Q_UNUSED( basePermissions ); 00080 #endif 00081 } 00082 00083 KACL::KACL() 00084 : d( new KACLPrivate ) 00085 { 00086 } 00087 00088 KACL::KACL( const KACL& rhs ) 00089 : d( new KACLPrivate ) 00090 { 00091 setACL( rhs.asString() ); 00092 } 00093 00094 KACL::~KACL() 00095 { 00096 delete d; 00097 } 00098 00099 KACL& KACL::operator=( const KACL& rhs ) 00100 { 00101 if ( this != &rhs ) 00102 setACL( rhs.asString() ); 00103 return *this; 00104 } 00105 00106 bool KACL::operator==( const KACL& rhs ) const { 00107 #ifdef HAVE_POSIX_ACL 00108 return ( acl_cmp( d->m_acl, rhs.d->m_acl ) == 0 ); 00109 #else 00110 Q_UNUSED( rhs ); 00111 return true; 00112 #endif 00113 } 00114 00115 bool KACL::operator!=( const KACL& rhs ) const 00116 { 00117 return !operator==( rhs ); 00118 } 00119 00120 bool KACL::isValid() const 00121 { 00122 bool valid = false; 00123 #ifdef HAVE_POSIX_ACL 00124 if ( d->m_acl ) { 00125 valid = ( acl_valid( d->m_acl ) == 0 ); 00126 } 00127 #endif 00128 return valid; 00129 } 00130 00131 bool KACL::isExtended() const 00132 { 00133 #ifdef HAVE_POSIX_ACL 00134 return ( acl_equiv_mode( d->m_acl, NULL ) != 0 ); 00135 #else 00136 return false; 00137 #endif 00138 } 00139 00140 #ifdef HAVE_POSIX_ACL 00141 static acl_entry_t entryForTag( acl_t acl, acl_tag_t tag ) 00142 { 00143 acl_entry_t entry; 00144 int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry ); 00145 while ( ret == 1 ) { 00146 acl_tag_t currentTag; 00147 acl_get_tag_type( entry, ¤tTag ); 00148 if ( currentTag == tag ) 00149 return entry; 00150 ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry ); 00151 } 00152 return 0; 00153 } 00154 00155 static unsigned short entryToPermissions( acl_entry_t entry ) 00156 { 00157 if ( entry == 0 ) return 0; 00158 acl_permset_t permset; 00159 if ( acl_get_permset( entry, &permset ) != 0 ) return 0; 00160 return( acl_get_perm( permset, ACL_READ ) << 2 | 00161 acl_get_perm( permset, ACL_WRITE ) << 1 | 00162 acl_get_perm( permset, ACL_EXECUTE ) ); 00163 } 00164 00165 static void permissionsToEntry( acl_entry_t entry, unsigned short v ) 00166 { 00167 if ( entry == 0 ) return; 00168 acl_permset_t permset; 00169 if ( acl_get_permset( entry, &permset ) != 0 ) return; 00170 acl_clear_perms( permset ); 00171 if ( v & 4 ) acl_add_perm( permset, ACL_READ ); 00172 if ( v & 2 ) acl_add_perm( permset, ACL_WRITE ); 00173 if ( v & 1 ) acl_add_perm( permset, ACL_EXECUTE ); 00174 } 00175 00176 #ifdef HAVE_POSIX_ACL 00177 #if 0 00178 static void printACL( acl_t acl, const QString &comment ) 00179 { 00180 const char* txt = acl_to_text(acl); 00181 kDebug() << comment << txt; 00182 acl_free(txt); 00183 } 00184 #endif 00185 #endif 00186 00187 static int getUidForName( const QString& name ) 00188 { 00189 struct passwd *user = getpwnam( name.toLocal8Bit() ); 00190 if ( user ) 00191 return user->pw_uid; 00192 else 00193 return -1; 00194 } 00195 00196 static int getGidForName( const QString& name ) 00197 { 00198 struct group *group = getgrnam( name.toLocal8Bit() ); 00199 if ( group ) 00200 return group->gr_gid; 00201 else 00202 return -1; 00203 } 00204 #endif 00205 // ------------------ begin API implementation ------------ 00206 00207 unsigned short KACL::ownerPermissions() const 00208 { 00209 #ifdef HAVE_POSIX_ACL 00210 return entryToPermissions( entryForTag( d->m_acl, ACL_USER_OBJ ) ); 00211 #else 00212 return 0; 00213 #endif 00214 } 00215 00216 bool KACL::setOwnerPermissions( unsigned short v ) 00217 { 00218 #ifdef HAVE_POSIX_ACL 00219 permissionsToEntry( entryForTag( d->m_acl, ACL_USER_OBJ ), v ); 00220 #else 00221 Q_UNUSED( v ); 00222 #endif 00223 return true; 00224 } 00225 00226 unsigned short KACL::owningGroupPermissions() const 00227 { 00228 #ifdef HAVE_POSIX_ACL 00229 return entryToPermissions( entryForTag( d->m_acl, ACL_GROUP_OBJ ) ); 00230 #else 00231 return 0; 00232 #endif 00233 } 00234 00235 bool KACL::setOwningGroupPermissions( unsigned short v ) 00236 { 00237 #ifdef HAVE_POSIX_ACL 00238 permissionsToEntry( entryForTag( d->m_acl, ACL_GROUP_OBJ ), v ); 00239 #else 00240 Q_UNUSED( v ); 00241 #endif 00242 return true; 00243 } 00244 00245 unsigned short KACL::othersPermissions() const 00246 { 00247 #ifdef HAVE_POSIX_ACL 00248 return entryToPermissions( entryForTag( d->m_acl, ACL_OTHER ) ); 00249 #else 00250 return 0; 00251 #endif 00252 } 00253 00254 bool KACL::setOthersPermissions( unsigned short v ) 00255 { 00256 #ifdef HAVE_POSIX_ACL 00257 permissionsToEntry( entryForTag( d->m_acl, ACL_OTHER ), v ); 00258 #else 00259 Q_UNUSED( v ); 00260 #endif 00261 return true; 00262 } 00263 00264 mode_t KACL::basePermissions() const 00265 { 00266 mode_t perms( 0 ); 00267 #ifdef HAVE_POSIX_ACL 00268 if ( ownerPermissions() & ACL_READ ) perms |= S_IRUSR; 00269 if ( ownerPermissions() & ACL_WRITE ) perms |= S_IWUSR; 00270 if ( ownerPermissions() & ACL_EXECUTE ) perms |= S_IXUSR; 00271 if ( owningGroupPermissions() & ACL_READ ) perms |= S_IRGRP; 00272 if ( owningGroupPermissions() & ACL_WRITE ) perms |= S_IWGRP; 00273 if ( owningGroupPermissions() & ACL_EXECUTE ) perms |= S_IXGRP; 00274 if ( othersPermissions() & ACL_READ ) perms |= S_IROTH; 00275 if ( othersPermissions() & ACL_WRITE ) perms |= S_IWOTH; 00276 if ( othersPermissions() & ACL_EXECUTE ) perms |= S_IXOTH; 00277 #endif 00278 return perms; 00279 } 00280 00281 unsigned short KACL::maskPermissions( bool &exists ) const 00282 { 00283 exists = true; 00284 #ifdef HAVE_POSIX_ACL 00285 acl_entry_t entry = entryForTag( d->m_acl, ACL_MASK ); 00286 if ( entry == 0 ) { 00287 exists = false; 00288 return 0; 00289 } 00290 return entryToPermissions( entry ); 00291 #else 00292 return 0; 00293 #endif 00294 } 00295 00296 #ifdef HAVE_POSIX_ACL 00297 bool KACL::KACLPrivate::setMaskPermissions( unsigned short v ) 00298 { 00299 acl_entry_t entry = entryForTag( m_acl, ACL_MASK ); 00300 if ( entry == 0 ) { 00301 acl_create_entry( &m_acl, &entry ); 00302 acl_set_tag_type( entry, ACL_MASK ); 00303 } 00304 permissionsToEntry( entry, v ); 00305 return true; 00306 } 00307 #endif 00308 00309 bool KACL::setMaskPermissions( unsigned short v ) 00310 { 00311 #ifdef HAVE_POSIX_ACL 00312 return d->setMaskPermissions( v ); 00313 #else 00314 Q_UNUSED( v ); 00315 return true; 00316 #endif 00317 } 00318 00319 /************************** 00320 * Deal with named users * 00321 **************************/ 00322 unsigned short KACL::namedUserPermissions( const QString& name, bool *exists ) const 00323 { 00324 #ifdef HAVE_POSIX_ACL 00325 acl_entry_t entry; 00326 uid_t id; 00327 *exists = false; 00328 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry ); 00329 while ( ret == 1 ) { 00330 acl_tag_t currentTag; 00331 acl_get_tag_type( entry, ¤tTag ); 00332 if ( currentTag == ACL_USER ) { 00333 id = *( (uid_t*) acl_get_qualifier( entry ) ); 00334 if ( d->getUserName( id ) == name ) { 00335 *exists = true; 00336 return entryToPermissions( entry ); 00337 } 00338 } 00339 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry ); 00340 } 00341 #else 00342 Q_UNUSED( name ); 00343 Q_UNUSED( exists ); 00344 #endif 00345 return 0; 00346 } 00347 00348 #ifdef HAVE_POSIX_ACL 00349 bool KACL::KACLPrivate::setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type ) 00350 { 00351 bool allIsWell = true; 00352 acl_t newACL = acl_dup( m_acl ); 00353 acl_entry_t entry; 00354 bool createdNewEntry = false; 00355 bool found = false; 00356 int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry ); 00357 while ( ret == 1 ) { 00358 acl_tag_t currentTag; 00359 acl_get_tag_type( entry, ¤tTag ); 00360 if ( currentTag == type ) { 00361 int id = * (int*)acl_get_qualifier( entry ); 00362 const QString entryName = type == ACL_USER? getUserName( id ): getGroupName( id ); 00363 if ( entryName == name ) { 00364 // found him, update 00365 permissionsToEntry( entry, permissions ); 00366 found = true; 00367 break; 00368 } 00369 } 00370 ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry ); 00371 } 00372 if ( !found ) { 00373 acl_create_entry( &newACL, &entry ); 00374 acl_set_tag_type( entry, type ); 00375 int id = type == ACL_USER? getUidForName( name ): getGidForName( name ); 00376 if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) { 00377 acl_delete_entry( newACL, entry ); 00378 allIsWell = false; 00379 } else { 00380 permissionsToEntry( entry, permissions ); 00381 createdNewEntry = true; 00382 } 00383 } 00384 if ( allIsWell && createdNewEntry ) { 00385 // 23.1.1 of 1003.1e states that as soon as there is a named user or 00386 // named group entry, there needs to be a mask entry as well, so add 00387 // one, if the user hasn't explicitly set one. 00388 if ( entryForTag( newACL, ACL_MASK ) == 0 ) { 00389 acl_calc_mask( &newACL ); 00390 } 00391 } 00392 00393 if ( !allIsWell || acl_valid( newACL ) != 0 ) { 00394 acl_free( newACL ); 00395 allIsWell = false; 00396 } else { 00397 acl_free( m_acl ); 00398 m_acl = newACL; 00399 } 00400 return allIsWell; 00401 } 00402 #endif 00403 00404 bool KACL::setNamedUserPermissions( const QString& name, unsigned short permissions ) 00405 { 00406 #ifdef HAVE_POSIX_ACL 00407 return d->setNamedUserOrGroupPermissions( name, permissions, ACL_USER ); 00408 #else 00409 Q_UNUSED( name ); 00410 Q_UNUSED( permissions ); 00411 return true; 00412 #endif 00413 } 00414 00415 ACLUserPermissionsList KACL::allUserPermissions() const 00416 { 00417 ACLUserPermissionsList list; 00418 #ifdef HAVE_POSIX_ACL 00419 acl_entry_t entry; 00420 uid_t id; 00421 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry ); 00422 while ( ret == 1 ) { 00423 acl_tag_t currentTag; 00424 acl_get_tag_type( entry, ¤tTag ); 00425 if ( currentTag == ACL_USER ) { 00426 id = *( (uid_t*) acl_get_qualifier( entry ) ); 00427 QString name = d->getUserName( id ); 00428 unsigned short permissions = entryToPermissions( entry ); 00429 ACLUserPermissions pair = qMakePair( name, permissions ); 00430 list.append( pair ); 00431 } 00432 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry ); 00433 } 00434 #endif 00435 return list; 00436 } 00437 00438 #ifdef HAVE_POSIX_ACL 00439 bool KACL::KACLPrivate::setAllUsersOrGroups( const QList< QPair<QString, unsigned short> > &list, acl_tag_t type ) 00440 { 00441 bool allIsWell = true; 00442 bool atLeastOneUserOrGroup = false; 00443 00444 // make working copy, in case something goes wrong 00445 acl_t newACL = acl_dup( m_acl ); 00446 acl_entry_t entry; 00447 00448 //printACL( newACL, "Before cleaning: " ); 00449 // clear user entries 00450 int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry ); 00451 while ( ret == 1 ) { 00452 acl_tag_t currentTag; 00453 acl_get_tag_type( entry, ¤tTag ); 00454 if ( currentTag == type ) { 00455 acl_delete_entry( newACL, entry ); 00456 // we have to start from the beginning, the iterator is 00457 // invalidated, on deletion 00458 ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry ); 00459 } else { 00460 ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry ); 00461 } 00462 } 00463 //printACL( newACL, "After cleaning out entries: " ); 00464 00465 // now add the entries from the list 00466 QList< QPair<QString, unsigned short> >::const_iterator it = list.constBegin(); 00467 while ( it != list.constEnd() ) { 00468 acl_create_entry( &newACL, &entry ); 00469 acl_set_tag_type( entry, type ); 00470 int id = type == ACL_USER? getUidForName( (*it).first):getGidForName( (*it).first ); 00471 if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) { 00472 // user or group doesn't exist => error 00473 acl_delete_entry( newACL, entry ); 00474 allIsWell = false; 00475 break; 00476 } else { 00477 permissionsToEntry( entry, (*it).second ); 00478 atLeastOneUserOrGroup = true; 00479 } 00480 ++it; 00481 } 00482 //printACL( newACL, "After adding entries: " ); 00483 if ( allIsWell && atLeastOneUserOrGroup ) { 00484 // 23.1.1 of 1003.1e states that as soon as there is a named user or 00485 // named group entry, there needs to be a mask entry as well, so add 00486 // one, if the user hasn't explicitly set one. 00487 if ( entryForTag( newACL, ACL_MASK ) == 0 ) { 00488 acl_calc_mask( &newACL ); 00489 } 00490 } 00491 if ( allIsWell && ( acl_valid( newACL ) == 0 ) ) { 00492 acl_free( m_acl ); 00493 m_acl = newACL; 00494 } else { 00495 acl_free( newACL ); 00496 } 00497 return allIsWell; 00498 } 00499 #endif 00500 00501 bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users ) 00502 { 00503 #ifdef HAVE_POSIX_ACL 00504 return d->setAllUsersOrGroups( users, ACL_USER ); 00505 #else 00506 Q_UNUSED( users ); 00507 return true; 00508 #endif 00509 } 00510 00511 00512 /************************** 00513 * Deal with named groups * 00514 **************************/ 00515 00516 unsigned short KACL::namedGroupPermissions( const QString& name, bool *exists ) const 00517 { 00518 *exists = false; 00519 #ifdef HAVE_POSIX_ACL 00520 acl_entry_t entry; 00521 gid_t id; 00522 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry ); 00523 while ( ret == 1 ) { 00524 acl_tag_t currentTag; 00525 acl_get_tag_type( entry, ¤tTag ); 00526 if ( currentTag == ACL_GROUP ) { 00527 id = *( (gid_t*) acl_get_qualifier( entry ) ); 00528 if ( d->getGroupName( id ) == name ) { 00529 *exists = true; 00530 return entryToPermissions( entry ); 00531 } 00532 } 00533 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry ); 00534 } 00535 #else 00536 Q_UNUSED( name ); 00537 #endif 00538 return 0; 00539 } 00540 00541 bool KACL::setNamedGroupPermissions( const QString& name, unsigned short permissions ) 00542 { 00543 #ifdef HAVE_POSIX_ACL 00544 return d->setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP ); 00545 #else 00546 Q_UNUSED( name ); 00547 Q_UNUSED( permissions ); 00548 return true; 00549 #endif 00550 } 00551 00552 00553 ACLGroupPermissionsList KACL::allGroupPermissions() const 00554 { 00555 ACLGroupPermissionsList list; 00556 #ifdef HAVE_POSIX_ACL 00557 acl_entry_t entry; 00558 gid_t id; 00559 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry ); 00560 while ( ret == 1 ) { 00561 acl_tag_t currentTag; 00562 acl_get_tag_type( entry, ¤tTag ); 00563 if ( currentTag == ACL_GROUP ) { 00564 id = *( (gid_t*) acl_get_qualifier( entry ) ); 00565 QString name = d->getGroupName( id ); 00566 unsigned short permissions = entryToPermissions( entry ); 00567 ACLGroupPermissions pair = qMakePair( name, permissions ); 00568 list.append( pair ); 00569 } 00570 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry ); 00571 } 00572 #endif 00573 return list; 00574 } 00575 00576 bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups ) 00577 { 00578 #ifdef HAVE_POSIX_ACL 00579 return d->setAllUsersOrGroups( groups, ACL_GROUP ); 00580 #else 00581 Q_UNUSED( groups ); 00582 return true; 00583 #endif 00584 } 00585 00586 /************************** 00587 * from and to string * 00588 **************************/ 00589 00590 bool KACL::setACL( const QString &aclStr ) 00591 { 00592 bool ret = false; 00593 #ifdef HAVE_POSIX_ACL 00594 acl_t temp = acl_from_text( aclStr.toLatin1() ); 00595 if ( acl_valid( temp ) != 0 ) { 00596 // TODO errno is set, what to do with it here? 00597 acl_free( temp ); 00598 } else { 00599 if ( d->m_acl ) 00600 acl_free( d->m_acl ); 00601 d->m_acl = temp; 00602 ret = true; 00603 } 00604 #else 00605 Q_UNUSED( aclStr ); 00606 #endif 00607 return ret; 00608 } 00609 00610 QString KACL::asString() const 00611 { 00612 #ifdef HAVE_POSIX_ACL 00613 ssize_t size = 0; 00614 char* txt = acl_to_text(d->m_acl, &size); 00615 const QString ret = QString::fromLatin1(txt, size); 00616 acl_free(txt); 00617 return ret; 00618 #else 00619 return QString(); 00620 #endif 00621 } 00622 00623 00624 // helpers 00625 00626 #ifdef HAVE_POSIX_ACL 00627 QString KACL::KACLPrivate::getUserName( uid_t uid ) const 00628 { 00629 if ( !m_usercache.contains( uid ) ) { 00630 struct passwd *user = getpwuid( uid ); 00631 if ( user ) { 00632 m_usercache.insert( uid, QString::fromLatin1(user->pw_name) ); 00633 } 00634 else 00635 return QString::number( uid ); 00636 } 00637 return m_usercache[uid]; 00638 } 00639 00640 00641 QString KACL::KACLPrivate::getGroupName( gid_t gid ) const 00642 { 00643 if ( !m_groupcache.contains( gid ) ) { 00644 struct group *grp = getgrgid( gid ); 00645 if ( grp ) { 00646 m_groupcache.insert( gid, QString::fromLatin1(grp->gr_name) ); 00647 } 00648 else 00649 return QString::number( gid ); 00650 } 00651 return m_groupcache[gid]; 00652 } 00653 #endif 00654 00655 void KACL::virtual_hook( int, void* ) 00656 { /*BASE::virtual_hook( id, data );*/ } 00657 00658 QDataStream & operator<< ( QDataStream & s, const KACL & a ) 00659 { 00660 s << a.asString(); 00661 return s; 00662 } 00663 00664 QDataStream & operator>> ( QDataStream & s, KACL & a ) 00665 { 00666 QString str; 00667 s >> str; 00668 a.setACL( str ); 00669 return s; 00670 } 00671 00672 // vim:set ts=8 sw=4:
KDE 4.6 API Reference