Add radmin tool.
[freeradius.git] / src / main / radmin.c
1 /*
2  * radmin.c     RADIUS Administration tool.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2008   The FreeRADIUS server project
21  * Copyright 2008   Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/libradius.h>
28
29 #ifdef HAVE_READLINE_READLINE_H
30 #include <readline/readline.h>
31 #include <readline/history.h>
32 #endif
33
34 /*
35  *      FIXME: configure checks.
36  */
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/un.h>
40
41
42 static int fr_domain_socket(const char *path)
43 {
44         int sockfd;
45         size_t len;
46         socklen_t socklen;
47         struct sockaddr_un saremote;
48
49         len = strlen(path);
50         if (len >= sizeof(saremote.sun_path)) {
51                 fprintf(stderr, "Path too long in filename\n");
52                 return -1;
53         }
54
55         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
56                 fprintf(stderr, "Failed creating socket: %s\n",
57                         strerror(errno));
58                 return -1;
59         }
60
61         saremote.sun_family = AF_UNIX;
62         memcpy(saremote.sun_path, path, len); /* not zero terminated */
63         
64         socklen = sizeof(saremote.sun_family) + len;
65
66         if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
67                 fprintf(stderr, "Failed connecting to %s: %s\n",
68                         path, strerror(errno));
69                 close(sockfd);
70                 return -1;
71         }
72
73 #ifdef O_NONBLOCK
74         {
75                 int flags;
76                 
77                 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0)  {
78                         fprintf(stderr, "Failure getting socket flags: %s",
79                                 strerror(errno));
80                         close(sockfd);
81                         return -1;
82                 }
83                 
84                 flags |= O_NONBLOCK;
85                 if( fcntl(sockfd, F_SETFL, flags) < 0) {
86                         fprintf(stderr, "Failure setting socket flags: %s",
87                                 strerror(errno));
88                         close(sockfd);
89                         return -1;
90                 }
91         }
92 #endif
93
94         return sockfd;
95 }
96
97 int main(int argc, char **argv)
98 {
99         int sockfd, port;
100         char *line;
101         ssize_t len, size;
102         char *p, buffer[2048];
103
104         if (argc == 1) {
105                 fprintf(stderr, "Figure it out, einstein.\n");
106                 exit(1);
107         }
108
109 #ifdef HAVE_READLINE_READLINE_H
110         using_history();
111         rl_bind_key('\t', rl_insert);
112 #endif
113
114         /*
115          *      FIXME: Get destination from command line, if possible?
116          */
117         sockfd = fr_domain_socket(argv[1]);
118         if (sockfd < 0) {
119                 exit(1);
120         }
121
122         /*
123          *      FIXME: Do login?
124          */
125
126         while (1) {
127 #ifndef HAVE_READLINE_READLINE_H
128                 fprintf(stdout, "radmin> ");
129                 fflush(stdout);
130
131                 line = fgets(buffer, sizeof(buffer), stdin);
132                 if (!line) break;
133
134                 p = strchr(buffer, '\n');
135                 if (!p) {
136                         fprintf(stderr, "line too long\n");
137                         exit(1);
138                 }
139
140                 *p = '\0';
141 #else
142                 line = readline("radmin> ");
143
144                 if (!line) break;
145                 
146                 if (!*line) {
147                         free(line);
148                         continue;
149                 }
150
151                 add_history(line);
152 #endif
153
154                 /*
155                  *      Write the text to the socket.
156                  */
157                 if (write(sockfd, line, strlen(line)) < 0) break;
158                 if (write(sockfd, "\r\n", 2) < 0) break;
159
160                 /*
161                  *      Exit, done, etc.
162                  */
163                 if ((strcmp(line, "exit") == 0) ||
164                     (strcmp(line, "quit") == 0)) {
165                         break;
166                 }
167
168                 /*
169                  *      Read the response
170                  */
171                 size = 0;
172                 buffer[0] = '\0';
173
174                 port = 1;
175                 memset(buffer, 0, sizeof(buffer));
176
177                 while (port == 1) {
178                         len = recv(sockfd, buffer + size,
179                                    sizeof(buffer) - size - 1, MSG_DONTWAIT);
180                         if (len < 0) {
181                                 /*
182                                  *      No data: keep looping
183                                  */
184                                 if ((errno == EAGAIN) || (errno == EINTR)) {
185                                         continue;
186                                 }
187
188                                 fprintf(stderr, "Error reading socket: %s\n",
189                                         strerror(errno));
190                                 exit(1);
191                         }
192                         if (len == 0) break; /* clean close of socket */
193
194                         size += len;
195                         buffer[size] = '\0';
196
197                         /*
198                          *      There really has to be a better way of
199                          *      doing this.
200                          */
201                         p = strstr(buffer, "radmin> ");
202                         if (p &&
203                             ((p == buffer) || 
204                              (p[-1] == '\n') ||
205                              (p[-1] == '\r'))) {
206                                 *p = '\0';
207
208                                 if (p[-1] == '\n') p[-1] = '\0';
209
210                                 port = 0;
211                                 break;
212                         }
213                 }
214
215                 /*
216                  *      Blank prompt.  Go get another line.
217                  */
218                 if (!buffer[0]) continue;
219
220                 buffer[size] = '\0'; /* this is at least right */
221                 puts(buffer);
222                 fflush(stdout);
223         }
224
225         printf("\n");
226
227         return 0;
228 }
229