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