162306a36Sopenharmony_ci#include <sys/ioctl.h>
262306a36Sopenharmony_ci#include <sys/types.h>
362306a36Sopenharmony_ci#include <sys/stat.h>
462306a36Sopenharmony_ci#include <fcntl.h>
562306a36Sopenharmony_ci#include <stdio.h>
662306a36Sopenharmony_ci#include <errno.h>
762306a36Sopenharmony_ci#include <string.h>
862306a36Sopenharmony_ci#include <inttypes.h>
962306a36Sopenharmony_ci#include <unistd.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/usbdevice_fs.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* For building without an updated set of headers */
1462306a36Sopenharmony_ci#ifndef USBDEVFS_DROP_PRIVILEGES
1562306a36Sopenharmony_ci#define USBDEVFS_DROP_PRIVILEGES		_IOW('U', 30, __u32)
1662306a36Sopenharmony_ci#define USBDEVFS_CAP_DROP_PRIVILEGES		0x40
1762306a36Sopenharmony_ci#endif
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_civoid drop_privileges(int fd, uint32_t mask)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int res;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	res = ioctl(fd, USBDEVFS_DROP_PRIVILEGES, &mask);
2462306a36Sopenharmony_ci	if (res)
2562306a36Sopenharmony_ci		printf("ERROR: USBDEVFS_DROP_PRIVILEGES returned %d\n", res);
2662306a36Sopenharmony_ci	else
2762306a36Sopenharmony_ci		printf("OK: privileges dropped!\n");
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_civoid reset_device(int fd)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	int res;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	res = ioctl(fd, USBDEVFS_RESET);
3562306a36Sopenharmony_ci	if (!res)
3662306a36Sopenharmony_ci		printf("OK: USBDEVFS_RESET succeeded\n");
3762306a36Sopenharmony_ci	else
3862306a36Sopenharmony_ci		printf("ERROR: reset failed! (%d - %s)\n",
3962306a36Sopenharmony_ci		       -res, strerror(-res));
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid claim_some_intf(int fd)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	int i, res;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
4762306a36Sopenharmony_ci		res = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &i);
4862306a36Sopenharmony_ci		if (!res)
4962306a36Sopenharmony_ci			printf("OK: claimed if %d\n", i);
5062306a36Sopenharmony_ci		else
5162306a36Sopenharmony_ci			printf("ERROR claiming if %d (%d - %s)\n",
5262306a36Sopenharmony_ci			       i, -res, strerror(-res));
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciint main(int argc, char *argv[])
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	uint32_t mask, caps;
5962306a36Sopenharmony_ci	int c, fd;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	fd = open(argv[1], O_RDWR);
6262306a36Sopenharmony_ci	if (fd < 0) {
6362306a36Sopenharmony_ci		printf("Failed to open file\n");
6462306a36Sopenharmony_ci		goto err_fd;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/*
6862306a36Sopenharmony_ci	 * check if dropping privileges is supported,
6962306a36Sopenharmony_ci	 * bail on systems where the capability is not present
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	ioctl(fd, USBDEVFS_GET_CAPABILITIES, &caps);
7262306a36Sopenharmony_ci	if (!(caps & USBDEVFS_CAP_DROP_PRIVILEGES)) {
7362306a36Sopenharmony_ci		printf("DROP_PRIVILEGES not supported\n");
7462306a36Sopenharmony_ci		goto err;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/*
7862306a36Sopenharmony_ci	 * Drop privileges but keep the ability to claim all
7962306a36Sopenharmony_ci	 * free interfaces (i.e., those not used by kernel drivers)
8062306a36Sopenharmony_ci	 */
8162306a36Sopenharmony_ci	drop_privileges(fd, -1U);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	printf("Available options:\n"
8462306a36Sopenharmony_ci		"[0] Exit now\n"
8562306a36Sopenharmony_ci		"[1] Reset device. Should fail if device is in use\n"
8662306a36Sopenharmony_ci		"[2] Claim 4 interfaces. Should succeed where not in use\n"
8762306a36Sopenharmony_ci		"[3] Narrow interface permission mask\n"
8862306a36Sopenharmony_ci		"Which option shall I run?: ");
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	while (scanf("%d", &c) == 1) {
9162306a36Sopenharmony_ci		switch (c) {
9262306a36Sopenharmony_ci		case 0:
9362306a36Sopenharmony_ci			goto exit;
9462306a36Sopenharmony_ci		case 1:
9562306a36Sopenharmony_ci			reset_device(fd);
9662306a36Sopenharmony_ci			break;
9762306a36Sopenharmony_ci		case 2:
9862306a36Sopenharmony_ci			claim_some_intf(fd);
9962306a36Sopenharmony_ci			break;
10062306a36Sopenharmony_ci		case 3:
10162306a36Sopenharmony_ci			printf("Insert new mask: ");
10262306a36Sopenharmony_ci			scanf("%x", &mask);
10362306a36Sopenharmony_ci			drop_privileges(fd, mask);
10462306a36Sopenharmony_ci			break;
10562306a36Sopenharmony_ci		default:
10662306a36Sopenharmony_ci			printf("I don't recognize that\n");
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		printf("Which test shall I run next?: ");
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciexit:
11362306a36Sopenharmony_ci	close(fd);
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cierr:
11762306a36Sopenharmony_ci	close(fd);
11862306a36Sopenharmony_cierr_fd:
11962306a36Sopenharmony_ci	return 1;
12062306a36Sopenharmony_ci}
121