From b501014935b0cdf9a9b65839d163336f0e59722f Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Mon, 20 Feb 2017 18:57:46 -0500 Subject: [PATCH] (feat) new sogo-tool manage-acl feature to get/add/remove ACLs from GCS folders --- Tools/GNUmakefile | 1 + Tools/SOGoToolManageACL.m | 283 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) create mode 100644 Tools/SOGoToolManageACL.m diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile index ad7cc9320..fa8bc5856 100644 --- a/Tools/GNUmakefile +++ b/Tools/GNUmakefile @@ -25,6 +25,7 @@ $(SOGO_TOOL)_OBJC_FILES += \ SOGoToolRestore.m \ SOGoToolCreateFolder.m \ SOGoToolUserPreferences.m \ + SOGoToolManageACL.m \ SOGoToolManageEAS.m \ SOGoToolTruncateCalendar.m TOOL_NAME += $(SOGO_TOOL) diff --git a/Tools/SOGoToolManageACL.m b/Tools/SOGoToolManageACL.m new file mode 100644 index 000000000..d08f08009 --- /dev/null +++ b/Tools/SOGoToolManageACL.m @@ -0,0 +1,283 @@ +/* SOGoToolManageACL.m - this file is part of SOGo + * + * Copyright (C) 2017 Inverse inc. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import + +#import + +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import + +#import +#import + +#import "SOGoTool.h" + +typedef enum +{ + ManageACLUnknown = -1, + ManageACLGet = 0, + ManageACLAdd = 1, + ManageACLRemove = 2, +} SOGoManageACLCommand; + +@interface SOGoToolManageACL : SOGoTool +{ + SOGoManageACLCommand command; + NSString *owner; + NSString *folder; + NSString *user; + NSArray *rights; +} + +@end + +@implementation SOGoToolManageACL + ++ (NSString *) command +{ + return @"manage-acl"; +} + ++ (NSString *) description +{ + return @"manage user's ACL"; +} + +- (id) init +{ + if ((self = [super init])) + { + command = ManageACLUnknown; + owner = nil; + folder = nil; + user = nil; + rights = nil; + } + + return self; +} + +- (void) dealloc +{ + [owner release]; + [folder release]; + [user release]; + [rights release]; + [super dealloc]; +} + +- (void) usage +{ + fprintf (stderr, "manage-acl get|add|remove owner folder user \n\n" + " get get ACL information of folder for user\n" + " add add ACL information of folder for user\n" + " remove remove all ACL information of folder for user\n" + " owner the user owning the folder\n" + " folder the folder - Calendar/ or Contacst/\n" + " user the user to get/set rights for - 'ALL', '', 'anonymous' are supported\n" + " rights rights to add\n\n" + "Example: sogo-tool get jdoe Calendar/personal\n\n" + "Note: You can add only one access right at the time. To set them all at once,\n" + " invoke 'remove' first to remove them all.\n\n"); +} + +- (BOOL) parseArguments +{ + NSString *s; + BOOL rc; + int max; + + max = [arguments count]; + if (max > 3 && max < 6) + { + s = [arguments objectAtIndex: 0]; + if ([s isEqualToString: @"get"]) + command = ManageACLGet; + else if ([s isEqualToString: @"add"]) + { + command = ManageACLAdd; + rights = RETAIN([[arguments objectAtIndex: 4] objectFromJSONString]); + } + else if ([s isEqualToString: @"remove"]) + command = ManageACLRemove; + else + { + [self usage]; + return NO; + } + + owner = RETAIN([arguments objectAtIndex: 1]); + folder = RETAIN([arguments objectAtIndex: 2]); + user = RETAIN([arguments objectAtIndex: 3]); + + rc = YES; + } + else + { + [self usage]; + rc = NO; + } + + return rc; +} + +- (void) addACLForUser: (NSString *) theUser + folder: (GCSFolder *) theFolder +{ + NSString *currentRole, *SQL, *path; + EOAdaptorChannel *channel; + int i; + + channel = [theFolder acquireAclChannel]; + path = [NSString stringWithFormat: @"%@/%@", owner, folder]; + + for (i = 0; i < [rights count]; i++) + { + currentRole = [rights objectAtIndex: i]; + if ([GCSFolderManager singleStoreMode]) + SQL = [NSString stringWithFormat: @"INSERT INTO %@" + @" (c_object, c_uid, c_role, c_folder_id)" + @" VALUES ('/%@', '%@', '%@', %@)", + [theFolder aclTableName], + path, user, currentRole, [theFolder folderId]]; + else + SQL = [NSString stringWithFormat: @"INSERT INTO %@" + @" (c_object, c_uid, c_role)" + @" VALUES ('/%@', '%@', '%@')", + [theFolder aclTableName], + path, user, currentRole]; + [channel evaluateExpressionX: SQL]; + } + +} + +- (void) getACLForUser: (NSString *) theUser + folder: (GCSFolder *) theFolder +{ + NSArray *allRights, *allKeys; + NSMutableDictionary *d; + EOQualifier *qualifier; + NSDictionary *right; + NSString *qs; + id o; + + int i; + + if ([theUser isEqualToString: @"ALL"]) + qualifier = nil; + else + { + qs = [NSString stringWithFormat: @"c_uid = '%@'", theUser]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + } + + allRights = [theFolder fetchAclMatchingQualifier: qualifier]; + d = [NSMutableDictionary dictionary]; + + for (i = 0; i < [allRights count]; i++) + { + right = [allRights objectAtIndex: i]; + if ((o = [d objectForKey: [right objectForKey: @"c_uid"]])) + [o addObject: [right objectForKey: @"c_role"]]; + else + [d setObject: [NSMutableArray arrayWithObject: [right objectForKey: @"c_role"]] + forKey: [right objectForKey: @"c_uid"]]; + } + + allKeys = [d allKeys]; + + for (i = 0; i < [allKeys count]; i++) + { + o = [allKeys objectAtIndex: i]; + NSLog(@"Rights for %@ %@", o, [[d objectForKey: o] jsonRepresentation]); + } +} + +- (void) removeACLForUser: (NSString *) theUser + folder: (GCSFolder *) theFolder +{ + EOQualifier *qualifier; + NSString *qs, *path; + + if ([theUser isEqualToString: @"ALL"]) + qualifier = nil; + else + { + qs = [NSString stringWithFormat: @"c_uid = '%@'", theUser]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + } + + [theFolder deleteAclMatchingQualifier: qualifier]; + + // We clear the cache. We first strip /Users/ from our path + path = [[[[theFolder path] pathComponents] subarrayWithRange: NSMakeRange(2,3)] componentsJoinedByString: @"/"]; + [[SOGoCache sharedCache] setACLs: nil + forPath: path]; +} + +- (BOOL) proceed +{ + NSAutoreleasePool *pool; + GCSFolderManager *fm; + GCSFolder *f; + + BOOL rc; + + rc = YES; + + pool = [NSAutoreleasePool new]; + + fm = [GCSFolderManager defaultFolderManager]; + f = [fm folderAtPath: [NSString stringWithFormat: @"/Users/%@/%@", owner, folder]]; + + if (command == ManageACLGet) + [self getACLForUser: user folder: f]; + else if (command == ManageACLRemove) + [self removeACLForUser: user folder: f]; + else if (command == ManageACLAdd) + [self addACLForUser: user folder: f]; + else + [self usage]; + + [pool release]; + + return rc; +} + +- (BOOL) run +{ + return ([self parseArguments] && [self proceed]); +} + +@end