]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/personas/persona_mgr.c
xnu-3248.40.184.tar.gz
[apple/xnu.git] / tools / tests / personas / persona_mgr.c
1 /*
2 * persona_mgr.c
3 * Tool to manage personas
4 *
5 * Jeremy C. Andrus <jeremy_andrus@apple.com>
6 *
7 */
8 #include <ctype.h>
9 #include <err.h>
10 #include <errno.h>
11 #include <inttypes.h>
12 #include <libgen.h>
13 #include <pthread.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <mach/mach.h>
20 #include <mach/task.h>
21 #include <mach/vm_param.h>
22 #include <sys/kauth.h>
23 #include <sys/queue.h>
24 #include <sys/sysctl.h>
25 #include <sys/types.h>
26
27 #include "persona_test.h"
28
29 /* internal */
30 #include <libproc.h>
31 #include <spawn_private.h>
32 #include <sys/persona.h>
33 #include <sys/proc_info.h>
34 #include <sys/spawn_internal.h>
35
36 #define PROG_NAME "Persona Manager"
37 #define PROG_VMAJOR 0
38 #define PROG_VMINOR 1
39
40 enum {
41 PERSONA_OP_CREATE = 1,
42 PERSONA_OP_DESTROY = 2,
43 PERSONA_OP_LOOKUP = 3,
44 PERSONA_OP_MAX = 3,
45 };
46
47 static struct mgr_config {
48 int verbose;
49 } g;
50
51
52 static int persona_op_create(struct kpersona_info *ki)
53 {
54 int ret;
55 uid_t persona_id = 0;
56
57 info("Creating persona...");
58 ki->persona_info_version = PERSONA_INFO_V1;
59 ret = kpersona_alloc(ki, &persona_id);
60 if (ret == 0) {
61 info("Created persona %d:", persona_id);
62 dump_kpersona(NULL, ki);
63 } else {
64 err("kpersona_alloc return %d (errno:%d)", ret, errno);
65 }
66
67 return ret;
68 }
69
70 static int persona_op_destroy(struct kpersona_info *ki)
71 {
72 int ret;
73
74 info("Destroying Persona %d...", ki->persona_id);
75 ki->persona_info_version = PERSONA_INFO_V1;
76 ret = kpersona_dealloc(ki->persona_id);
77 if (ret < 0)
78 err_print("destroy failed!");
79
80 return ret;
81 }
82
83 static int persona_op_lookup(struct kpersona_info *ki, pid_t pid, uid_t uid)
84 {
85 int ret;
86
87 info("Looking up persona (pid:%d, uid:%d)", pid, uid);
88 if (pid > 0) {
89 ki->persona_info_version = PERSONA_INFO_V1;
90 ret = kpersona_pidinfo(pid, ki);
91 if (ret < 0)
92 err_print("pidinfo failed!");
93 else
94 dump_kpersona("Persona-for-pid:", ki);
95 } else {
96 int np = 0;
97 uid_t personas[128];
98 size_t npersonas = ARRAY_SZ(personas);
99 const char *name = NULL;
100 if (ki->persona_name[0] != 0)
101 name = ki->persona_name;
102
103 np = kpersona_find(name, uid, personas, &npersonas);
104 if (np < 0)
105 err("kpersona_find returned %d (errno:%d)", np, errno);
106 info("Found %zu persona%c", npersonas, npersonas != 1 ? 's' : ' ');
107 np = npersonas;
108 while (np--) {
109 info("\tpersona[%d]=%d...", np, personas[np]);
110 ki->persona_info_version = PERSONA_INFO_V1;
111 ret = kpersona_info(personas[np], ki);
112 if (ret < 0)
113 err("kpersona_info failed (errno:%d) for persona[%d]", errno, personas[np]);
114 dump_kpersona(NULL, ki);
115 }
116 }
117
118 return ret;
119 }
120
121
122 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
123 *
124 * Main Entry Point
125 *
126 * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
127 */
128 static void usage_main(const char *progname, const char *msg, int verbose)
129 {
130 const char *nm = basename((char *)progname);
131
132 if (msg)
133 printf("%s\n\n", msg);
134
135 printf("%s v%d.%d\n", PROG_NAME, PROG_VMAJOR, PROG_VMINOR);
136 printf("usage: %s [op] [-v] [-i id] [-t type] [-p pid] [-u uid] [-g gid] [-l login] [-G {groupspec}] [-m gmuid]\n", nm);
137 if (!verbose)
138 exit(1);
139
140 printf("\t%-15s\tOne of: create | destroy | lookup\n", "[op]");
141 printf("\t%-15s\tBe verbose\n", "-v");
142
143 printf("\t%-15s\tID of the persona\n", "-i id");
144 printf("\t%-15s\tType of the persona\n", "-t type");
145 printf("\t%-15s\tPID of the process whose persona info to lookup\n", "-p pid");
146 printf("\t%-15s\tUID to use in lookup\n", "-u uid");
147 printf("\t%-15s\tGID of the persona\n", "-g gid");
148 printf("\t%-15s\tLogin name of the persona\n", "-l login");
149 printf("\t%-15s\tGroups to which the persona will belong\n", "-G {groupspec}");
150 printf("\t%-15s\tgroupspec: G1{,G2,G3...}\n", " ");
151 printf("\t%-15s\tUID used for memberd lookup (opt-in to memberd)\n", "-m gmuid");
152
153 printf("\n");
154 exit(1);
155 }
156
157 int main(int argc, char **argv)
158 {
159 char ch;
160 int ret;
161
162 const char *op_str = NULL;
163 int persona_op = 0;
164 struct kpersona_info kinfo;
165 uid_t uid = (uid_t)-1;
166 pid_t pid = (pid_t)-1;
167
168 /*
169 * Defaults
170 */
171 g.verbose = 0;
172
173 if (geteuid() != 0)
174 err("%s must be run as root", argv[0] ? basename(argv[0]) : PROG_NAME);
175
176 if (argc < 2)
177 usage_main(argv[0], "Not enough arguments", 0);
178
179 op_str = argv[1];
180
181 if (strcmp(op_str, "create") == 0)
182 persona_op = PERSONA_OP_CREATE;
183 else if (strcmp(op_str, "destroy") == 0)
184 persona_op = PERSONA_OP_DESTROY;
185 else if (strcmp(op_str, "lookup") == 0)
186 persona_op = PERSONA_OP_LOOKUP;
187 else if (strcmp(op_str, "help") == 0 || strcmp(op_str, "-h") == 0)
188 usage_main(argv[0], NULL, 1);
189
190 if (persona_op <= 0 || persona_op > PERSONA_OP_MAX)
191 usage_main(argv[0], "Invalid [op]", 0);
192
193 memset(&kinfo, 0, sizeof(kinfo));
194 kinfo.persona_gmuid = KAUTH_UID_NONE;
195
196 /*
197 * Argument parse
198 */
199 optind = 2;
200 while ((ch = getopt(argc, argv, "vi:t:p:u:g:l:G:m:h")) != -1) {
201 switch (ch) {
202 case 'i':
203 ret = atoi(optarg);
204 if (ret <= 0)
205 err("Invalid Persona ID: %s", optarg);
206 kinfo.persona_id = (uid_t)ret;
207 break;
208 case 't':
209 ret = atoi(optarg);
210 if (ret <= PERSONA_INVALID || ret > PERSONA_TYPE_MAX)
211 err("Invalid type specification: %s", optarg);
212 kinfo.persona_type = ret;
213 break;
214 case 'p':
215 ret = atoi(optarg);
216 if (ret <= 0)
217 err("Invalid PID: %s", optarg);
218 pid = (pid_t)ret;
219 break;
220 case 'u':
221 ret = atoi(optarg);
222 if (ret <= 0)
223 err("Invalid UID: %s", optarg);
224 uid = (uid_t)ret;
225 break;
226 case 'g':
227 kinfo.persona_gid = (gid_t)atoi(optarg);
228 if (kinfo.persona_gid <= 500)
229 err("Invalid GID: %d", kinfo.persona_gid);
230 break;
231 case 'l':
232 strncpy(kinfo.persona_name, optarg, MAXLOGNAME);
233 break;
234 case 'G':
235 ret = parse_groupspec(&kinfo, optarg);
236 if (ret < 0)
237 err("Invalid groupspec: \"%s\"", optarg);
238 break;
239 case 'm':
240 ret = atoi(optarg);
241 if (ret < 0)
242 err("Invalid group membership ID: %s", optarg);
243 kinfo.persona_gmuid = (uid_t)ret;
244 break;
245 case 'v':
246 g.verbose = 1;
247 break;
248 case 'h':
249 case '?':
250 usage_main(argv[0], NULL, 1);
251 case ':':
252 default:
253 printf("Invalid option: '%c'\n", ch);
254 usage_main(argv[0], NULL, 0);
255 }
256 }
257
258 if (uid == (uid_t)-1)
259 uid = kinfo.persona_id;
260
261 if (kinfo.persona_gmuid && kinfo.persona_ngroups == 0) {
262 /*
263 * In order to set the group membership UID, we need to set at
264 * least one group: make it equal to either the GID or UID
265 */
266 kinfo.persona_ngroups = 1;
267 if (kinfo.persona_gid)
268 kinfo.persona_groups[0] = kinfo.persona_gid;
269 else
270 kinfo.persona_groups[0] = kinfo.persona_id;
271 }
272
273 if (g.verbose)
274 dump_kpersona("Input persona:", &kinfo);
275
276 switch (persona_op) {
277 case PERSONA_OP_CREATE:
278 ret = persona_op_create(&kinfo);
279 break;
280 case PERSONA_OP_DESTROY:
281 ret = persona_op_destroy(&kinfo);
282 break;
283 case PERSONA_OP_LOOKUP:
284 ret = persona_op_lookup(&kinfo, pid, uid);
285 break;
286 default:
287 err("Invalid persona op: %d", persona_op);
288 }
289
290 return ret;
291 }