Skip to content

Commit c69cd03

Browse files
committed
clean up radmin
double check return paths, exit codes, messages, etc.
1 parent 01e16b8 commit c69cd03

1 file changed

Lines changed: 82 additions & 73 deletions

File tree

src/listen/control/radmin.c

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,22 @@ static NEVER_RETURNS void usage(int status)
193193
fprintf(output, " -l <log_file> Commands which are executed will be written to this file.\n");
194194
fprintf(output, " -n name Read ${confdir}/name.conf instead of ${confdir}/radiusd.conf\n");
195195
fprintf(output, " -q Reduce output verbosity\n");
196-
fprintf(output, " -s <server> Look in named server for name of control socket.\n");
196+
fprintf(output, " -s <server> When '-d' is specified, look in the named virtual server for\n");
197+
fprintf(output, " the control socket filename.\n");
198+
fprintf(output, " Otherwise start a TCP connection to the named server and port.\n");
197199
fprintf(output, " -S <secret> Use argument as shared secret for authentication to the server.\n");
200+
fprintf(output, " Note that local users may be able to read the secret via 'ps'!\n");
198201
fprintf(output, " -x Increase output verbosity\n");
199202
fr_exit_now(status);
200203
}
201204

205+
/*
206+
* Create the client socket.
207+
*
208+
* @todo - use the BIO code. But this means lots of changes to convert bare strings into the complex
209+
* data structures needed by the BIO code. That functionality properly belongs in a BIO FD helper
210+
* function.
211+
*/
202212
static int client_socket(char const *server)
203213
{
204214
int fd;
@@ -236,6 +246,7 @@ static ssize_t do_challenge(int fd)
236246
{
237247
ssize_t r;
238248
fr_conduit_type_t conduit;
249+
uint8_t hmac[16];
239250
uint8_t challenge[16];
240251

241252
challenge[0] = 0x00;
@@ -254,10 +265,10 @@ static ssize_t do_challenge(int fd)
254265

255266
if (!secret) return -1;
256267

257-
fr_hmac_md5(challenge, (uint8_t const *) secret, strlen(secret),
268+
fr_hmac_md5(hmac, (uint8_t const *) secret, strlen(secret),
258269
challenge, sizeof(challenge));
259270

260-
r = fr_conduit_write(fd, FR_CONDUIT_AUTH_RESPONSE, challenge, sizeof(challenge));
271+
r = fr_conduit_write(fd, FR_CONDUIT_AUTH_RESPONSE, hmac, sizeof(hmac));
261272
if (r <= 0) return r;
262273

263274
/*
@@ -295,7 +306,7 @@ static ssize_t flush_conduits(int fd, char *buffer, size_t bufsize)
295306
break;
296307

297308
case FR_CONDUIT_STDERR:
298-
fprintf(stderr, "ERROR: %s", buffer);
309+
fprintf(stderr, "ERROR: %s\n", buffer);
299310
break;
300311

301312
case FR_CONDUIT_CMD_STATUS:
@@ -680,6 +691,9 @@ radmin_completion(const char *text, int start, UNUSED int end)
680691
# define write_history(history_file)
681692
#endif
682693

694+
/*
695+
* See if there is a control socket in the given virtual server.
696+
*/
683697
static int check_server(CONF_SECTION *subcs, uid_t uid, gid_t gid, char const **file_p, char const **server_p)
684698
{
685699
int rcode;
@@ -869,7 +883,7 @@ int main(int argc, char **argv)
869883
char *commands[MAX_COMMANDS];
870884
int num_commands = 0;
871885

872-
int exit_status = EXIT_SUCCESS;
886+
int exit_status = EXIT_FAILURE;
873887

874888
char const *prompt = "radmin> ";
875889
char prompt_buffer[1024];
@@ -901,10 +915,6 @@ int main(int argc, char **argv)
901915

902916
while ((c = getopt(argc, argv, "d:D:hi:e:Ef:n:qs:S:x")) != -1) switch (c) {
903917
case 'd':
904-
if (file) {
905-
fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname);
906-
fr_exit_now(EXIT_FAILURE);
907-
}
908918
confdir = optarg;
909919
break;
910920

@@ -932,7 +942,7 @@ int main(int argc, char **argv)
932942

933943
default:
934944
case 'h':
935-
usage(0); /* never returns */
945+
usage(EXIT_SUCCESS); /* never returns */
936946

937947
case 'i':
938948
/*
@@ -956,10 +966,6 @@ int main(int argc, char **argv)
956966
break;
957967

958968
case 's':
959-
if (file) {
960-
fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname);
961-
usage(1);
962-
}
963969
server = optarg;
964970
break;
965971

@@ -996,41 +1002,31 @@ int main(int argc, char **argv)
9961002
* validation errors when we try and parse the config.
9971003
*/
9981004
if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
1005+
fail:
9991006
fr_perror("radmin");
1000-
fr_exit_now(64);
1007+
goto done;
10011008
}
10021009

1003-
if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
1004-
fr_perror("radmin");
1005-
fr_exit_now(64);
1006-
}
1010+
if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) goto fail;
10071011

1008-
if (fr_dict_autoload(radmin_dict) < 0) {
1009-
fr_perror("radmon");
1010-
fr_exit_now(64);
1011-
}
1012+
if (fr_dict_autoload(radmin_dict) < 0) goto fail;
10121013

1013-
if (fr_dict_attr_autoload(radmin_dict_attr) < 0) {
1014-
fr_perror("radmin");
1015-
fr_exit_now(64);
1016-
}
1014+
if (fr_dict_attr_autoload(radmin_dict_attr) < 0) goto fail;
10171015

1018-
if (fr_dict_read(dict, confdir, FR_DICTIONARY_FILE) == -1) {
1019-
fr_perror("radmin 2");
1020-
fr_exit_now(64);
1021-
}
1016+
if (fr_dict_read(dict, confdir, FR_DICTIONARY_FILE) == -1) goto fail;
10221017

10231018
cs = cf_section_alloc(autofree, NULL, "main", NULL);
1024-
if (!cs) fr_exit_now(EXIT_FAILURE);
1019+
if (!cs) goto fail;
10251020

10261021
if ((cf_file_read(cs, io_buffer, true) < 0) || (cf_section_pass2(cs) < 0)) {
1022+
fr_perror("radmin");
10271023
fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, io_buffer);
1028-
error:
1029-
fr_exit_now(EXIT_FAILURE);
1024+
goto done;
10301025
}
10311026

10321027
uid = getuid();
10331028
gid = getgid();
1029+
fr_strerror_clear();
10341030

10351031
/*
10361032
* We are looking for: server whatever { namespace="control" ... }
@@ -1039,28 +1035,33 @@ int main(int argc, char **argv)
10391035
subcs = cf_section_find(cs, "server", server);
10401036
if (!subcs) {
10411037
fprintf(stderr, "%s: Could not find virtual server %s {}\n", progname, server);
1042-
goto error;
1038+
goto done;
10431039
}
10441040

10451041
rcode = check_server(subcs, uid, gid, &file, &server);
1046-
if (rcode < 0) goto error;
1047-
if (rcode == 0) file = NULL;
1042+
if (rcode < 0) goto done;
1043+
if (rcode == 0) {
1044+
fprintf(stderr, "%s: Could not find control socket virtual server %s { ... }\n", progname, server);
1045+
goto done;
1046+
}
10481047

10491048
} else {
10501049
for (subcs = cf_section_find_next(cs, NULL, "server", CF_IDENT_ANY);
10511050
subcs != NULL;
10521051
subcs = cf_section_find_next(cs, subcs, "server", CF_IDENT_ANY)) {
10531052
rcode = check_server(subcs, uid, gid, &file, &server);
1054-
if (rcode < 0) goto error;
1053+
if (rcode < 0) goto done;
10551054
if (rcode == 1) break;
10561055
}
1057-
}
10581056

1059-
if (!file) {
1060-
fprintf(stderr, "%s: Could not find control socket in %s (server %s {})\n", progname, io_buffer, server);
1061-
goto error;
1057+
if (!file) {
1058+
fprintf(stderr, "%s: Could not find 'namespace = control' in any virtual server\n");
1059+
goto done;
1060+
}
10621061
}
10631062

1063+
fr_assert(file);
1064+
10641065
/*
10651066
* Log the commands we've run.
10661067
*/
@@ -1072,8 +1073,8 @@ int main(int argc, char **argv)
10721073
radmin_log.file = cf_pair_value(cp);
10731074

10741075
if (!radmin_log.file) {
1075-
fprintf(stderr, "%s: Invalid value for 'radmin' log destination", progname);
1076-
goto error;
1076+
fprintf(stderr, "%s: Invalid value for 'radmin' log destination\n", progname);
1077+
goto done;
10771078
}
10781079
}
10791080
}
@@ -1083,27 +1084,29 @@ int main(int argc, char **argv)
10831084
radmin_log.fd = open(radmin_log.file, O_APPEND | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
10841085
if (radmin_log.fd < 0) {
10851086
fprintf(stderr, "%s: Failed opening %s: %s\n", progname, radmin_log.file, fr_syserror(errno));
1086-
goto error;
1087+
goto done;
10871088
}
10881089

10891090
radmin_log.dst = L_DST_FILES;
10901091
}
1092+
1093+
} else if (!file) {
1094+
fprintf(stderr, "%s: No '-d <confdir' or '-f <socket_file>' specified.\n", progname);
1095+
goto done;
1096+
1097+
} else if (server) {
1098+
fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname);
1099+
usage(EXIT_FAILURE);
10911100
}
10921101

10931102
if (input_file) {
10941103
inputfp = fopen(input_file, "r");
10951104
if (!inputfp) {
10961105
fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, fr_syserror(errno));
1097-
goto error;
1106+
goto done;
10981107
}
10991108
}
11001109

1101-
if (!file) {
1102-
fprintf(stderr, "%s: Failed to find socket file name\n",
1103-
progname);
1104-
goto error;
1105-
}
1106-
11071110
/*
11081111
* Check if stdin is a TTY only if input is from stdin
11091112
*/
@@ -1135,15 +1138,15 @@ int main(int argc, char **argv)
11351138
*/
11361139
signal(SIGPIPE, SIG_IGN);
11371140

1138-
if (do_connect(&sockfd, file, server) < 0) fr_exit_now(EXIT_FAILURE);
1141+
if (do_connect(&sockfd, file, server) < 0) goto done;
11391142

11401143
/*
11411144
* Register local commands.
11421145
*/
11431146
if (fr_command_add_multi(autofree, &local_cmds, NULL, NULL, cmd_table) < 0) {
11441147
fprintf(stderr, "%s: Failed registering local commands: %s\n",
11451148
progname, fr_strerror());
1146-
goto error;
1149+
goto done;
11471150
}
11481151

11491152
fr_command_info_init(autofree, &local_info);
@@ -1156,12 +1159,9 @@ int main(int argc, char **argv)
11561159

11571160
for (i = 0; i < num_commands; i++) {
11581161
result = run_command(sockfd, commands[i], io_buffer, sizeof(io_buffer));
1159-
if (result < 0) fr_exit_now(EXIT_FAILURE);
1162+
if (result < 0) goto done;
11601163

1161-
if (result == FR_CONDUIT_FAIL) {
1162-
exit_status = EXIT_FAILURE;
1163-
goto exit;
1164-
}
1164+
if (result == FR_CONDUIT_FAIL) goto done;
11651165
}
11661166

11671167
if (unbuffered) {
@@ -1171,12 +1171,13 @@ int main(int argc, char **argv)
11711171
/*
11721172
* We're done all of the commands, exit now.
11731173
*/
1174-
goto exit;
1174+
exit_status = EXIT_SUCCESS;
1175+
goto done;
11751176
}
11761177

11771178
if (!quiet) {
11781179
printf("%s - FreeRADIUS Server administration tool.\n", radmin_version);
1179-
printf("Copyright 2008-2019 The FreeRADIUS server project and contributors.\n");
1180+
printf("Copyright 2008-2026 The FreeRADIUS server project and contributors.\n");
11801181
printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
11811182
printf("PARTICULAR PURPOSE.\n");
11821183
printf("You may redistribute copies of FreeRADIUS under the terms of the\n");
@@ -1211,7 +1212,7 @@ int main(int argc, char **argv)
12111212
if (strcmp(line, "reconnect") == 0) {
12121213
if (do_connect(&sockfd, file, server) < 0) {
12131214
radmin_free(line);
1214-
fr_exit_now(EXIT_FAILURE);
1215+
goto done;
12151216
}
12161217
goto next;
12171218
}
@@ -1220,13 +1221,17 @@ int main(int argc, char **argv)
12201221
secret = talloc_strdup(autofree, line + 7);
12211222
if (!secret) {
12221223
radmin_free(line);
1223-
fr_exit_now(EXIT_FAILURE);
1224+
goto done;
12241225
}
12251226

12261227
if (do_challenge(sockfd) < 0) {
12271228
radmin_free(line);
1228-
fr_exit_now(EXIT_FAILURE);
1229+
goto done;
12291230
}
1231+
1232+
/*
1233+
* Don't add the secret to the history.
1234+
*/
12301235
goto next;
12311236
}
12321237

@@ -1292,9 +1297,8 @@ int main(int argc, char **argv)
12921297

12931298
len = cmd_copy(line);
12941299
if (len < 0) {
1295-
exit_status = EXIT_FAILURE;
12961300
radmin_free(line);
1297-
break;
1301+
goto done;
12981302
}
12991303

13001304
retry:
@@ -1305,28 +1309,27 @@ int main(int argc, char **argv)
13051309

13061310
if (do_connect(&sockfd, file, server) < 0) {
13071311
radmin_free(line);
1308-
fr_exit_now(EXIT_FAILURE);
1312+
goto done;
13091313
}
13101314

13111315
retries++;
13121316
if (retries < 2) goto retry;
13131317

13141318
fprintf(stderr, "Failed to connect to server\n");
13151319
radmin_free(line);
1316-
fr_exit_now(EXIT_FAILURE);
1320+
goto done;
13171321

13181322
} else if (result == FR_CONDUIT_FAIL) {
13191323
fprintf(stderr, "Failed running command\n");
1320-
exit_status = EXIT_FAILURE;
1324+
goto done;
13211325

13221326
} else if (result == FR_CONDUIT_PARTIAL) {
13231327
char *p;
13241328

13251329
if (stack_depth >= (MAX_STACK - 1)) {
13261330
fprintf(stderr, "Too many sub-contexts running command\n");
1327-
exit_status = EXIT_FAILURE;
13281331
radmin_free(line);
1329-
break;
1332+
goto done;
13301333
}
13311334

13321335
/*
@@ -1359,8 +1362,14 @@ int main(int argc, char **argv)
13591362
next:
13601363
radmin_free(line);
13611364
}
1365+
exit_status = EXIT_SUCCESS;
1366+
1367+
done:
1368+
if (fr_dict_autofree(radmin_dict) < 0) {
1369+
fr_perror("radmin");
1370+
exit_status = EXIT_FAILURE;
1371+
}
13621372

1363-
exit:
13641373
fr_dict_free(&dict, __FILE__);
13651374

13661375
if (inputfp != stdin) fclose(inputfp);
@@ -1369,7 +1378,7 @@ int main(int argc, char **argv)
13691378

13701379
if (sockfd >= 0) close(sockfd);
13711380

1372-
if (!quiet) fprintf(stdout, "\n");
1381+
if (!quiet && (exit_status == EXIT_SUCCESS)) fprintf(stdout, "\n");
13731382

13741383
/*
13751384
* Ensure our atexit handlers run before any other

0 commit comments

Comments
 (0)