]> git.saurik.com Git - apple/xnu.git/blame - tools/tests/personas/persona_mgr.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / tools / tests / personas / persona_mgr.c
CommitLineData
490019cf
A
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
40enum {
41 PERSONA_OP_CREATE = 1,
42 PERSONA_OP_DESTROY = 2,
43 PERSONA_OP_LOOKUP = 3,
d9a64523
A
44 PERSONA_OP_SUPPORT = 4,
45 PERSONA_OP_MAX = 4,
490019cf
A
46};
47
48static struct mgr_config {
49 int verbose;
50} g;
51
52
53static int persona_op_create(struct kpersona_info *ki)
54{
55 int ret;
56 uid_t persona_id = 0;
57
58 info("Creating persona...");
59 ki->persona_info_version = PERSONA_INFO_V1;
60 ret = kpersona_alloc(ki, &persona_id);
61 if (ret == 0) {
62 info("Created persona %d:", persona_id);
63 dump_kpersona(NULL, ki);
64 } else {
65 err("kpersona_alloc return %d (errno:%d)", ret, errno);
66 }
67
68 return ret;
69}
70
71static int persona_op_destroy(struct kpersona_info *ki)
72{
73 int ret;
74
75 info("Destroying Persona %d...", ki->persona_id);
76 ki->persona_info_version = PERSONA_INFO_V1;
77 ret = kpersona_dealloc(ki->persona_id);
78 if (ret < 0)
79 err_print("destroy failed!");
80
81 return ret;
82}
83
84static int persona_op_lookup(struct kpersona_info *ki, pid_t pid, uid_t uid)
85{
86 int ret;
87
d9a64523 88 info("Looking up persona (login:%s, pid:%d, uid:%d)", ki->persona_name, pid, uid);
490019cf
A
89 if (pid > 0) {
90 ki->persona_info_version = PERSONA_INFO_V1;
91 ret = kpersona_pidinfo(pid, ki);
92 if (ret < 0)
93 err_print("pidinfo failed!");
94 else
95 dump_kpersona("Persona-for-pid:", ki);
96 } else {
97 int np = 0;
98 uid_t personas[128];
99 size_t npersonas = ARRAY_SZ(personas);
100 const char *name = NULL;
101 if (ki->persona_name[0] != 0)
102 name = ki->persona_name;
103
104 np = kpersona_find(name, uid, personas, &npersonas);
105 if (np < 0)
106 err("kpersona_find returned %d (errno:%d)", np, errno);
107 info("Found %zu persona%c", npersonas, npersonas != 1 ? 's' : ' ');
108 np = npersonas;
109 while (np--) {
110 info("\tpersona[%d]=%d...", np, personas[np]);
111 ki->persona_info_version = PERSONA_INFO_V1;
112 ret = kpersona_info(personas[np], ki);
113 if (ret < 0)
114 err("kpersona_info failed (errno:%d) for persona[%d]", errno, personas[np]);
115 dump_kpersona(NULL, ki);
116 }
117 }
118
119 return ret;
120}
121
d9a64523
A
122static int persona_op_support(void)
123{
124 uid_t pna_id = -1;
125 int ret = kpersona_get(&pna_id);
126 if (ret == 0 || errno != ENOSYS) {
127 info("Persona subsystem is supported (id=%d)", pna_id);
128 return 0;
129 }
130
131 info("Persona subsystem is not supported");
132 return ENOSYS;
133}
134
490019cf
A
135
136/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
137 *
138 * Main Entry Point
139 *
140 * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
141 */
142static void usage_main(const char *progname, const char *msg, int verbose)
143{
144 const char *nm = basename((char *)progname);
145
146 if (msg)
147 printf("%s\n\n", msg);
148
149 printf("%s v%d.%d\n", PROG_NAME, PROG_VMAJOR, PROG_VMINOR);
150 printf("usage: %s [op] [-v] [-i id] [-t type] [-p pid] [-u uid] [-g gid] [-l login] [-G {groupspec}] [-m gmuid]\n", nm);
151 if (!verbose)
152 exit(1);
153
d9a64523 154 printf("\t%-15s\tOne of: create | destroy | lookup | support\n", "[op]");
490019cf
A
155 printf("\t%-15s\tBe verbose\n", "-v");
156
157 printf("\t%-15s\tID of the persona\n", "-i id");
158 printf("\t%-15s\tType of the persona\n", "-t type");
159 printf("\t%-15s\tPID of the process whose persona info to lookup\n", "-p pid");
160 printf("\t%-15s\tUID to use in lookup\n", "-u uid");
161 printf("\t%-15s\tGID of the persona\n", "-g gid");
162 printf("\t%-15s\tLogin name of the persona\n", "-l login");
163 printf("\t%-15s\tGroups to which the persona will belong\n", "-G {groupspec}");
164 printf("\t%-15s\tgroupspec: G1{,G2,G3...}\n", " ");
165 printf("\t%-15s\tUID used for memberd lookup (opt-in to memberd)\n", "-m gmuid");
166
167 printf("\n");
168 exit(1);
169}
170
171int main(int argc, char **argv)
172{
173 char ch;
174 int ret;
175
176 const char *op_str = NULL;
d9a64523 177 int persona_op = -1;
490019cf
A
178 struct kpersona_info kinfo;
179 uid_t uid = (uid_t)-1;
180 pid_t pid = (pid_t)-1;
181
182 /*
183 * Defaults
184 */
185 g.verbose = 0;
186
187 if (geteuid() != 0)
188 err("%s must be run as root", argv[0] ? basename(argv[0]) : PROG_NAME);
189
190 if (argc < 2)
191 usage_main(argv[0], "Not enough arguments", 0);
192
193 op_str = argv[1];
194
195 if (strcmp(op_str, "create") == 0)
196 persona_op = PERSONA_OP_CREATE;
197 else if (strcmp(op_str, "destroy") == 0)
198 persona_op = PERSONA_OP_DESTROY;
199 else if (strcmp(op_str, "lookup") == 0)
200 persona_op = PERSONA_OP_LOOKUP;
d9a64523
A
201 else if (strcmp(op_str, "support") == 0)
202 persona_op = PERSONA_OP_SUPPORT;
490019cf
A
203 else if (strcmp(op_str, "help") == 0 || strcmp(op_str, "-h") == 0)
204 usage_main(argv[0], NULL, 1);
205
206 if (persona_op <= 0 || persona_op > PERSONA_OP_MAX)
207 usage_main(argv[0], "Invalid [op]", 0);
208
209 memset(&kinfo, 0, sizeof(kinfo));
210 kinfo.persona_gmuid = KAUTH_UID_NONE;
211
212 /*
213 * Argument parse
214 */
215 optind = 2;
216 while ((ch = getopt(argc, argv, "vi:t:p:u:g:l:G:m:h")) != -1) {
217 switch (ch) {
218 case 'i':
219 ret = atoi(optarg);
d9a64523
A
220 if (ret <= 0) {
221 ret = PERSONA_ID_NONE;
222 }
490019cf
A
223 kinfo.persona_id = (uid_t)ret;
224 break;
225 case 't':
d9a64523
A
226 if (strncmp(optarg, "guest", 6) == 0) {
227 kinfo.persona_type = PERSONA_GUEST;
228 } else if (strncmp(optarg, "managed", 8) == 0) {
229 kinfo.persona_type = PERSONA_MANAGED;
230 } else if (strncmp(optarg, "priv", 4) == 0) { /* shortcut... */
231 kinfo.persona_type = PERSONA_PRIV;
232 } else if (strncmp(optarg, "system", 7) == 0) {
233 kinfo.persona_type = PERSONA_SYSTEM;
234 } else {
235 ret = atoi(optarg);
236 if (ret <= PERSONA_INVALID || ret > PERSONA_TYPE_MAX) {
237 err("Invalid type specification: %s", optarg);
238 }
239 kinfo.persona_type = ret;
240 }
490019cf
A
241 break;
242 case 'p':
243 ret = atoi(optarg);
244 if (ret <= 0)
245 err("Invalid PID: %s", optarg);
246 pid = (pid_t)ret;
247 break;
248 case 'u':
249 ret = atoi(optarg);
527f9951
A
250 /* allow invalid / -1 as a wildcard for lookup */
251 if (ret < 0 && persona_op != PERSONA_OP_LOOKUP) {
252 err("Invalid UID:%s (%d)", optarg, ret);
253 }
490019cf
A
254 uid = (uid_t)ret;
255 break;
256 case 'g':
257 kinfo.persona_gid = (gid_t)atoi(optarg);
258 if (kinfo.persona_gid <= 500)
259 err("Invalid GID: %d", kinfo.persona_gid);
260 break;
261 case 'l':
262 strncpy(kinfo.persona_name, optarg, MAXLOGNAME);
263 break;
264 case 'G':
265 ret = parse_groupspec(&kinfo, optarg);
266 if (ret < 0)
267 err("Invalid groupspec: \"%s\"", optarg);
268 break;
269 case 'm':
270 ret = atoi(optarg);
271 if (ret < 0)
272 err("Invalid group membership ID: %s", optarg);
273 kinfo.persona_gmuid = (uid_t)ret;
274 break;
275 case 'v':
276 g.verbose = 1;
277 break;
278 case 'h':
279 case '?':
280 usage_main(argv[0], NULL, 1);
281 case ':':
282 default:
283 printf("Invalid option: '%c'\n", ch);
284 usage_main(argv[0], NULL, 0);
285 }
286 }
287
d9a64523 288 if (uid == (uid_t)-1 && persona_op != PERSONA_OP_LOOKUP) {
490019cf 289 uid = kinfo.persona_id;
d9a64523 290 }
490019cf 291
d9a64523 292 if (kinfo.persona_gmuid != KAUTH_UID_NONE && kinfo.persona_ngroups == 0) {
490019cf
A
293 /*
294 * In order to set the group membership UID, we need to set at
295 * least one group: make it equal to either the GID or UID
296 */
297 kinfo.persona_ngroups = 1;
298 if (kinfo.persona_gid)
299 kinfo.persona_groups[0] = kinfo.persona_gid;
300 else
301 kinfo.persona_groups[0] = kinfo.persona_id;
302 }
303
304 if (g.verbose)
305 dump_kpersona("Input persona:", &kinfo);
306
307 switch (persona_op) {
308 case PERSONA_OP_CREATE:
309 ret = persona_op_create(&kinfo);
310 break;
311 case PERSONA_OP_DESTROY:
312 ret = persona_op_destroy(&kinfo);
313 break;
314 case PERSONA_OP_LOOKUP:
315 ret = persona_op_lookup(&kinfo, pid, uid);
316 break;
d9a64523
A
317 case PERSONA_OP_SUPPORT:
318 ret = persona_op_support();
319 break;
490019cf
A
320 default:
321 err("Invalid persona op: %d", persona_op);
322 }
323
324 return ret;
325}