94420b27e1f8e70dae13c69e3af2e3b3f9503c2a
[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 #include <freeradius-devel/radpaths.h>
29
30 #ifdef HAVE_READLINE_READLINE_H
31 #include <readline/readline.h>
32 #include <readline/history.h>
33 #endif
34
35 /*
36  *      FIXME: configure checks.
37  */
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
41
42
43 static int fr_domain_socket(const char *path)
44 {
45         int sockfd;
46         size_t len;
47         socklen_t socklen;
48         struct sockaddr_un saremote;
49
50         len = strlen(path);
51         if (len >= sizeof(saremote.sun_path)) {
52                 fprintf(stderr, "Path too long in filename\n");
53                 return -1;
54         }
55
56         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
57                 fprintf(stderr, "Failed creating socket: %s\n",
58                         strerror(errno));
59                 return -1;
60         }
61
62         saremote.sun_family = AF_UNIX;
63         memcpy(saremote.sun_path, path, len); /* not zero terminated */
64         
65         socklen = sizeof(saremote.sun_family) + len;
66
67         if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
68                 fprintf(stderr, "Failed connecting to %s: %s\n",
69                         path, strerror(errno));
70                 close(sockfd);
71                 return -1;
72         }
73
74 #ifdef O_NONBLOCK
75         {
76                 int flags;
77                 
78                 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0)  {
79                         fprintf(stderr, "Failure getting socket flags: %s",
80                                 strerror(errno));
81                         close(sockfd);
82                         return -1;
83                 }
84                 
85                 flags |= O_NONBLOCK;
86                 if( fcntl(sockfd, F_SETFL, flags) < 0) {
87                         fprintf(stderr, "Failure setting socket flags: %s",
88                                 strerror(errno));
89                         close(sockfd);
90                         return -1;
91                 }
92         }
93 #endif
94
95         return sockfd;
96 }
97
98 int main(int argc, char **argv)
99 {
100         int sockfd, port;
101         char *line;
102         ssize_t len, size;
103         const char *file = RUNDIR "/radiusd/radiusd.sock";
104         char *p, buffer[2048];
105
106         if ((argc > 2) ||
107             ((argc == 2) && (strcmp(argv[1], "-h") == 0))) {
108                 printf("Usage: radmin [socket]\n");
109                 exit(0);
110         }
111
112         if (argc == 2) file = argv[1];
113
114 #ifdef HAVE_READLINE_READLINE_H
115         using_history();
116         rl_bind_key('\t', rl_insert);
117 #endif
118
119         /*
120          *      FIXME: Get destination from command line, if possible?
121          */
122         sockfd = fr_domain_socket(file);
123         if (sockfd < 0) {
124                 exit(1);
125         }
126
127         /*
128          *      FIXME: Do login?
129          */
130
131         while (1) {
132 #ifndef HAVE_READLINE_READLINE_H
133                 fprintf(stdout, "radmin> ");
134                 fflush(stdout);
135
136                 line = fgets(buffer, sizeof(buffer), stdin);
137                 if (!line) break;
138
139                 p = strchr(buffer, '\n');
140                 if (!p) {
141                         fprintf(stderr, "line too long\n");
142                         exit(1);
143                 }
144
145                 *p = '\0';
146 #else
147                 line = readline("radmin> ");
148
149                 if (!line) break;
150                 
151                 if (!*line) {
152                         free(line);
153                         continue;
154                 }
155
156                 add_history(line);
157 #endif
158
159                 /*
160                  *      Write the text to the socket.
161                  */
162                 if (write(sockfd, line, strlen(line)) < 0) break;
163                 if (write(sockfd, "\r\n", 2) < 0) break;
164
165                 /*
166                  *      Exit, done, etc.
167                  */
168                 if ((strcmp(line, "exit") == 0) ||
169                     (strcmp(line, "quit") == 0)) {
170                         break;
171                 }
172
173                 /*
174                  *      Read the response
175                  */
176                 size = 0;
177                 buffer[0] = '\0';
178
179                 port = 1;
180                 memset(buffer, 0, sizeof(buffer));
181
182                 while (port == 1) {
183                         len = recv(sockfd, buffer + size,
184                                    sizeof(buffer) - size - 1, MSG_DONTWAIT);
185                         if (len < 0) {
186                                 /*
187                                  *      No data: keep looping
188                                  */
189                                 if ((errno == EAGAIN) || (errno == EINTR)) {
190                                         continue;
191                                 }
192
193                                 fprintf(stderr, "Error reading socket: %s\n",
194                                         strerror(errno));
195                                 exit(1);
196                         }
197                         if (len == 0) break; /* clean close of socket */
198
199                         size += len;
200                         buffer[size] = '\0';
201
202                         /*
203                          *      There really has to be a better way of
204                          *      doing this.
205                          */
206                         p = strstr(buffer, "radmin> ");
207                         if (p &&
208                             ((p == buffer) || 
209                              (p[-1] == '\n') ||
210                              (p[-1] == '\r'))) {
211                                 *p = '\0';
212
213                                 if (p[-1] == '\n') p[-1] = '\0';
214
215                                 port = 0;
216                                 break;
217                         }
218                 }
219
220                 /*
221                  *      Blank prompt.  Go get another line.
222                  */
223                 if (!buffer[0]) continue;
224
225                 buffer[size] = '\0'; /* this is at least right */
226                 puts(buffer);
227                 fflush(stdout);
228         }
229
230         printf("\n");
231
232         return 0;
233 }
234