Imported Upstream version 3.2.2
[debian/gnuradio] / usrp2 / host / lib / usrp2_socket_opener.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008 Free Software Foundation, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /*!
20  * setuid root program that opens a socket using (PF_PACKET, SOCK_RAW,
21  * htons(0xBEEF)), and sends the resulting file descriptor by way of
22  * of the file descriptor specified as the first command line argument.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
38 #elif defined(HAVE_NETINET_IN_H)
39 #include <netinet/in.h>
40 #endif
41
42
43 ssize_t
44 write_fd(int fd, const void *ptr, size_t nbytes, int sendfd)
45 {
46   struct msghdr msg;
47   struct iovec iov[1];
48
49 #ifdef  HAVE_STRUCT_MSGHDR_MSG_CONTROL
50   union {
51     struct cmsghdr cm;
52     char    control[CMSG_SPACE(sizeof(int))];
53   } control_un;
54   struct cmsghdr *cmptr;
55
56   msg.msg_control = control_un.control;
57   msg.msg_controllen = sizeof(control_un.control);
58
59   cmptr = CMSG_FIRSTHDR(&msg);
60   cmptr->cmsg_len = CMSG_LEN(sizeof(int));
61   cmptr->cmsg_level = SOL_SOCKET;
62   cmptr->cmsg_type = SCM_RIGHTS;
63   *((int *) CMSG_DATA(cmptr)) = sendfd;
64 #else
65   msg.msg_accrights = (char *) &sendfd;
66   msg.msg_accrightslen = sizeof(int);
67 #endif
68
69   msg.msg_name = NULL;
70   msg.msg_namelen = 0;
71
72   iov[0].iov_base = const_cast<void *>(ptr);
73   iov[0].iov_len = nbytes;
74   msg.msg_iov = iov;
75   msg.msg_iovlen = 1;
76
77   return sendmsg(fd, &msg, 0);
78 }
79
80 bool
81 reset_eids()
82 {
83   if (setgid(getgid()) < 0){
84     perror("setguid");
85     return false;
86   }
87
88   if (setuid(getuid()) < 0){
89     perror("setuid");
90     return false;
91   }
92
93   return true;
94 }
95
96
97 static void
98 usage()
99 {
100   fprintf(stderr, "usage: usrp2_socket_opener file-descriptor\n");
101   exit(1);
102 }
103
104 int
105 main(int argc, char **argv)
106 {
107   if (argc != 2)
108     usage();
109
110   char *endptr;
111   int unix_domain_fd = strtol(argv[1], &endptr, 0);
112   if (*endptr != 0)
113     usage();
114
115   // FIXME get client credentials from unix_domain_fd using SCM_CREDENTIALS
116
117   // open the raw socket
118   int socket_fd = socket(PF_PACKET, SOCK_RAW, htons(0xBEEF));
119   if (socket_fd == -1){
120     perror("socket(PF_PACKET, SOCK_RAW, htons(0xBEEF))");
121     // printf("errno = %d\n", errno);
122     if (errno == EACCES || errno == ESPIPE){
123       fprintf(stderr, "usrp2_socket_opener must be setuid root to open the socket using SOCK_RAW.\n");
124       fprintf(stderr, "Running as root, please execute:  \n");
125       fprintf(stderr, "  # chown root:usrp usrp2_socket_opener\n");
126       fprintf(stderr, "  # chmod 04750 usrp2_socket_opener\n");
127     }
128     exit(2);
129   }
130
131   // drop privs
132   if (!reset_eids()){
133     fprintf(stderr, "Can't drop root permissions\n");
134     exit(3);
135   }
136
137   if (write_fd(unix_domain_fd, "", 1, socket_fd) != 1){
138     perror("write_fd");
139     exit(4);
140   }
141
142   return 0;
143 }