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 acl_entry_t entry = entryForTag( m_acl, ACL_MASK );
00293 if ( entry == 0 ) {
00294 acl_create_entry( &m_acl, &entry );
00295 acl_set_tag_type( entry, ACL_MASK );
00296 }
00297 permissionsToEntry( entry, v );
00298 return true;
00299 }
00300 #endif
00301
00302 bool KACL::setMaskPermissions( unsigned short v )
00303 {
00304 #ifdef USE_POSIX_ACL
00305 return d->setMaskPermissions( v );
00306 #else
00307 Q_UNUSED( v );
00308 return true;
00309 #endif
00310 }
00311
00312
00313
00314
00315 unsigned short KACL::namedUserPermissions( const QString& name, bool *exists ) const
00316 {
00317 #ifdef USE_POSIX_ACL
00318 acl_entry_t entry;
00319 uid_t id;
00320 *exists = false;
00321 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00322 while ( ret == 1 ) {
00323 acl_tag_t currentTag;
00324 acl_get_tag_type( entry, ¤tTag );
00325 if ( currentTag == ACL_USER ) {
00326 id = *( (uid_t*) acl_get_qualifier( entry ) );
00327 if ( d->getUserName( id ) == name ) {
00328 *exists = true;
00329 return entryToPermissions( entry );
00330 }
00331 }
00332 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00333 }
00334 #else
00335 Q_UNUSED( name );
00336 Q_UNUSED( exists );
00337 #endif
00338 return 0;
00339 }
00340
00341 #ifdef USE_POSIX_ACL
00342 bool KACL::KACLPrivate::setNamedUserOrGroupPermissions( const QString& name, unsigned short permissions, acl_tag_t type )
00343 {
00344 bool allIsWell = true;
00345 acl_t newACL = acl_dup( m_acl );
00346 acl_entry_t entry;
00347 bool createdNewEntry = false;
00348 bool found = false;
00349 int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00350 while ( ret == 1 ) {
00351 acl_tag_t currentTag;
00352 acl_get_tag_type( entry, ¤tTag );
00353 if ( currentTag == type ) {
00354 int id = * (int*)acl_get_qualifier( entry );
00355 const QString entryName = type == ACL_USER? getUserName( id ): getGroupName( id );
00356 if ( entryName == name ) {
00357
00358 permissionsToEntry( entry, permissions );
00359 found = true;
00360 break;
00361 }
00362 }
00363 ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00364 }
00365 if ( !found ) {
00366 acl_create_entry( &newACL, &entry );
00367 acl_set_tag_type( entry, type );
00368 int id = type == ACL_USER? getUidForName( name ): getGidForName( name );
00369 if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
00370 acl_delete_entry( newACL, entry );
00371 allIsWell = false;
00372 } else {
00373 permissionsToEntry( entry, permissions );
00374 createdNewEntry = true;
00375 }
00376 }
00377 if ( allIsWell && createdNewEntry ) {
00378
00379
00380
00381 if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00382 acl_calc_mask( &newACL );
00383 }
00384 }
00385
00386 if ( !allIsWell || acl_valid( newACL ) != 0 ) {
00387 acl_free( newACL );
00388 allIsWell = false;
00389 } else {
00390 acl_free( m_acl );
00391 m_acl = newACL;
00392 }
00393 return allIsWell;
00394 }
00395 #endif
00396
00397 bool KACL::setNamedUserPermissions( const QString& name, unsigned short permissions )
00398 {
00399 #ifdef USE_POSIX_ACL
00400 return d->setNamedUserOrGroupPermissions( name, permissions, ACL_USER );
00401 #else
00402 Q_UNUSED( name );
00403 Q_UNUSED( permissions );
00404 return true;
00405 #endif
00406 }
00407
00408 ACLUserPermissionsList KACL::allUserPermissions() const
00409 {
00410 ACLUserPermissionsList list;
00411 #ifdef USE_POSIX_ACL
00412 acl_entry_t entry;
00413 uid_t id;
00414 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00415 while ( ret == 1 ) {
00416 acl_tag_t currentTag;
00417 acl_get_tag_type( entry, ¤tTag );
00418 if ( currentTag == ACL_USER ) {
00419 id = *( (uid_t*) acl_get_qualifier( entry ) );
00420 QString name = d->getUserName( id );
00421 unsigned short permissions = entryToPermissions( entry );
00422 ACLUserPermissions pair = qMakePair( name, permissions );
00423 list.append( pair );
00424 }
00425 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00426 }
00427 #endif
00428 return list;
00429 }
00430
00431 #ifdef USE_POSIX_ACL
00432 bool KACL::KACLPrivate::setAllUsersOrGroups( const QValueList< QPair<QString, unsigned short> > &list, acl_tag_t type )
00433 {
00434 bool allIsWell = true;
00435 bool atLeastOneUserOrGroup = false;
00436
00437
00438 acl_t newACL = acl_dup( m_acl );
00439 acl_entry_t entry;
00440
00441
00442
00443 int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00444 while ( ret == 1 ) {
00445 acl_tag_t currentTag;
00446 acl_get_tag_type( entry, ¤tTag );
00447 if ( currentTag == type ) {
00448 acl_delete_entry( newACL, entry );
00449
00450
00451 ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
00452 } else {
00453 ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
00454 }
00455 }
00456
00457
00458
00459 QValueList< QPair<QString, unsigned short> >::const_iterator it = list.constBegin();
00460 while ( it != list.constEnd() ) {
00461 acl_create_entry( &newACL, &entry );
00462 acl_set_tag_type( entry, type );
00463 int id = type == ACL_USER? getUidForName( (*it).first):getGidForName( (*it).first );
00464 if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
00465
00466 acl_delete_entry( newACL, entry );
00467 allIsWell = false;
00468 break;
00469 } else {
00470 permissionsToEntry( entry, (*it).second );
00471 atLeastOneUserOrGroup = true;
00472 }
00473 ++it;
00474 }
00475
00476 if ( allIsWell && atLeastOneUserOrGroup ) {
00477
00478
00479
00480 if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
00481 acl_calc_mask( &newACL );
00482 }
00483 }
00484 if ( allIsWell && ( acl_valid( newACL ) == 0 ) ) {
00485 acl_free( m_acl );
00486 m_acl = newACL;
00487 } else {
00488 acl_free( newACL );
00489 }
00490 return allIsWell;
00491 }
00492 #endif
00493
00494 bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users )
00495 {
00496 #ifdef USE_POSIX_ACL
00497 return d->setAllUsersOrGroups( users, ACL_USER );
00498 #else
00499 Q_UNUSED( users );
00500 return true;
00501 #endif
00502 }
00503
00504
00505
00506
00507
00508
00509 unsigned short KACL::namedGroupPermissions( const QString& name, bool *exists ) const
00510 {
00511 *exists = false;
00512 #ifdef USE_POSIX_ACL
00513 acl_entry_t entry;
00514 gid_t id;
00515 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00516 while ( ret == 1 ) {
00517 acl_tag_t currentTag;
00518 acl_get_tag_type( entry, ¤tTag );
00519 if ( currentTag == ACL_GROUP ) {
00520 id = *( (gid_t*) acl_get_qualifier( entry ) );
00521 if ( d->getGroupName( id ) == name ) {
00522 *exists = true;
00523 return entryToPermissions( entry );
00524 }
00525 }
00526 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00527 }
00528 #else
00529 Q_UNUSED( name );
00530 #endif
00531 return 0;
00532 }
00533
00534 bool KACL::setNamedGroupPermissions( const QString& name, unsigned short permissions )
00535 {
00536 #ifdef USE_POSIX_ACL
00537 return d->setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP );
00538 #else
00539 Q_UNUSED( name );
00540 Q_UNUSED( permissions );
00541 return true;
00542 #endif
00543 }
00544
00545
00546 ACLGroupPermissionsList KACL::allGroupPermissions() const
00547 {
00548 ACLGroupPermissionsList list;
00549 #ifdef USE_POSIX_ACL
00550 acl_entry_t entry;
00551 gid_t id;
00552 int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
00553 while ( ret == 1 ) {
00554 acl_tag_t currentTag;
00555 acl_get_tag_type( entry, ¤tTag );
00556 if ( currentTag == ACL_GROUP ) {
00557 id = *( (gid_t*) acl_get_qualifier( entry ) );
00558 QString name = d->getGroupName( id );
00559 unsigned short permissions = entryToPermissions( entry );
00560 ACLGroupPermissions pair = qMakePair( name, permissions );
00561 list.append( pair );
00562 }
00563 ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
00564 }
00565 #endif
00566 return list;
00567 }
00568
00569 bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups )
00570 {
00571 #ifdef USE_POSIX_ACL
00572 return d->setAllUsersOrGroups( groups, ACL_GROUP );
00573 #else
00574 Q_UNUSED( groups );
00575 return true;
00576 #endif
00577 }
00578
00579
00580
00581
00582
00583 bool KACL::setACL( const QString &aclStr )
00584 {
00585 bool ret = false;
00586 #ifdef USE_POSIX_ACL
00587 if ( aclStr.isEmpty() )
00588 return false;
00589
00590 acl_t temp = acl_from_text( aclStr.latin1() );
00591 if ( acl_valid( temp ) != 0 ) {
00592
00593 acl_free( temp );
00594 } else {
00595 if ( d->m_acl )
00596 acl_free( d->m_acl );
00597 d->m_acl = temp;
00598 ret = true;
00599 }
00600 #else
00601 Q_UNUSED( aclStr );
00602 #endif
00603 return ret;
00604 }
00605
00606 QString KACL::asString() const
00607 {
00608 #ifdef USE_POSIX_ACL
00609 return aclAsString( d->m_acl );
00610 #else
00611 return QString::null;
00612 #endif
00613 }
00614
00615
00616
00617
00618 #ifdef USE_POSIX_ACL
00619 QString KACL::KACLPrivate::getUserName( uid_t uid ) const
00620 {
00621 QString *temp;
00622 temp = m_usercache.find( uid );
00623 if ( !temp ) {
00624 struct passwd *user = getpwuid( uid );
00625 if ( user ) {
00626 m_usercache.insert( uid, new QString(QString::fromLatin1(user->pw_name)) );
00627 return QString::fromLatin1( user->pw_name );
00628 }
00629 else
00630 return QString::number( uid );
00631 }
00632 else
00633 return *temp;
00634 }
00635
00636
00637 QString KACL::KACLPrivate::getGroupName( gid_t gid ) const
00638 {
00639 QString *temp;
00640 temp = m_groupcache.find( gid );
00641 if ( !temp ) {
00642 struct group *grp = getgrgid( gid );
00643 if ( grp ) {
00644 m_groupcache.insert( gid, new QString(QString::fromLatin1(grp->gr_name)) );
00645 return QString::fromLatin1( grp->gr_name );
00646 }
00647 else
00648 return QString::number( gid );
00649 }
00650 else
00651 return *temp;
00652 }
00653
00654 static QString aclAsString(const acl_t acl)
00655 {
00656 char *aclString = acl_to_text( acl, 0 );
00657 QString ret = QString::fromLatin1( aclString );
00658 acl_free( (void*)aclString );
00659 return ret;
00660 }
00661
00662
00663 #endif
00664
00665 void KACL::virtual_hook( int, void* )
00666 { }
00667
00668 QDataStream & operator<< ( QDataStream & s, const KACL & a )
00669 {
00670 s << a.asString();
00671 return s;
00672 }
00673
00674 QDataStream & operator>> ( QDataStream & s, KACL & a )
00675 {
00676 QString str;
00677 s >> str;
00678 a.setACL( str );
00679 return s;
00680 }
00681
00682