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 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
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
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
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
00386
00387
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
00445 acl_t newACL = acl_dup( m_acl );
00446 acl_entry_t entry;
00447
00448
00449
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
00457
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
00464
00465
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
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
00483 if ( allIsWell && atLeastOneUserOrGroup ) {
00484
00485
00486
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
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
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
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
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 { }
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