00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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 ssize_t size = acl_size( acl );
00181 kDebug() << comment << acl_to_text( acl, &size );
00182 }
00183 #endif
00184 #endif
00185
00186 static int getUidForName( const QString& name )
00187 {
00188 struct passwd *user = getpwnam( name.toLocal8Bit() );
00189 if ( user )
00190 return user->pw_uid;
00191 else
00192 return -1;
00193 }
00194
00195 static int getGidForName( const QString& name )
00196 {
00197 struct group *group = getgrnam( name.toLocal8Bit() );
00198 if ( group )
00199 return group->gr_gid;
00200 else
00201 return -1;
00202 }
00203 #endif
00204
00205
00206 unsigned short KACL::ownerPermissions() const
00207 {
00208 #ifdef HAVE_POSIX_ACL
00209 return entryToPermissions( entryForTag( d->m_acl, ACL_USER_OBJ ) );
00210 #else
00211 return 0;
00212 #endif
00213 }
00214
00215 bool KACL::setOwnerPermissions( unsigned short v )
00216 {
00217 #ifdef HAVE_POSIX_ACL
00218 permissionsToEntry( entryForTag( d->m_acl, ACL_USER_OBJ ), v );
00219 #else
00220 Q_UNUSED( v );
00221 #endif
00222 return true;
00223 }
00224
00225 unsigned short KACL::owningGroupPermissions() const
00226 {
00227 #ifdef HAVE_POSIX_ACL
00228 return entryToPermissions( entryForTag( d->m_acl, ACL_GROUP_OBJ ) );
00229 #else
00230 return 0;
00231 #endif
00232 }
00233
00234 bool KACL::setOwningGroupPermissions( unsigned short v )
00235 {
00236 #ifdef HAVE_POSIX_ACL
00237 permissionsToEntry( entryForTag( d->m_acl, ACL_GROUP_OBJ ), v );
00238 #else
00239 Q_UNUSED( v );
00240 #endif
00241 return true;
00242 }
00243
00244 unsigned short KACL::othersPermissions() const
00245 {
00246 #ifdef HAVE_POSIX_ACL
00247 return entryToPermissions( entryForTag( d->m_acl, ACL_OTHER ) );
00248 #else
00249 return 0;
00250 #endif
00251 }
00252
00253 bool KACL::setOthersPermissions( unsigned short v )
00254 {
00255 #ifdef HAVE_POSIX_ACL
00256 permissionsToEntry( entryForTag( d->m_acl, ACL_OTHER ), v );
00257 #else
00258 Q_UNUSED( v );
00259 #endif
00260 return true;
00261 }
00262
00263 mode_t KACL::basePermissions() const
00264 {
00265 mode_t perms( 0 );
00266 #ifdef HAVE_POSIX_ACL
00267 if ( ownerPermissions() & ACL_READ ) perms |= S_IRUSR;
00268 if ( ownerPermissions() & ACL_WRITE ) perms |= S_IWUSR;
00269 if ( ownerPermissions() & ACL_EXECUTE ) perms |= S_IXUSR;
00270 if ( owningGroupPermissions() & ACL_READ ) perms |= S_IRGRP;
00271 if ( owningGroupPermissions() & ACL_WRITE ) perms |= S_IWGRP;
00272 if ( owningGroupPermissions() & ACL_EXECUTE ) perms |= S_IXGRP;
00273 if ( othersPermissions() & ACL_READ ) perms |= S_IROTH;
00274 if ( othersPermissions() & ACL_WRITE ) perms |= S_IWOTH;
00275 if ( othersPermissions() & ACL_EXECUTE ) perms |= S_IXOTH;
00276 #endif
00277 return perms;
00278 }
00279
00280 unsigned short KACL::maskPermissions( bool &exists ) const
00281 {
00282 exists = true;
00283 #ifdef HAVE_POSIX_ACL
00284 acl_entry_t entry = entryForTag( d->m_acl, ACL_MASK );
00285 if ( entry == 0 ) {
00286 exists = false;
00287 return 0;
00288 }
00289 return entryToPermissions( entry );
00290 #else
00291 return 0;
00292 #endif
00293 }
00294
00295 #ifdef HAVE_POSIX_ACL
00296 bool KACL::KACLPrivate::setMaskPermissions( unsigned short v )
00297 {
00298 acl_entry_t entry = entryForTag( m_acl, ACL_MASK );
00299 if ( entry == 0 ) {
00300 acl_create_entry( &m_acl, &entry );
00301 acl_set_tag_type( entry, ACL_MASK );
00302 }
00303 permissionsToEntry( entry, v );
00304 return true;
00305 }
00306 #endif
00307
00308 bool KACL::setMaskPermissions( unsigned short v )
00309 {
00310 #ifdef HAVE_POSIX_ACL
00311 return d->setMaskPermissions( v );
00312 #else
00313 Q_UNUSED( v );
00314 return true;
00315 #endif
00316 }
00317
00318
00319
00320
00321 unsigned short KACL::namedUserPermissions( const QString& name, bool *exists ) const
00322 {
00323 #ifdef HAVE_POSIX_ACL
00324 acl_entry_t entry;
00325 uid_t id;
00326 *exists = false;
00327 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00328 while ( ret == 1 ) {
00329 acl_tag_t currentTag;
00330 acl_get_tag_type( entry, ¤tTag );
00331 if ( currentTag == ACL_USER ) {
00332 id = *( (uid_t*) acl_get_qualifier( entry ) );
00333 if ( d->getUserName( id ) == name ) {
00334 *exists = true;
00335 return entryToPermissions( entry );
00336 }
00337 }
00338 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00339 }
00340 #else
00341 Q_UNUSED( name );
00342 Q_UNUSED( exists );
00343 #endif
00344 return 0;
00345 }
00346
00347 #ifdef HAVE_POSIX_ACL
00348 bool KACL::KACLPrivate::setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type )
00349 {
00350 bool allIsWell = true;
00351 acl_t newACL = acl_dup( m_acl );
00352 acl_entry_t entry;
00353 bool createdNewEntry = false;
00354 bool found = false;
00355 int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00356 while ( ret == 1 ) {
00357 acl_tag_t currentTag;
00358 acl_get_tag_type( entry, ¤tTag );
00359 if ( currentTag == type ) {
00360 int id = * (int*)acl_get_qualifier( entry );
00361 const QString entryName = type == ACL_USER? getUserName( id ): getGroupName( id );
00362 if ( entryName == name ) {
00363
00364 permissionsToEntry( entry, permissions );
00365 found = true;
00366 break;
00367 }
00368 }
00369 ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00370 }
00371 if ( !found ) {
00372 acl_create_entry( &newACL, &entry );
00373 acl_set_tag_type( entry, type );
00374 int id = type == ACL_USER? getUidForName( name ): getGidForName( name );
00375 if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
00376 acl_delete_entry( newACL, entry );
00377 allIsWell = false;
00378 } else {
00379 permissionsToEntry( entry, permissions );
00380 createdNewEntry = true;
00381 }
00382 }
00383 if ( allIsWell && createdNewEntry ) {
00384
00385
00386
00387 if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00388 acl_calc_mask( &newACL );
00389 }
00390 }
00391
00392 if ( !allIsWell || acl_valid( newACL ) != 0 ) {
00393 acl_free( newACL );
00394 allIsWell = false;
00395 } else {
00396 acl_free( m_acl );
00397 m_acl = newACL;
00398 }
00399 return allIsWell;
00400 }
00401 #endif
00402
00403 bool KACL::setNamedUserPermissions( const QString& name, unsigned short permissions )
00404 {
00405 #ifdef HAVE_POSIX_ACL
00406 return d->setNamedUserOrGroupPermissions( name, permissions, ACL_USER );
00407 #else
00408 Q_UNUSED( name );
00409 Q_UNUSED( permissions );
00410 return true;
00411 #endif
00412 }
00413
00414 ACLUserPermissionsList KACL::allUserPermissions() const
00415 {
00416 ACLUserPermissionsList list;
00417 #ifdef HAVE_POSIX_ACL
00418 acl_entry_t entry;
00419 uid_t id;
00420 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00421 while ( ret == 1 ) {
00422 acl_tag_t currentTag;
00423 acl_get_tag_type( entry, ¤tTag );
00424 if ( currentTag == ACL_USER ) {
00425 id = *( (uid_t*) acl_get_qualifier( entry ) );
00426 QString name = d->getUserName( id );
00427 unsigned short permissions = entryToPermissions( entry );
00428 ACLUserPermissions pair = qMakePair( name, permissions );
00429 list.append( pair );
00430 }
00431 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00432 }
00433 #endif
00434 return list;
00435 }
00436
00437 #ifdef HAVE_POSIX_ACL
00438 bool KACL::KACLPrivate::setAllUsersOrGroups( const QList< QPair<QString, unsigned short> > &list, acl_tag_t type )
00439 {
00440 bool allIsWell = true;
00441 bool atLeastOneUserOrGroup = false;
00442
00443
00444 acl_t newACL = acl_dup( m_acl );
00445 acl_entry_t entry;
00446
00447
00448
00449 int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00450 while ( ret == 1 ) {
00451 acl_tag_t currentTag;
00452 acl_get_tag_type( entry, ¤tTag );
00453 if ( currentTag == type ) {
00454 acl_delete_entry( newACL, entry );
00455
00456
00457 ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00458 } else {
00459 ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00460 }
00461 }
00462
00463
00464
00465 QList< QPair<QString, unsigned short> >::const_iterator it = list.constBegin();
00466 while ( it != list.constEnd() ) {
00467 acl_create_entry( &newACL, &entry );
00468 acl_set_tag_type( entry, type );
00469 int id = type == ACL_USER? getUidForName( (*it).first):getGidForName( (*it).first );
00470 if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
00471
00472 acl_delete_entry( newACL, entry );
00473 allIsWell = false;
00474 break;
00475 } else {
00476 permissionsToEntry( entry, (*it).second );
00477 atLeastOneUserOrGroup = true;
00478 }
00479 ++it;
00480 }
00481
00482 if ( allIsWell && atLeastOneUserOrGroup ) {
00483
00484
00485
00486 if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00487 acl_calc_mask( &newACL );
00488 }
00489 }
00490 if ( allIsWell && ( acl_valid( newACL ) == 0 ) ) {
00491 acl_free( m_acl );
00492 m_acl = newACL;
00493 } else {
00494 acl_free( newACL );
00495 }
00496 return allIsWell;
00497 }
00498 #endif
00499
00500 bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users )
00501 {
00502 #ifdef HAVE_POSIX_ACL
00503 return d->setAllUsersOrGroups( users, ACL_USER );
00504 #else
00505 Q_UNUSED( users );
00506 return true;
00507 #endif
00508 }
00509
00510
00511
00512
00513
00514
00515 unsigned short KACL::namedGroupPermissions( const QString& name, bool *exists ) const
00516 {
00517 *exists = false;
00518 #ifdef HAVE_POSIX_ACL
00519 acl_entry_t entry;
00520 gid_t id;
00521 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00522 while ( ret == 1 ) {
00523 acl_tag_t currentTag;
00524 acl_get_tag_type( entry, ¤tTag );
00525 if ( currentTag == ACL_GROUP ) {
00526 id = *( (gid_t*) acl_get_qualifier( entry ) );
00527 if ( d->getGroupName( id ) == name ) {
00528 *exists = true;
00529 return entryToPermissions( entry );
00530 }
00531 }
00532 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00533 }
00534 #else
00535 Q_UNUSED( name );
00536 #endif
00537 return 0;
00538 }
00539
00540 bool KACL::setNamedGroupPermissions( const QString& name, unsigned short permissions )
00541 {
00542 #ifdef HAVE_POSIX_ACL
00543 return d->setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP );
00544 #else
00545 Q_UNUSED( name );
00546 Q_UNUSED( permissions );
00547 return true;
00548 #endif
00549 }
00550
00551
00552 ACLGroupPermissionsList KACL::allGroupPermissions() const
00553 {
00554 ACLGroupPermissionsList list;
00555 #ifdef HAVE_POSIX_ACL
00556 acl_entry_t entry;
00557 gid_t id;
00558 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00559 while ( ret == 1 ) {
00560 acl_tag_t currentTag;
00561 acl_get_tag_type( entry, ¤tTag );
00562 if ( currentTag == ACL_GROUP ) {
00563 id = *( (gid_t*) acl_get_qualifier( entry ) );
00564 QString name = d->getGroupName( id );
00565 unsigned short permissions = entryToPermissions( entry );
00566 ACLGroupPermissions pair = qMakePair( name, permissions );
00567 list.append( pair );
00568 }
00569 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00570 }
00571 #endif
00572 return list;
00573 }
00574
00575 bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups )
00576 {
00577 #ifdef HAVE_POSIX_ACL
00578 return d->setAllUsersOrGroups( groups, ACL_GROUP );
00579 #else
00580 Q_UNUSED( groups );
00581 return true;
00582 #endif
00583 }
00584
00585
00586
00587
00588
00589 bool KACL::setACL( const QString &aclStr )
00590 {
00591 bool ret = false;
00592 #ifdef HAVE_POSIX_ACL
00593 acl_t temp = acl_from_text( aclStr.toLatin1() );
00594 if ( acl_valid( temp ) != 0 ) {
00595
00596 acl_free( temp );
00597 } else {
00598 if ( d->m_acl )
00599 acl_free( d->m_acl );
00600 d->m_acl = temp;
00601 ret = true;
00602 }
00603 #else
00604 Q_UNUSED( aclStr );
00605 #endif
00606 return ret;
00607 }
00608
00609 QString KACL::asString() const
00610 {
00611 #ifdef HAVE_POSIX_ACL
00612 ssize_t size = acl_size( d->m_acl );
00613 return QString::fromLatin1( acl_to_text( d->m_acl, &size ) );
00614 #else
00615 return QString();
00616 #endif
00617 }
00618
00619
00620
00621
00622 #ifdef HAVE_POSIX_ACL
00623 QString KACL::KACLPrivate::getUserName( uid_t uid ) const
00624 {
00625 if ( !m_usercache.contains( uid ) ) {
00626 struct passwd *user = getpwuid( uid );
00627 if ( user ) {
00628 m_usercache.insert( uid, QString::fromLatin1(user->pw_name) );
00629 }
00630 else
00631 return QString::number( uid );
00632 }
00633 return m_usercache[uid];
00634 }
00635
00636
00637 QString KACL::KACLPrivate::getGroupName( gid_t gid ) const
00638 {
00639 if ( !m_groupcache.contains( gid ) ) {
00640 struct group *grp = getgrgid( gid );
00641 if ( grp ) {
00642 m_groupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
00643 }
00644 else
00645 return QString::number( gid );
00646 }
00647 return m_groupcache[gid];
00648 }
00649 #endif
00650
00651 void KACL::virtual_hook( int, void* )
00652 { }
00653
00654 QDataStream & operator<< ( QDataStream & s, const KACL & a )
00655 {
00656 s << a.asString();
00657 return s;
00658 }
00659
00660 QDataStream & operator>> ( QDataStream & s, KACL & a )
00661 {
00662 QString str;
00663 s >> str;
00664 a.setACL( str );
00665 return s;
00666 }
00667
00668