mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-11-10 19:21:01 +00:00
#3122: fix sieve injection
This commit is contained in:
1 parent
49049f6d42
commit
76d75de17b
2 files changed
+109
-10
No files matched your search
@@ -1094,8 +1094,8 @@ static NSString *sieveScriptName = @"sogo";
|
||||
if ([[values objectForKey: @"startTimeEnabled"] boolValue])
|
||||
{
|
||||
startTime = [values objectForKey: @"startTime"];
|
||||
timeCondition = [NSString stringWithFormat: @"date :value \"ge\" :zone \"%@\" \"date\" \"time\" \"%@:00\"",
|
||||
timeZone, startTime];
|
||||
timeCondition = [NSString stringWithFormat: @"date :value \"ge\" :zone \"%@\" \"date\" \"time\" %@",
|
||||
timeZone, [[NSString stringWithFormat: @"%@:00", startTime] asSieveQuotedString]];
|
||||
[timeConditions addObject: timeCondition];
|
||||
}
|
||||
|
||||
@@ -1103,8 +1103,8 @@ static NSString *sieveScriptName = @"sogo";
|
||||
if ([[values objectForKey: @"endTimeEnabled"] boolValue])
|
||||
{
|
||||
endTime = [values objectForKey: @"endTime"];
|
||||
timeCondition = [NSString stringWithFormat: @"date :value \"lt\" :zone \"%@\" \"date\" \"time\" \"%@:00\"",
|
||||
timeZone, endTime];
|
||||
timeCondition = [NSString stringWithFormat: @"date :value \"lt\" :zone \"%@\" \"date\" \"time\" %@",
|
||||
timeZone, [[NSString stringWithFormat: @"%@:00", endTime] asSieveQuotedString]];
|
||||
[timeConditions addObject: timeCondition];
|
||||
}
|
||||
|
||||
@@ -1176,7 +1176,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
[vacation_script appendString: @" :addresses ["];
|
||||
for (i = 0; i < [addresses count]; i++)
|
||||
{
|
||||
[vacation_script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
|
||||
[vacation_script appendString: [[NSString stringWithFormat: @"%@", [addresses objectAtIndex: i]] asSieveQuotedString]];
|
||||
|
||||
if (i == [addresses count]-1)
|
||||
[vacation_script appendString: @"] "];
|
||||
@@ -1184,7 +1184,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
[vacation_script appendString: @", "];
|
||||
}
|
||||
|
||||
[vacation_script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
|
||||
[vacation_script appendFormat: @"%@;\r\n", [text asSieveQuotedString]];
|
||||
|
||||
// Should we discard incoming mails during vacation?
|
||||
if (discardMails)
|
||||
@@ -1226,7 +1226,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
v = [addresses objectAtIndex: i];
|
||||
if (v && [v length] > 0)
|
||||
{
|
||||
redirect = [NSString stringWithFormat: @"redirect \"%@\";\r\n", v];
|
||||
redirect = [NSString stringWithFormat: @"redirect %@;\r\n", [v asSieveQuotedString]];
|
||||
if (alwaysSend)
|
||||
[script insertString: redirect atIndex: 0];
|
||||
else
|
||||
@@ -1265,7 +1265,11 @@ static NSString *sieveScriptName = @"sogo";
|
||||
addresses = [addresses componentsSeparatedByString: @","];
|
||||
|
||||
message = [values objectForKey: @"notificationMessage"];
|
||||
if (![message isKindOfClass: [NSString class]])
|
||||
message = @"";
|
||||
notificationTranslated = [values objectForKey: @"notificationTranslated"];
|
||||
if (![notificationTranslated isKindOfClass: [NSString class]])
|
||||
notificationTranslated = @"";
|
||||
|
||||
for (i = 0; i < [addresses count]; i++)
|
||||
{
|
||||
@@ -1274,8 +1278,10 @@ static NSString *sieveScriptName = @"sogo";
|
||||
{
|
||||
notify = @"if header :matches \"subject\" \"*\" {\r\n set \"subject\" \"${1}\";\r\n}\r\n";
|
||||
notify = [notify stringByAppendingString: @"if header :matches \"From\" \"*<*>\" {\r\n set \"from\" \"${1} ${2}\";\r\n}\r\n"];
|
||||
notify = [notify stringByAppendingFormat: @"set :encodeurl \"body_param\" \"%@\";\r\n", message];
|
||||
notify = [notify stringByAppendingFormat: @"notify :message \"%@: '${subject}' from: ${from}\" \"mailto:%@?body=${body_param}\";\r\n", notificationTranslated, v];
|
||||
notify = [notify stringByAppendingFormat: @"set :encodeurl \"body_param\" %@;\r\n", [message asSieveQuotedString]];
|
||||
notify = [notify stringByAppendingFormat: @"notify :message %@ %@;\r\n",
|
||||
[[NSString stringWithFormat: @"%@: '${subject}' from: ${from}", notificationTranslated] asSieveQuotedString],
|
||||
[[NSString stringWithFormat: @"mailto:%@?body=${body_param}", v] asSieveQuotedString]];
|
||||
|
||||
[script appendString: notify];
|
||||
}
|
||||
|
||||
@@ -1747,6 +1747,76 @@ static NSArray *reminderValues = nil;
|
||||
return YES;
|
||||
}
|
||||
|
||||
//
|
||||
// Checks a list of addresses (array, or comma-separated string as found in
|
||||
// the Notification preference) against SOGoForwardConstraints.
|
||||
//
|
||||
- (BOOL) _addressesMatchForwardConstraints: (id) addresses
|
||||
{
|
||||
NSMutableArray *mails;
|
||||
id address;
|
||||
|
||||
if ([[[context activeUser] domainDefaults] forwardConstraints] <= 0)
|
||||
return YES;
|
||||
|
||||
if ([addresses isKindOfClass: [NSString class]])
|
||||
addresses = [addresses componentsSeparatedByString: @","];
|
||||
|
||||
if (![addresses isKindOfClass: [NSArray class]])
|
||||
return NO;
|
||||
|
||||
mails = [NSMutableArray array];
|
||||
for (address in addresses)
|
||||
{
|
||||
if (![address isKindOfClass: [NSString class]])
|
||||
return NO;
|
||||
if ([address length])
|
||||
[mails addObject: address];
|
||||
}
|
||||
|
||||
return [self doForwardsMatchTheConstraints: mails];
|
||||
}
|
||||
|
||||
//
|
||||
// Checks the arguments of 'redirect' and 'notify' actions of Sieve filters
|
||||
// against SOGoForwardConstraints, as the web interface does client-side.
|
||||
//
|
||||
- (BOOL) _sieveFiltersMatchForwardConstraints: (id) filters
|
||||
{
|
||||
NSMutableArray *mails;
|
||||
id filter, actions, action, method, argument;
|
||||
|
||||
if ([[[context activeUser] domainDefaults] forwardConstraints] <= 0
|
||||
|| ![filters isKindOfClass: [NSArray class]])
|
||||
return YES;
|
||||
|
||||
mails = [NSMutableArray array];
|
||||
for (filter in filters)
|
||||
{
|
||||
if (![filter isKindOfClass: [NSDictionary class]])
|
||||
continue;
|
||||
actions = [filter objectForKey: @"actions"];
|
||||
if (![actions isKindOfClass: [NSArray class]])
|
||||
continue;
|
||||
for (action in actions)
|
||||
{
|
||||
if (![action isKindOfClass: [NSDictionary class]])
|
||||
continue;
|
||||
method = [action objectForKey: @"method"];
|
||||
if ([method isKindOfClass: [NSString class]]
|
||||
&& ([method isEqualToString: @"redirect"] || [method isEqualToString: @"notify"]))
|
||||
{
|
||||
argument = [action objectForKey: @"argument"];
|
||||
if (![argument isKindOfClass: [NSString class]])
|
||||
return NO;
|
||||
[mails addObject: argument];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [self doForwardsMatchTheConstraints: mails];
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /so/:username/Preferences/save Save user's defaults and settings
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1780,7 +1850,7 @@ static NSArray *reminderValues = nil;
|
||||
{
|
||||
NSMutableDictionary *sanitizedLabels;
|
||||
NSArray *allKeys, *accounts, *identities, *forwardMails;
|
||||
NSDictionary *newLabels, *forwardPref;
|
||||
NSDictionary *newLabels, *forwardPref, *notificationPref;
|
||||
NSString *name;
|
||||
id loginModule;
|
||||
|
||||
@@ -1833,6 +1903,29 @@ static NSArray *reminderValues = nil;
|
||||
[v removeObjectForKey: @"Forward"];
|
||||
}
|
||||
|
||||
// Notification addresses and filters' redirect/notify actions are
|
||||
// subject to the same forward constraints. Since the submitted values
|
||||
// replace all the stored ones, keep the currently stored value when
|
||||
// the new one is rejected (otherwise all the filters would be lost).
|
||||
notificationPref = [v objectForKey: @"Notification"];
|
||||
if (notificationPref && [notificationPref isKindOfClass: [NSDictionary class]]
|
||||
&& [[notificationPref objectForKey: @"enabled"] boolValue]
|
||||
&& ![self _addressesMatchForwardConstraints: [notificationPref objectForKey: @"notificationAddress"]])
|
||||
{
|
||||
if ([[user userDefaults] notificationOptions])
|
||||
[v setObject: [[user userDefaults] notificationOptions] forKey: @"Notification"];
|
||||
else
|
||||
[v removeObjectForKey: @"Notification"];
|
||||
}
|
||||
|
||||
if (![self _sieveFiltersMatchForwardConstraints: [v objectForKey: @"SOGoSieveFilters"]])
|
||||
{
|
||||
if ([[user userDefaults] sieveFilters])
|
||||
[v setObject: [[user userDefaults] sieveFilters] forKey: @"SOGoSieveFilters"];
|
||||
else
|
||||
[v removeObjectForKey: @"SOGoSieveFilters"];
|
||||
}
|
||||
|
||||
if ([self userHasMailAccess])
|
||||
{
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user