]> git.saurik.com Git - apple/security.git/blob - RegressionTests/manifeststresstest/manifeststresstest.m
Security-59306.61.1.tar.gz
[apple/security.git] / RegressionTests / manifeststresstest / manifeststresstest.m
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
18 static 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
68 static void usage_exit(void)
69 {
70 printf("%s", usage_message);
71 exit(1);
72 }
73
74 int 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 }