]> git.saurik.com Git - apple/security.git/blame - RegressionTests/manifeststresstest/manifeststresstest.m
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / RegressionTests / manifeststresstest / manifeststresstest.m
CommitLineData
866f8763
A
1//
2// manifeststresstest.m
3// Security
4//
5// Created by Ben Williamson on 6/1/17.
6//
7//
8
9#import <Foundation/Foundation.h>
10#import <stdlib.h>
11
12#import "Monkey.h"
13#import "Config.h"
14#import "Keychain.h"
15#import "mark.h"
16#import <Security/SecItemPriv.h>
17
18static const char *usage_message =
19"Usage: mainfeststresstest <command> [options...]\n"
20"\n"
21"Commands:\n"
22"\n"
23" reset Delete all items in the access group. Do this before starting the test.\n"
24"\n"
25" monkey Randomly add, update and delete items for a while. Then delete those items.\n"
26" --seed <n> Seed the random number generator\n"
27" --steps <n> Stop after n random actions. Default 1000.\n"
28" --maxitems <n> Limit number of items created to n. Default 20.\n"
29" --nocleanup Leave the items in place when finished.\n"
30" --dryrun Print actions to stdout but don't actually touch the keychain.\n"
31" --name Specialize items names (to isolate and avoid interfering changes)\n"
32" --view Keychain syncing view name. If not, specified \"Engram\" is used\n"
33"\n"
34" mark <id> [view] Write some items containing the string <id>, to mark the known finishing\n"
35" state for this device. The view argument takes a keychain syncing view name;\n"
36" If not specified, the view is \"Engram\".\n"
37"\n"
38" unmark <id> Delete the items that make up the mark for this id.\n"
39"\n"
40" update <id> Update the items that make up the mark for this id.\n"
41"\n"
42" verify <id>... Check that the access group contains only the marks for the\n"
43" given <id> list, corresponding to all the devices being finished.\n"
44" If given an empty id list this checks the access group is empty.\n"
45" Exits with nonzero status if verification fails.\n"
46"\n"
47" verify_update <id>... Check that the access group contains only the updated marks for\n"
48" the given <id> list, corresponding to all the devices being\n"
49" finished. If given an empty id list this checks the access group\n"
50" is empty. Exits with nonzero status if verification fails.\n"
51"\n"
52"Example:\n"
53"\n"
54" manifeststresstest reset\n"
55" manifeststresstest monkey --seed 12345 --steps 1000 --maxitems 20\n"
56" manifeststresstest mark foo\n"
57" manifeststresstest verify foo bar baz\n"
58"\n"
59" One device should run reset to clear the contents of the access group before the test\n"
60" begins. Then all devices should run monkey for a while. When each device is finished\n"
61" monkeying it should set a pattern with an id that uniquely identifies that device.\n"
62" When all devices are finished, one device can verify all the patterns by running the\n"
63" verify command with the ids of all of the devices, as it expects to see the patterns\n"
64" written by all devices, and no other items.\n"
65"\n"
66;
67
68static void usage_exit(void)
69{
70 printf("%s", usage_message);
71 exit(1);
72}
73
74int main(int argc, const char ** argv)
75{
76 @autoreleasepool {
77 Keychain *keychain = [[Keychain alloc] init];
78
79 NSArray<NSString *> *args = [[NSProcessInfo processInfo] arguments];
80 if ([args count] < 2) {
81 usage_exit();
82 }
83 NSString *verb = args[1];
84
85 if ([verb isEqualToString:@"reset"]) {
86 printf("Reseting\n");
87 NSLog(@"reset - deleteAllItems");
88 [keychain deleteAllItems];
89
90 } else if ([verb isEqualToString:@"monkey"]) {
91 BOOL dryrun = NO;
92 BOOL cleanup = YES;
93 unsigned steps = 1000;
94 Config *config = [[Config alloc] init];
95 config.maxItems = 20;
96 config.distinctNames = 40;
97 config.distinctValues = 10;
98 config.addItemWeight = 20;
99 config.deleteItemWeight = 10;
100 config.updateNameWeight = 10;
101 config.updateDataWeight = 10;
102 config.updateNameAndDataWeight = 10;
103 config.view = (__bridge NSString *)kSecAttrViewHintEngram;
104
105 NSUInteger i = 2;
106 while (i < [args count]) {
107 NSString *opt = args[i++];
108 if ([opt isEqualToString:@"--seed"]) {
109 if (i >= [args count]) {
110 printf("error: --seed needs a value\n");
111 exit(1);
112 }
113 unsigned seed = (unsigned)[args[i++] integerValue];
114 NSLog(@"Seeding with %d", seed);
115 srandom(seed);
116 } else if ([opt isEqualToString:@"--steps"]) {
117 if (i >= [args count]) {
118 printf("error: --steps needs a value\n");
119 exit(1);
120 }
121 steps = (unsigned)[args[i++] integerValue];
122 } else if ([opt isEqualToString:@"--maxitems"]) {
123 if (i >= [args count]) {
124 printf("error: --maxitems needs a value\n");
125 exit(1);
126 }
127 config.maxItems = (unsigned)[args[i++] integerValue];
128 } else if ([opt isEqualToString:@"--nocleanup"]) {
129 cleanup = NO;
130 } else if ([opt isEqualToString:@"--dryrun"]) {
131 dryrun = YES;
132 } else if ([opt isEqualToString:@"--name"]) {
133 if (i >= [args count]) {
134 printf("error: --name needs a value\n");
135 exit(1);
136 }
137 config.name = args[i++];
138 } else if ([opt isEqualToString:@"--view"]) {
139 if (i >= [args count]) {
140 printf("error: --view needs a value\n");
141 exit(1);
142 }
143 config.view = args[i++];
144 } else {
145 printf("Unrecognised argument %s\n", [opt UTF8String]);
146 exit(1);
147 }
148 }
149 NSLog(@"steps: %d", steps);
150 NSLog(@"maxitems: %d", config.maxItems);
151 NSLog(@"cleanup: %s", cleanup ? "yes" : "no");
152 NSLog(@"dryrun: %s", dryrun ? "yes" : "no");
153
154 Monkey *monkey = [[Monkey alloc] initWithConfig:config];
155 if (!dryrun) {
156 monkey.keychain = keychain;
157 }
158
159 while (monkey.step < steps) {
160 [monkey advanceOneStep];
161 }
162
163 if (cleanup) {
164 [monkey cleanup];
165 }
166
167 } else if ([verb isEqualToString:@"mark"]) {
168 if ([args count] < 3) {
169 printf("mark command needs an identifier\n");
170 exit(1);
171 }
172 NSString *ident = args[2];
173 NSString *view = (__bridge NSString*)kSecAttrViewHintEngram;
174 if ([args count] == 4) {
175 view = args[3];
176 }
177 NSLog(@"Writing mark %@", ident);
178 writeMark(ident, view);
179
180 } else if ([verb isEqualToString:@"unmark"]) {
181 if ([args count] < 3) {
182 printf("unmark command needs an identifier\n");
183 exit(1);
184 }
185 NSString *ident = args[2];
186 NSLog(@"Deleting mark %@", ident);
187 deleteMark(ident);
188
189 } else if ([verb isEqualToString:@"verify"]) {
190 NSRange range;
191 range.location = 2;
192 range.length = args.count - 2;
193 NSArray<NSString*> *idents = [args subarrayWithRange:range];
194 NSLog(@"Verifying, idents = %@", idents);
195 if (!verifyMarks(idents)) {
196 NSLog(@"Exiting nonzero status");
197 exit(1);
198 }
199
200 } else if ([verb isEqualToString:@"update"]) {
201 if ([args count] < 3) {
202 printf("unmark command needs an identifier\n");
203 exit(1);
204 }
205 NSString *ident = args[2];
206 NSLog(@"Updating mark %@", ident);
207 updateMark(ident);
208
209 } else if ([verb isEqualToString:@"verify_update"]) {
210 NSRange range;
211 range.location = 2;
212 range.length = args.count - 2;
213 NSArray<NSString*> *idents = [args subarrayWithRange:range];
214 NSLog(@"Verifying, idents = %@", idents);
215 if (!verifyUpdateMarks(idents)) {
216 NSLog(@"Exiting nonzero status");
217 exit(1);
218 }
219
220 } else {
221 usage_exit();
222 }
223 NSLog(@"Done.");
224 }
225}