-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add logger for usr.bin/mdo/mdo.c: a logger like sudo. #1512
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <syslog.h> | ||
#include <unistd.h> | ||
|
||
static void | ||
|
@@ -22,10 +23,29 @@ | |
exit(EXIT_FAILURE); | ||
} | ||
|
||
static char* | ||
join_strings(char **arr, int size, const char *delimiter) | ||
{ | ||
int total_length = 0, delimiter_length = strlen(delimiter); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are several branches in these loops, also I think it's a good idea to print the function name where it fails. Slightly changed static char *join_strings2(char **arr, int nlen, const char *delim)
{
char *buf;
size_t dlen, tlen, i;
tlen = 0;
dlen = strlen(delim);
for (i = 0; i < nlen; i++)
tlen += strlen(arr[i]) + dlen;
if ((buf = malloc(tlen)) == NULL)
err(1, "malloc()");
*buf = '\0';
strcpy(buf, arr[0]);
for (i = 1; i < nlen; i++) {
strcpy(buf + strlen(buf), delim);
strcpy(buf + strlen(buf), arr[i]);
}
return (buf);
} |
||
for (int i = 0; i < size; i++) | ||
total_length += strlen(arr[i]) + (i < size - 1 ? delimiter_length : 0); | ||
char *result = malloc(total_length + 1); | ||
if (!result) | ||
exit(1); | ||
result[0] = '\0'; | ||
for (int i = 0; i < size; i++) { | ||
strcat(result, arr[i]); | ||
if (i < size - 1) | ||
strcat(result, delimiter); | ||
} | ||
return (result); | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
struct passwd *pw; | ||
struct passwd *pw = getpwuid(getuid()); | ||
char original_username[33]; | ||
const char *username = "root"; | ||
bool uidonly = false; | ||
int ch; | ||
|
@@ -45,32 +65,61 @@ | |
argc -= optind; | ||
argv += optind; | ||
|
||
openlog("mdo", LOG_PID | LOG_CONS, LOG_USER); | ||
strcpy(original_username, pw->pw_name); | ||
|
||
if ((pw = getpwnam(username)) == NULL) { | ||
if (strspn(username, "0123456789") == strlen(username)) { | ||
const char *errp = NULL; | ||
uid_t uid = strtonum(username, 0, UID_MAX, &errp); | ||
if (errp != NULL) | ||
|
||
if (errp != NULL) { | ||
syslog(LOG_ERR, "Failed due to: %s", errp); | ||
err(EXIT_FAILURE, "%s", errp); | ||
} | ||
pw = getpwuid(uid); | ||
} | ||
if (pw == NULL) | ||
if (pw == NULL) { | ||
syslog(LOG_AUTH | LOG_WARNING, "invalid username: %s", username); | ||
err(EXIT_FAILURE, "invalid username '%s'", username); | ||
} | ||
} | ||
|
||
if (!uidonly) { | ||
if (initgroups(pw->pw_name, pw->pw_gid) == -1) | ||
if (initgroups(pw->pw_name, pw->pw_gid) == -1) { | ||
syslog(LOG_AUTH | LOG_ERR, "USER: %s; failed to call initgroups: %d", | ||
original_username, | ||
EXIT_FAILURE); | ||
err(EXIT_FAILURE, "failed to call initgroups"); | ||
if (setgid(pw->pw_gid) == -1) | ||
} | ||
if (setgid(pw->pw_gid) == -1) { | ||
syslog(LOG_AUTH | LOG_ERR, "USER: %s; failed to call setgid: %d", | ||
original_username, | ||
EXIT_FAILURE); | ||
err(EXIT_FAILURE, "failed to call setgid"); | ||
} | ||
} | ||
if (setuid(pw->pw_uid) == -1) | ||
if (setuid(pw->pw_uid) == -1) { | ||
syslog(LOG_AUTH | LOG_ERR, "USER: %s; failed to call setuid: %d", | ||
original_username, | ||
EXIT_FAILURE); | ||
err(EXIT_FAILURE, "failed to call setuid"); | ||
} | ||
if (*argv == NULL) { | ||
const char *sh = getenv("SHELL"); | ||
if (sh == NULL) | ||
sh = _PATH_BSHELL; | ||
syslog(LOG_AUTH | LOG_INFO, | ||
"USER: %s; COMMAND=%s", | ||
original_username, sh); | ||
execlp(sh, sh, "-i", NULL); | ||
} else { | ||
char *command = join_strings(argv, argc, " "); | ||
syslog(LOG_AUTH | LOG_INFO, "USER: %s; COMMAND=%s", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, previous comment was lost. Note that allocating buffer in the function and returning is more prone to memory leaks, although for this particular use case it is Okay because we are calling Additionally you might want to use
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the memory block of new generated command string is allocated by malloc, maybe I could just free the memory block after logging just like this? As for using sbuf, I believe if we can guarantee that the What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the VM space is going to be discarded anyway soon (with a successful
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. open_memstream(3) can also be used instead of sbuf(9) |
||
original_username, | ||
command); | ||
free(command); | ||
execvp(argv[0], argv); | ||
} | ||
err(EXIT_FAILURE, "exec failed"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function is only used once, it can be folded into
main()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the separation would make the code easier to read and without loss the original code logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really have strong opinion here, it's more of a personal preference.
However, this approach also matches existing patterns of other similar situations: from readability point of view, while separating a more complex function is generally helpful (e.g. this program would do some complicated operations A, B, and C in order, and these operations are implemented as separate functions), it can actually hurt readability to overly wrap simple operations. My personal rule of thumb is to not extract an operation into a function if a) it's only used once, and b) the function itself plus the caller's code block would fit one page or screen (about 20-25 lines) worth of code block.
Note that there are other similar situations where it's done in place instead of in a separate function, for example in
apply(1)
andnewsyslog(8)
.