1#include <sys/ioctl.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <stdio.h>
6#include <errno.h>
7#include <string.h>
8#include <inttypes.h>
9#include <unistd.h>
10
11#include <linux/usbdevice_fs.h>
12
13/* For building without an updated set of headers */
14#ifndef USBDEVFS_DROP_PRIVILEGES
15#define USBDEVFS_DROP_PRIVILEGES		_IOW('U', 30, __u32)
16#define USBDEVFS_CAP_DROP_PRIVILEGES		0x40
17#endif
18
19void drop_privileges(int fd, uint32_t mask)
20{
21	int res;
22
23	res = ioctl(fd, USBDEVFS_DROP_PRIVILEGES, &mask);
24	if (res)
25		printf("ERROR: USBDEVFS_DROP_PRIVILEGES returned %d\n", res);
26	else
27		printf("OK: privileges dropped!\n");
28}
29
30void reset_device(int fd)
31{
32	int res;
33
34	res = ioctl(fd, USBDEVFS_RESET);
35	if (!res)
36		printf("OK: USBDEVFS_RESET succeeded\n");
37	else
38		printf("ERROR: reset failed! (%d - %s)\n",
39		       -res, strerror(-res));
40}
41
42void claim_some_intf(int fd)
43{
44	int i, res;
45
46	for (i = 0; i < 4; i++) {
47		res = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &i);
48		if (!res)
49			printf("OK: claimed if %d\n", i);
50		else
51			printf("ERROR claiming if %d (%d - %s)\n",
52			       i, -res, strerror(-res));
53	}
54}
55
56int main(int argc, char *argv[])
57{
58	uint32_t mask, caps;
59	int c, fd;
60
61	fd = open(argv[1], O_RDWR);
62	if (fd < 0) {
63		printf("Failed to open file\n");
64		goto err_fd;
65	}
66
67	/*
68	 * check if dropping privileges is supported,
69	 * bail on systems where the capability is not present
70	 */
71	ioctl(fd, USBDEVFS_GET_CAPABILITIES, &caps);
72	if (!(caps & USBDEVFS_CAP_DROP_PRIVILEGES)) {
73		printf("DROP_PRIVILEGES not supported\n");
74		goto err;
75	}
76
77	/*
78	 * Drop privileges but keep the ability to claim all
79	 * free interfaces (i.e., those not used by kernel drivers)
80	 */
81	drop_privileges(fd, -1U);
82
83	printf("Available options:\n"
84		"[0] Exit now\n"
85		"[1] Reset device. Should fail if device is in use\n"
86		"[2] Claim 4 interfaces. Should succeed where not in use\n"
87		"[3] Narrow interface permission mask\n"
88		"Which option shall I run?: ");
89
90	while (scanf("%d", &c) == 1) {
91		switch (c) {
92		case 0:
93			goto exit;
94		case 1:
95			reset_device(fd);
96			break;
97		case 2:
98			claim_some_intf(fd);
99			break;
100		case 3:
101			printf("Insert new mask: ");
102			scanf("%x", &mask);
103			drop_privileges(fd, mask);
104			break;
105		default:
106			printf("I don't recognize that\n");
107		}
108
109		printf("Which test shall I run next?: ");
110	}
111
112exit:
113	close(fd);
114	return 0;
115
116err:
117	close(fd);
118err_fd:
119	return 1;
120}
121