18c2ecf20Sopenharmony_ci#include <sys/ioctl.h>
28c2ecf20Sopenharmony_ci#include <sys/types.h>
38c2ecf20Sopenharmony_ci#include <sys/stat.h>
48c2ecf20Sopenharmony_ci#include <fcntl.h>
58c2ecf20Sopenharmony_ci#include <stdio.h>
68c2ecf20Sopenharmony_ci#include <errno.h>
78c2ecf20Sopenharmony_ci#include <string.h>
88c2ecf20Sopenharmony_ci#include <inttypes.h>
98c2ecf20Sopenharmony_ci#include <unistd.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/usbdevice_fs.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* For building without an updated set of headers */
148c2ecf20Sopenharmony_ci#ifndef USBDEVFS_DROP_PRIVILEGES
158c2ecf20Sopenharmony_ci#define USBDEVFS_DROP_PRIVILEGES		_IOW('U', 30, __u32)
168c2ecf20Sopenharmony_ci#define USBDEVFS_CAP_DROP_PRIVILEGES		0x40
178c2ecf20Sopenharmony_ci#endif
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_civoid drop_privileges(int fd, uint32_t mask)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	int res;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	res = ioctl(fd, USBDEVFS_DROP_PRIVILEGES, &mask);
248c2ecf20Sopenharmony_ci	if (res)
258c2ecf20Sopenharmony_ci		printf("ERROR: USBDEVFS_DROP_PRIVILEGES returned %d\n", res);
268c2ecf20Sopenharmony_ci	else
278c2ecf20Sopenharmony_ci		printf("OK: privileges dropped!\n");
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_civoid reset_device(int fd)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	int res;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	res = ioctl(fd, USBDEVFS_RESET);
358c2ecf20Sopenharmony_ci	if (!res)
368c2ecf20Sopenharmony_ci		printf("OK: USBDEVFS_RESET succeeded\n");
378c2ecf20Sopenharmony_ci	else
388c2ecf20Sopenharmony_ci		printf("ERROR: reset failed! (%d - %s)\n",
398c2ecf20Sopenharmony_ci		       -res, strerror(-res));
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_civoid claim_some_intf(int fd)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	int i, res;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
478c2ecf20Sopenharmony_ci		res = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &i);
488c2ecf20Sopenharmony_ci		if (!res)
498c2ecf20Sopenharmony_ci			printf("OK: claimed if %d\n", i);
508c2ecf20Sopenharmony_ci		else
518c2ecf20Sopenharmony_ci			printf("ERROR claiming if %d (%d - %s)\n",
528c2ecf20Sopenharmony_ci			       i, -res, strerror(-res));
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	uint32_t mask, caps;
598c2ecf20Sopenharmony_ci	int c, fd;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	fd = open(argv[1], O_RDWR);
628c2ecf20Sopenharmony_ci	if (fd < 0) {
638c2ecf20Sopenharmony_ci		printf("Failed to open file\n");
648c2ecf20Sopenharmony_ci		goto err_fd;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/*
688c2ecf20Sopenharmony_ci	 * check if dropping privileges is supported,
698c2ecf20Sopenharmony_ci	 * bail on systems where the capability is not present
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci	ioctl(fd, USBDEVFS_GET_CAPABILITIES, &caps);
728c2ecf20Sopenharmony_ci	if (!(caps & USBDEVFS_CAP_DROP_PRIVILEGES)) {
738c2ecf20Sopenharmony_ci		printf("DROP_PRIVILEGES not supported\n");
748c2ecf20Sopenharmony_ci		goto err;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/*
788c2ecf20Sopenharmony_ci	 * Drop privileges but keep the ability to claim all
798c2ecf20Sopenharmony_ci	 * free interfaces (i.e., those not used by kernel drivers)
808c2ecf20Sopenharmony_ci	 */
818c2ecf20Sopenharmony_ci	drop_privileges(fd, -1U);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	printf("Available options:\n"
848c2ecf20Sopenharmony_ci		"[0] Exit now\n"
858c2ecf20Sopenharmony_ci		"[1] Reset device. Should fail if device is in use\n"
868c2ecf20Sopenharmony_ci		"[2] Claim 4 interfaces. Should succeed where not in use\n"
878c2ecf20Sopenharmony_ci		"[3] Narrow interface permission mask\n"
888c2ecf20Sopenharmony_ci		"Which option shall I run?: ");
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	while (scanf("%d", &c) == 1) {
918c2ecf20Sopenharmony_ci		switch (c) {
928c2ecf20Sopenharmony_ci		case 0:
938c2ecf20Sopenharmony_ci			goto exit;
948c2ecf20Sopenharmony_ci		case 1:
958c2ecf20Sopenharmony_ci			reset_device(fd);
968c2ecf20Sopenharmony_ci			break;
978c2ecf20Sopenharmony_ci		case 2:
988c2ecf20Sopenharmony_ci			claim_some_intf(fd);
998c2ecf20Sopenharmony_ci			break;
1008c2ecf20Sopenharmony_ci		case 3:
1018c2ecf20Sopenharmony_ci			printf("Insert new mask: ");
1028c2ecf20Sopenharmony_ci			scanf("%x", &mask);
1038c2ecf20Sopenharmony_ci			drop_privileges(fd, mask);
1048c2ecf20Sopenharmony_ci			break;
1058c2ecf20Sopenharmony_ci		default:
1068c2ecf20Sopenharmony_ci			printf("I don't recognize that\n");
1078c2ecf20Sopenharmony_ci		}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		printf("Which test shall I run next?: ");
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ciexit:
1138c2ecf20Sopenharmony_ci	close(fd);
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cierr:
1178c2ecf20Sopenharmony_ci	close(fd);
1188c2ecf20Sopenharmony_cierr_fd:
1198c2ecf20Sopenharmony_ci	return 1;
1208c2ecf20Sopenharmony_ci}
121