Merge pull request #7 from inverse-inc/fix/1955_sogo-tool-passwd-handling

Fix/1955 sogo tool passwd handling
pull/8/head
extrafu 2013-01-15 10:37:14 -08:00
commit 8ce4b89656
4 changed files with 278 additions and 157 deletions

View File

@ -31,6 +31,7 @@
{ {
BOOL verbose; BOOL verbose;
NSArray *arguments; NSArray *arguments;
NSArray *sanitizedArguments; /* arguments w/o args from NSArgumentDomain */
} }
+ (NSString *) command; + (NSString *) command;
@ -40,6 +41,7 @@
verbose: (BOOL) isVerbose; verbose: (BOOL) isVerbose;
- (void) setArguments: (NSArray *) newArguments; - (void) setArguments: (NSArray *) newArguments;
- (void) setSanitizedArguments: (NSArray *) newArguments;
- (void) setVerbose: (BOOL) newVerbose; - (void) setVerbose: (BOOL) newVerbose;
- (BOOL) run; - (BOOL) run;

View File

@ -21,7 +21,10 @@
*/ */
#import <Foundation/NSArray.h> #import <Foundation/NSArray.h>
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import "SOGoTool.h" #import "SOGoTool.h"
@ -49,6 +52,7 @@
[instance autorelease]; [instance autorelease];
[instance setArguments: toolArguments]; [instance setArguments: toolArguments];
[instance setSanitizedArguments: toolArguments];
[instance setVerbose: isVerbose]; [instance setVerbose: isVerbose];
return [instance run]; return [instance run];
@ -59,6 +63,7 @@
if ((self = [super init])) if ((self = [super init]))
{ {
arguments = nil; arguments = nil;
sanitizedArguments = nil;
verbose = NO; verbose = NO;
} }
@ -70,6 +75,51 @@
ASSIGN (arguments, newArguments); ASSIGN (arguments, newArguments);
} }
- (void) setSanitizedArguments: (NSArray *) newArguments
{
NSString *argsString = [newArguments componentsJoinedByString:@" "];
NSDictionary *cliArguments;
NSArray *keys;
int i;
argsString = [newArguments componentsJoinedByString:@" "];
/* Remove NSArgumentDomain -key value from the arguments */
cliArguments = [[NSUserDefaults standardUserDefaults]
volatileDomainForName:NSArgumentDomain];
keys = [cliArguments allKeys];
for (i=0; i < [keys count]; i++)
{
NSString *k = [keys objectAtIndex: i];
NSString *v = [cliArguments objectForKey:k];
NSString *argPair = [NSString stringWithFormat:@"-%@ %@", k, v];
argsString = [argsString stringByReplacingOccurrencesOfString: argPair
withString: @""];
}
if ([argsString length])
{
/* dance to compact whitespace */
NSArray *wordsWP = [argsString componentsSeparatedByCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]];
NSMutableArray *words = [NSMutableArray array];
for (NSString *word in wordsWP)
{
if([word length] > 1)
{
[words addObject:word];
}
}
argsString = [words componentsJoinedByString:@" "];
ASSIGN (sanitizedArguments, [argsString componentsSeparatedByString:@" "]);
}
else
{
DESTROY(sanitizedArguments);
}
}
- (void) setVerbose: (BOOL) newVerbose - (void) setVerbose: (BOOL) newVerbose
{ {
verbose = newVerbose; verbose = newVerbose;
@ -78,6 +128,7 @@
- (void) dealloc - (void) dealloc
{ {
[arguments release]; [arguments release];
[sanitizedArguments release];
[super dealloc]; [super dealloc];
} }

View File

@ -22,9 +22,11 @@
#import <Foundation/NSArray.h> #import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h> #import <Foundation/NSCalendarDate.h>
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSData.h> #import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h> #import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSValue.h> #import <Foundation/NSValue.h>
#import <GDLAccess/EOAdaptorChannel.h> #import <GDLAccess/EOAdaptorChannel.h>
@ -63,10 +65,12 @@
- (void) usage - (void) usage
{ {
fprintf (stderr, "expire-autoreply authname:authpassword\n\n" fprintf (stderr, "expire-autoreply -p credentialFile\n\n"
" authname administrator username of the Sieve server\n" " -p credentialFile Specify the file containing the sieve admin credentials\n"
" authpassword administrator password of the Sieve server\n\n" " The file should contain a single line:\n"
"The expire-autoreply action should be configured as a daily cronjob.\n"); " username:password\n"
"\n"
"The expire-autoreply action should be configured as a daily cronjob.\n");
} }
- (BOOL) removeAutoReplyForLogin: (NSString *) theLogin - (BOOL) removeAutoReplyForLogin: (NSString *) theLogin
@ -123,12 +127,20 @@
now = [[NSCalendarDate calendarDate] timeIntervalSince1970]; now = [[NSCalendarDate calendarDate] timeIntervalSince1970];
sd = [SOGoSystemDefaults sharedSystemDefaults]; sd = [SOGoSystemDefaults sharedSystemDefaults];
profileURL = [sd profileURL]; profileURL = [sd profileURL];
if (profileURL) if (!profileURL)
{
NSLog(@"Couldn't obtain the profileURL. (Hint: SOGoProfileURL)");
}
else
{ {
tableURL = [[NSURL alloc] initWithString: profileURL]; tableURL = [[NSURL alloc] initWithString: profileURL];
cm = [GCSChannelManager defaultChannelManager]; cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: tableURL]; channel = [cm acquireOpenChannelForURL: tableURL];
if (channel) if (!channel)
{
NSLog(@"Couldn't acquire channel for profileURL");
}
else
{ {
sql = [NSString stringWithFormat: @"SELECT c_uid, c_defaults FROM %@", sql = [NSString stringWithFormat: @"SELECT c_uid, c_defaults FROM %@",
[tableURL gcsTableName]]; [tableURL gcsTableName]];
@ -166,30 +178,60 @@
} }
} }
- (BOOL) run - (BOOL) run
{ {
NSError *err;
NSRange r; NSRange r;
NSString *creds, *authname, *authpwd; NSString *creds, *credsFile, *authname, *authpwd;
BOOL rc; BOOL rc;
int max; int max;
max = [arguments count]; max = [sanitizedArguments count];
creds = nil;
authname = nil;
authpwd = nil;
rc = NO; rc = NO;
credsFile = [[NSUserDefaults standardUserDefaults] stringForKey: @"p"];
if (credsFile)
{
creds = [NSString stringWithContentsOfFile: credsFile
encoding: NSUTF8StringEncoding
error: &err];
if (!creds)
{
NSLog(@"Error reading credential file '%@': %@", credsFile, err);
}
creds = [creds stringByTrimmingCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
}
if (max > 0) if (max > 0)
{ {
creds = [arguments objectAtIndex: 0]; /* assume we got the creds directly on the cli */
r = [creds rangeOfString: @":"]; creds = [sanitizedArguments objectAtIndex: 0];
if (r.location != NSNotFound)
{
authname = [creds substringToIndex: r.location];
authpwd = [creds substringFromIndex: r.location+1];
[self expireAutoReplyWithUsername: authname andPassword: authpwd];
rc = YES;
}
} }
if (creds)
{
r = [creds rangeOfString: @":"];
if (r.location == NSNotFound)
{
NSLog(@"Invalid credential string format (user:pass)");
}
else
{
authname = [creds substringToIndex: r.location];
authpwd = [creds substringFromIndex: r.location+1];
}
}
if (authname && authpwd)
{
[self expireAutoReplyWithUsername: authname andPassword: authpwd];
rc = YES;
}
if (!rc) if (!rc)
[self usage]; [self usage];

View File

@ -21,9 +21,11 @@
*/ */
#import <Foundation/NSArray.h> #import <Foundation/NSArray.h>
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSData.h> #import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h> #import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import <SOGo/NSString+Utilities.h> #import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h> #import <SOGo/SOGoUser.h>
@ -62,13 +64,16 @@ typedef enum
- (void) usage - (void) usage
{ {
fprintf (stderr, "user-preferences get|set|unset defaults|settings user [authname:authpassword] key [value|-f filename]\n\n" fprintf (stderr, "user-preferences get|set|unset defaults|settings user [-p credentialFile] key [value|-f filename]\n\n"
" user the user of whom to set the defaults/settings key/value\n" " user the user of whom to set the defaults/settings key/value\n"
" value the JSON-formatted value of the key\n\n" " value the JSON-formatted value of the key\n\n"
" Examples:\n" " -p credentialFile Specify the file containing the sieve admin credentials\n"
" sogo-tool user-preferences get defaults janedoe SOGoLanguage\n" " The file should contain a single line:\n"
" sogo-tool user-preferences unset settings janedoe Mail\n" " username:password\n"
" sogo-tool user-preferences set defaults janedoe SOGoTimeFormat '{\"SOGoTimeFormat\":\"%%I:%%M %%p\"}'\n"); " Examples:\n"
" sogo-tool user-preferences get defaults janedoe SOGoLanguage\n"
" sogo-tool user-preferences unset settings janedoe Mail\n"
" sogo-tool user-preferences set defaults janedoe SOGoTimeFormat '{\"SOGoTimeFormat\":\"%%I:%%M %%p\"}'\n");
} }
// //
@ -79,11 +84,12 @@ typedef enum
if ([theString length] > 2) if ([theString length] > 2)
{ {
if ([theString caseInsensitiveCompare: @"get"] == NSOrderedSame) if ([theString caseInsensitiveCompare: @"get"] == NSOrderedSame)
return UserPreferencesGet; return UserPreferencesGet;
else if ([theString caseInsensitiveCompare: @"set"] == NSOrderedSame) else if ([theString caseInsensitiveCompare: @"set"] == NSOrderedSame)
return UserPreferencesSet; return UserPreferencesSet;
else if ([theString caseInsensitiveCompare: @"unset"] == NSOrderedSame) else if ([theString caseInsensitiveCompare: @"unset"] == NSOrderedSame)
return UserPreferencesUnset; } return UserPreferencesUnset;
}
return UserPreferencesUnknown; return UserPreferencesUnknown;
} }
@ -96,42 +102,64 @@ typedef enum
// //
- (BOOL) _updateSieveScripsForkey: (NSString *) theKey - (BOOL) _updateSieveScripsForkey: (NSString *) theKey
manager: (SOGoSieveManager *) theManager manager: (SOGoSieveManager *) theManager
login: (NSString *) theLogin login: (NSString *) theLogin
authname: (NSString *) theAuthName
password: (NSString *) thePassword
{ {
if ([theKey caseInsensitiveCompare: @"Forward"] == NSOrderedSame || if ([theKey caseInsensitiveCompare: @"Forward"] == NSOrderedSame ||
[theKey caseInsensitiveCompare: @"SOGoSieveFilters"] == NSOrderedSame || [theKey caseInsensitiveCompare: @"SOGoSieveFilters"] == NSOrderedSame ||
[theKey caseInsensitiveCompare: @"Vacation"] == NSOrderedSame) [theKey caseInsensitiveCompare: @"Vacation"] == NSOrderedSame)
{ {
if ([theAuthName length] == 0 || [thePassword length] == 0) /* credentials file handling */
{ NSRange r;
NSLog(@"To update Sieve scripts, you must provide the \"authname:password\" parameter"); NSString *credsFile, *creds, *authname, *authpwd;
return NO; authname = nil;
} authpwd = nil;
credsFile = [[NSUserDefaults standardUserDefaults] stringForKey: @"p"];
if (credsFile)
{
/* TODO: add back support for user:pwd here? */
creds = [NSString stringWithContentsOfFile: credsFile
encoding: NSUTF8StringEncoding
error: NULL];
if (creds == nil)
{
NSLog(@"Error reading credential file '%@'", credsFile);
return NO;
}
creds = [creds stringByTrimmingCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
r = [creds rangeOfString: @":"];
authname = [creds substringToIndex: r.location];
authpwd = [creds substringFromIndex: r.location+1];
}
if (authname == nil || authpwd == nil)
{
NSLog(@"To update Sieve scripts, you must provide the \"-p credentialFile\" parameter");
return NO;
}
return [theManager updateFiltersForLogin: theLogin return [theManager updateFiltersForLogin: theLogin
authname: theAuthName authname: authname
password: thePassword password: authpwd
account: nil]; account: nil];
} }
return YES; return YES;
} }
- (BOOL) run - (BOOL) run
{ {
NSString *userId, *type, *key; NSString *userId, *type, *key, *value;
NSString *jsonValueFile;
SOGoUserPreferencesCommand cmd; SOGoUserPreferencesCommand cmd;
id o; id o;
NSRange r;
BOOL rc; BOOL rc;
int max; int max;
max = [arguments count]; max = [sanitizedArguments count];
rc = NO; rc = NO;
if (max > 3) if (max > 3)
@ -140,128 +168,126 @@ typedef enum
SOGoSieveManager *manager; SOGoSieveManager *manager;
SOGoUser *user; SOGoUser *user;
cmd = [self _cmdFromString: [arguments objectAtIndex: 0]]; cmd = [self _cmdFromString: [sanitizedArguments objectAtIndex: 0]];
if (cmd != UserPreferencesUnknown) type = [sanitizedArguments objectAtIndex: 1];
{ userId = [sanitizedArguments objectAtIndex: 2];
type = [arguments objectAtIndex: 1]; key = [sanitizedArguments objectAtIndex: 3];
userId = [arguments objectAtIndex: 2];
key = [arguments objectAtIndex: 3];
user = [SOGoUser userWithLogin: userId]; user = [SOGoUser userWithLogin: userId];
manager = [SOGoSieveManager sieveManagerForUser: user]; manager = [SOGoSieveManager sieveManagerForUser: user];
if ([type caseInsensitiveCompare: @"defaults"] == NSOrderedSame) if ([type caseInsensitiveCompare: @"defaults"] == NSOrderedSame)
source = [user userDefaults]; source = [user userDefaults];
else else
source = [user userSettings]; source = [user userSettings];
if (cmd == UserPreferencesGet) switch (cmd)
{ {
o = [source objectForKey: key]; case UserPreferencesGet:
o = [source objectForKey: key];
if (o) if (o)
printf("%s: %s\n", [key UTF8String], [[o jsonRepresentation] UTF8String]); {
else printf("%s: %s\n", [key UTF8String], [[o jsonRepresentation] UTF8String]);
NSLog(@"Value for key \"%@\" not found in %@", key, type); rc = YES;
}
else
{
NSLog(@"Value for key \"%@\" not found in %@", key, type);
return rc;
}
break;
rc = YES; case UserPreferencesSet:
} if (max > 4)
else {
{ /* value specified on command line */
NSString *authname, *authpwd, *value; value = [sanitizedArguments objectAtIndex: 4];
NSData *data; }
int i; else
{
authname = @""; /* value is to be found in file specified with -f filename */
authpwd = @""; jsonValueFile = [[NSUserDefaults standardUserDefaults]
value = @""; stringForKey: @"f"];
if (max > 4)
{
r = [[arguments objectAtIndex: 3] rangeOfString: @":"];
if (r.location == NSNotFound)
{
i = 3;
}
else
{
authname = [[arguments objectAtIndex: 3] substringToIndex: r.location];
authpwd = [[arguments objectAtIndex: 3] substringFromIndex: r.location+1];
i = 4;
}
key = [arguments objectAtIndex: i++]; if (jsonValueFile == nil)
{
NSLog(@"No value specified, aborting");
[self usage];
return rc;
}
else
{
if (max > i) NSData *data = [NSData dataWithContentsOfFile: jsonValueFile];
{ if (data == nil)
value = [arguments objectAtIndex: i++]; {
if ([value caseInsensitiveCompare: @"-f"] == NSOrderedSame) NSLog(@"Error reading file '%@'", jsonValueFile);
{ [self usage];
if (max > i) return rc;
{ }
data = [NSData dataWithContentsOfFile: [arguments objectAtIndex: i]]; value = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
value = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; [value autorelease];
[value autorelease]; }
} }
} o = [value objectFromJSONString];
}
} //
else // We support setting only "values" - for example, setting :
{ //
if (cmd == UserPreferencesUnset) // SOGoDayStartTime to 9:00
{ //
key = [arguments objectAtIndex: 3]; // Values in JSON must be a dictionary so we must support passing:
} //
else // key == SOGoDayStartTime
{ // value == '{"SOGoDayStartTime": "09:00"}'
key = [arguments objectAtIndex: 3]; //
value = [arguments objectAtIndex: 4]; // to achieve what we want.
} //
} if (o && [o count] == 1)
{
if (cmd == UserPreferencesUnset) [source setObject: [[o allValues] lastObject] forKey: key];
[source removeObjectForKey: key]; }
else //
{ // We also support passing values that are already dictionaries so in this
o = [value objectFromJSONString]; // case, we simply set it to the passed key.
//
// else if (o)
// We support setting only "values" - for example, setting : {
// [source setObject: o forKey: key];
// SOGoDayStartTime to 9:00 }
// else
// Values in JSON must be a dictionary so we must support passing: {
// NSLog(@"Invalid JSON input - no changes performed in the database. The supplied value was: %@", value);
// key == SOGoDayStartTime [self usage];
// value == '{"SOGoDayStartTime": "09:00"}' return rc;
// }
// to achieve what we want.
// rc = [self _updateSieveScripsForkey: key
if (o && [o count] == 1) manager: manager
{ login: userId];
[source setObject: [[o allValues] lastObject] forKey: key]; if (rc)
} [source synchronize];
// else
// We also support passing values that are already dictionaries so in this NSLog(@"Error updating sieve script, not updating database");
// case, we simply set it to the passed key.
// break;
else if (o)
{ case UserPreferencesUnset:
[source setObject: o forKey: key]; [source removeObjectForKey: key];
} rc = [self _updateSieveScripsForkey: key
else manager: manager
NSLog(@"Invalid JSON input - no changes performed in the database. The supplied value was: %@", value); login: userId];
} if (rc)
[source synchronize];
[source synchronize]; else
rc = [self _updateSieveScripsForkey: key NSLog(@"Error updating sieve script, not updating database");
manager: manager
login: userId break;
authname: authname case UserPreferencesUnknown:
password: authpwd]; break;
} }
}
} }
if (!rc) if (!rc)