From: Arran Cudbard-Bell Date: Tue, 27 Apr 2021 17:23:58 +0000 (-0500) Subject: Move user/group/permissions functions into util library X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9b46ded5b4349454230e08a7ace2a9788119c1e;p=thirdparty%2Ffreeradius-server.git Move user/group/permissions functions into util library --- diff --git a/src/lib/server/cf_file.c b/src/lib/server/cf_file.c index 176e6d2c5d5..7a05229af30 100644 --- a/src/lib/server/cf_file.c +++ b/src/lib/server/cf_file.c @@ -38,6 +38,7 @@ RCSID("$Id$") #include #include #include +#include #include #include @@ -623,7 +624,7 @@ bool cf_file_check(CONF_SECTION *cs, char const *filename, bool check_perms) if (!check_perms) { if (stat(filename, &file->buf) < 0) { perm_error: - rad_file_error(errno); /* Write error and euid/egid to error buff */ + fr_perm_file_error(errno); /* Write error and euid/egid to error buff */ PERROR("Unable to open file \"%s\"", filename); error: if (fd >= 0) close(fd); diff --git a/src/lib/server/exfile.c b/src/lib/server/exfile.c index 7c6668fe279..901589ce48f 100644 --- a/src/lib/server/exfile.c +++ b/src/lib/server/exfile.c @@ -23,12 +23,14 @@ * @author Alan DeKok (aland@freeradius.org) * @copyright 2014 The FreeRADIUS server project */ +#include #include -#include #include -#include +#include #include +#include +#include #include #include @@ -476,19 +478,19 @@ try_lock: char str_need[10], oct_need[5]; char str_have[10], oct_have[5]; - rad_mode_to_oct(oct_need, permissions); - rad_mode_to_str(str_need, permissions); + fr_perm_mode_to_oct(oct_need, permissions); + fr_perm_mode_to_str(str_need, permissions); - rad_mode_to_oct(oct_have, st.st_mode & ~S_IFMT); - rad_mode_to_str(str_have, st.st_mode & ~S_IFMT); + fr_perm_mode_to_oct(oct_have, st.st_mode & ~S_IFMT); + fr_perm_mode_to_str(str_have, st.st_mode & ~S_IFMT); WARN("File %s permissions are %s (%s) not %s (%s))", filename, oct_have, str_have, oct_need, str_need); if (((st.st_mode | permissions) != st.st_mode) && (fchmod(ef->entries[i].fd, (st.st_mode & ~S_IFMT) | permissions) < 0)) { - rad_mode_to_oct(oct_need, (st.st_mode & ~S_IFMT) | permissions); - rad_mode_to_str(str_need, (st.st_mode & ~S_IFMT) | permissions); + fr_perm_mode_to_oct(oct_need, (st.st_mode & ~S_IFMT) | permissions); + fr_perm_mode_to_str(str_need, (st.st_mode & ~S_IFMT) | permissions); WARN("Failed resetting file %s permissions to %s (%s): %s", filename, oct_need, str_need, fr_syserror(errno)); diff --git a/src/lib/server/main_config.c b/src/lib/server/main_config.c index 85e899476ad..198dd0c1488 100644 --- a/src/lib/server/main_config.c +++ b/src/lib/server/main_config.c @@ -40,6 +40,7 @@ RCSID("$Id$") #include #include #include +#include #include #include @@ -372,7 +373,7 @@ static int uid_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, uid_name = cf_pair_value(cf_item_to_pair(ci)); - if (rad_getpwnam(ctx, &user, uid_name) < 0) { + if (fr_perm_getpwnam(ctx, &user, uid_name) < 0) { cf_log_perr(ci, "Cannot get passwd entry for user \"%s\"", uid_name); return 0; } @@ -392,7 +393,7 @@ static int gid_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, gid_name = cf_pair_value(cf_item_to_pair(ci)); - if (rad_getgrnam(ctx, &group, gid_name) < 0) { + if (fr_perm_getgrnam(ctx, &group, gid_name) < 0) { cf_log_perr(ci, "Cannot resolve group name \"%s\"", gid_name); return 0; } @@ -629,7 +630,7 @@ static int switch_users(main_config_t *config, CONF_SECTION *cs) { struct passwd *user; - if (rad_getpwuid(config, &user, config->uid) < 0) { + if (fr_perm_getpwuid(config, &user, config->uid) < 0) { fprintf(stderr, "%s: Failed resolving UID %i: %s\n", config->name, (int)config->uid, fr_syserror(errno)); return -1; @@ -690,7 +691,7 @@ static int switch_users(main_config_t *config, CONF_SECTION *cs) if (setgid(config->server_gid) < 0) { struct group *group; - if (rad_getgrgid(config, &group, config->gid) < 0) { + if (fr_perm_getgrgid(config, &group, config->gid) < 0) { fprintf(stderr, "%s: Failed resolving GID %i: %s\n", config->name, (int)config->gid, fr_syserror(errno)); return -1; diff --git a/src/lib/server/util.c b/src/lib/server/util.c index e494976c549..84354e9ef5f 100644 --- a/src/lib/server/util.c +++ b/src/lib/server/util.c @@ -22,7 +22,6 @@ RCSID("$Id$") - #include #include #include @@ -30,6 +29,7 @@ RCSID("$Id$") #include #include #include +#include #include #include @@ -679,371 +679,6 @@ int rad_expand_xlat(request_t *request, char const *cmd, return argc; } -/** Convert mode_t into humanly readable permissions flags - * - * @author Jonathan Leffler. - * - * @param mode to convert. - * @param out Where to write the string to, must be exactly 10 bytes long. - */ -void rad_mode_to_str(char out[static 10], mode_t mode) -{ - static char const *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; - - strcpy(&out[0], rwx[(mode >> 6) & 0x07]); - strcpy(&out[3], rwx[(mode >> 3) & 0x07]); - strcpy(&out[6], rwx[(mode & 7)]); - if (mode & S_ISUID) out[2] = (mode & 0100) ? 's' : 'S'; - if (mode & S_ISGID) out[5] = (mode & 0010) ? 's' : 'l'; - if (mode & S_ISVTX) out[8] = (mode & 0100) ? 't' : 'T'; - out[9] = '\0'; -} - -void rad_mode_to_oct(char out[static 5], mode_t mode) -{ - out[0] = '0' + ((mode >> 9) & 0x07); - out[1] = '0' + ((mode >> 6) & 0x07); - out[2] = '0' + ((mode >> 3) & 0x07); - out[3] = '0' + (mode & 0x07); - out[4] = '\0'; -} - -/** Resolve a uid to a passwd entry - * - * Resolves a uid to a passwd entry. The memory to hold the - * passwd entry is talloced under ctx, and must be freed when no - * longer required. - * - * @param ctx to allocate passwd entry in. - * @param out Where to write pointer to entry. - * @param uid to resolve. - * @return - * - 0 on success. - * - -1 on failure. - */ -int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid) -{ - static size_t len; - uint8_t *buff; - int ret; - - *out = NULL; - - /* - * We assume this won't change between calls, - * and that the value is the same, so races don't - * matter. - */ - if (len == 0) { -#ifdef _SC_GETPW_R_SIZE_MAX - long int sc_len; - - sc_len = sysconf(_SC_GETPW_R_SIZE_MAX); - if (sc_len <= 0) sc_len = 1024; - len = (size_t)sc_len; -#else - len = 1024; -#endif - } - - buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len); - if (!buff) return -1; - - /* - * In some cases we may need to dynamically - * grow the string buffer. - */ - while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)), - talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) { - MEM(buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2)); - } - - if ((ret != 0) || !*out) { - fr_strerror_printf("%s", (errno != 0) ? fr_syserror(ret) : "Non-existent user"); - talloc_free(buff); - errno = ret; - return -1; - } - - talloc_set_type(buff, struct passwd); - *out = (struct passwd *)buff; - - return 0; -} - -/** Resolve a username to a passwd entry - * - * Resolves a username to a passwd entry. The memory to hold the - * passwd entry is talloced under ctx, and must be freed when no - * longer required. - * - * @param ctx to allocate passwd entry in. - * @param out Where to write pointer to entry. - * @param name to resolve. - * @return - * - 0 on success. - * - -1 on failure. - */ -int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name) -{ - static size_t len; - uint8_t *buff; - int ret; - - *out = NULL; - - /* - * We assume this won't change between calls, - * and that the value is the same, so races don't - * matter. - */ - if (len == 0) { -#ifdef _SC_GETPW_R_SIZE_MAX - long int sc_len; - - sc_len = sysconf(_SC_GETPW_R_SIZE_MAX); - if (sc_len <= 0) sc_len = 1024; - len = (size_t)sc_len; -#else - sc_len = 1024; -#endif - } - - buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len); - if (!buff) return -1; - - /* - * In some cases we may need to dynamically - * grow the string buffer. - */ - while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)), - talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) { - MEM(buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2)); - } - - if ((ret != 0) || !*out) { - fr_strerror_printf("%s", (errno != 0) ? fr_syserror(ret) : "Non-existent user"); - talloc_free(buff); - errno = ret; - return -1; - } - - talloc_set_type(buff, struct passwd); - *out = (struct passwd *)buff; - - return 0; -} - -/** Resolve a gid to a group database entry - * - * Resolves a gid to a group database entry. The memory to hold the - * group entry is talloced under ctx, and must be freed when no - * longer required. - * - * @param ctx to allocate passwd entry in. - * @param out Where to write pointer to entry. - * @param gid to resolve. - * @return - * - 0 on success. - * - -1 on failure. - */ -int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid) -{ - static size_t len; - uint8_t *buff; - int ret; - - *out = NULL; - - /* - * We assume this won't change between calls, - * and that the value is the same, so races don't - * matter. - */ - if (len == 0) { -#ifdef _SC_GETGR_R_SIZE_MAX - long int sc_len; - - sc_len = sysconf(_SC_GETGR_R_SIZE_MAX); - if (sc_len <= 0) sc_len = 1024; - len = (size_t)sc_len; -#else - sc_len = 1024; -#endif - } - - buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len); - if (!buff) return -1; - - /* - * In some cases we may need to dynamically - * grow the string buffer. - */ - while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)), - talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) { - MEM(buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2)); - } - - if ((ret != 0) || !*out) { - fr_strerror_printf("%s", (ret != 0) ? fr_syserror(ret) : "Non-existent group"); - talloc_free(buff); - errno = ret; - return -1; - } - - talloc_set_type(buff, struct group); - *out = (struct group *)buff; - - return 0; -} - -/** Resolve a group name to a group database entry - * - * Resolves a group name to a group database entry. - * The memory to hold the group entry is talloced under ctx, - * and must be freed when no longer required. - * - * @param ctx to allocate passwd entry in. - * @param out Where to write pointer to entry. - * @param name to resolve. - * @return - * - 0 on success. - * - -1 on failure. - */ -int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name) -{ - static size_t len; - uint8_t *buff; - int ret; - - *out = NULL; - - /* - * We assume this won't change between calls, - * and that the value is the same, so races don't - * matter. - */ - if (len == 0) { -#ifdef _SC_GETGR_R_SIZE_MAX - long int sc_len; - - sc_len = sysconf(_SC_GETGR_R_SIZE_MAX); - if (sc_len <= 0) sc_len = 1024; - len = (size_t)sc_len; -#else - len = 1024; -#endif - } - - buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len); - if (!buff) return -1; - - /* - * In some cases we may need to dynamically - * grow the string buffer. - */ - while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)), - talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) { - MEM(buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2)); - } - - if ((ret != 0) || !*out) { - fr_strerror_printf("%s", (ret != 0) ? fr_syserror(ret) : "Non-existent group"); - talloc_free(buff); - errno = ret; - return -1; - } - - talloc_set_type(buff, struct group); - *out = (struct group *)buff; - - return 0; -} - -/** Resolve a group name to a GID - * - * @param ctx TALLOC_CTX for temporary allocations. - * @param name of group. - * @param out where to write gid. - * @return - * - 0 on success. - * - -1 on failure. - */ -int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name) -{ - int ret; - struct group *result; - - ret = rad_getgrnam(ctx, &result, name); - if (ret < 0) return -1; - - *out = result->gr_gid; - talloc_free(result); - return 0; -} - -/** Print uid to a string - * - * @param ctx TALLOC_CTX for temporary allocations. - * @param uid to resolve. - * @return - * - 0 on success. - * - -1 on failure. - */ -char *rad_asprint_uid(TALLOC_CTX *ctx, uid_t uid) -{ - struct passwd *result; - char *out; - - if (rad_getpwuid(ctx, &result, uid) < 0) return NULL; - out = talloc_typed_strdup(ctx, result->pw_name); - talloc_free(result); - - return out; -} - -/** Print gid to a string - * - * @param ctx TALLOC_CTX for temporary allocations. - * @param gid to resolve. - * @return - * - 0 on success. - * - -1 on failure. - */ -char *rad_asprint_gid(TALLOC_CTX *ctx, uid_t gid){ - struct group *result; - char *out; - - if (rad_getgrgid(ctx, &result, gid) < 0) return NULL; - out = talloc_typed_strdup(ctx, result->gr_name); - talloc_free(result); - - return out; -} - -/** Write a file access error to the fr_strerror buffer, including euid/egid - * - * @note retrieve error with fr_strerror() - * - * @param num Usually errno, unless the error is returned by the function. - */ -void rad_file_error(int num) -{ - char const *error; - struct passwd *user = NULL; - struct group *group = NULL; - - error = fr_syserror(num); - - if (rad_getpwuid(NULL, &user, geteuid()) < 0) goto finish; - if (rad_getgrgid(NULL, &group, getegid()) < 0) goto finish; - - fr_strerror_printf("Effective user/group - %s:%s: %s", user->pw_name, group->gr_name, error); -finish: - talloc_free(user); - talloc_free(group); -} - #ifdef HAVE_SETUID static bool doing_setuid = false; static uid_t suid_down_uid = (uid_t)-1; @@ -1089,7 +724,7 @@ void rad_suid_down(void) struct passwd *passwd; char const *name; - name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name; + name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name; ERROR("Failed switching to uid %s: %s", name, fr_syserror(errno)); talloc_free(passwd); fr_exit_now(EXIT_FAILURE); @@ -1111,7 +746,7 @@ void rad_suid_down_permanent(void) struct passwd *passwd; char const *name; - name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name; + name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name; ERROR("Failed in permanent switch to uid %s: %s", name, fr_syserror(errno)); talloc_free(passwd); fr_exit_now(EXIT_FAILURE); @@ -1151,7 +786,7 @@ void rad_suid_down(void) struct passwd *passwd; char const *name; - name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name; + name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name; ERROR("Failed switching to euid %s: %s", name, fr_syserror(errno)); talloc_free(passwd); fr_exit_now(EXIT_FAILURE); @@ -1181,7 +816,7 @@ void rad_suid_down_permanent(void) struct passwd *passwd; char const *name; - name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name; + name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name; ERROR("Failed switching permanently to uid %s: %s", name, fr_syserror(errno)); talloc_free(passwd); fr_exit_now(EXIT_FAILURE); @@ -1233,10 +868,10 @@ bool rad_suid_is_down_permanent(void) int rad_seuid(uid_t uid) { if (seteuid(uid) < 0) { - int sete_errno = errno; /* errno sets overwritten by rad_getpwuid */ + int sete_errno = errno; /* errno sets overwritten by fr_perm_getpwuid */ struct passwd *passwd; - if (rad_getpwuid(NULL, &passwd, uid) < 0) return -1; + if (fr_perm_getpwuid(NULL, &passwd, uid) < 0) return -1; fr_strerror_printf("%s", fr_syserror(sete_errno)); talloc_free(passwd); @@ -1255,10 +890,10 @@ int rad_seuid(uid_t uid) int rad_segid(gid_t gid) { if (setegid(gid) < 0) { - int sete_errno = errno; /* errno sets overwritten by rad_getgrgid */ + int sete_errno = errno; /* errno sets overwritten by fr_perm_getgrgid */ struct group *group; - if (rad_getgrgid(NULL, &group, gid) < 0) return -1; + if (fr_perm_getgrgid(NULL, &group, gid) < 0) return -1; fr_strerror_printf("%s", fr_syserror(sete_errno)); talloc_free(group); diff --git a/src/lib/server/util.h b/src/lib/server/util.h index ae4bb0512a5..565775a335c 100644 --- a/src/lib/server/util.h +++ b/src/lib/server/util.h @@ -46,16 +46,6 @@ int rad_expand_xlat(request_t *request, char const *cmd, int max_argc, char const *argv[], bool can_fail, size_t argv_buflen, char *argv_buf); -void rad_mode_to_str(char out[static 10], mode_t mode); -void rad_mode_to_oct(char out[static 5], mode_t mode); -int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid); -int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name); -int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid); -int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name); -int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name); -char *rad_asprint_uid(TALLOC_CTX *ctx, uid_t uid); -char *rad_asprint_gid(TALLOC_CTX *ctx, gid_t gid); -void rad_file_error(int num); int rad_seuid(uid_t uid); int rad_segid(gid_t gid); diff --git a/src/lib/util/libfreeradius-util.mk b/src/lib/util/libfreeradius-util.mk index e3a68404223..f413d4c324c 100644 --- a/src/lib/util/libfreeradius-util.mk +++ b/src/lib/util/libfreeradius-util.mk @@ -52,6 +52,7 @@ SOURCES := \ pair_tokenize.c \ paths.c \ pcap.c \ + perm.c \ print.c \ proto.c \ rand.c \ diff --git a/src/lib/util/perm.c b/src/lib/util/perm.c new file mode 100644 index 00000000000..4f5572bbacc --- /dev/null +++ b/src/lib/util/perm.c @@ -0,0 +1,392 @@ +/* + * This program is is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** Implementation of filed semaphores that release on exit + * + * @file src/lib/util/perm.c + * + * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSID("$Id$") + +#include +#include +#include + +/** Convert mode_t into humanly readable permissions flags + * + * @author Jonathan Leffler. + * + * @param mode to convert. + * @param out Where to write the string to, must be exactly 10 bytes long. + */ +void fr_perm_mode_to_str(char out[static 10], mode_t mode) +{ + static char const *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; + + strcpy(&out[0], rwx[(mode >> 6) & 0x07]); + strcpy(&out[3], rwx[(mode >> 3) & 0x07]); + strcpy(&out[6], rwx[(mode & 7)]); + if (mode & S_ISUID) out[2] = (mode & 0100) ? 's' : 'S'; + if (mode & S_ISGID) out[5] = (mode & 0010) ? 's' : 'l'; + if (mode & S_ISVTX) out[8] = (mode & 0100) ? 't' : 'T'; + out[9] = '\0'; +} + +void fr_perm_mode_to_oct(char out[static 5], mode_t mode) +{ + out[0] = '0' + ((mode >> 9) & 0x07); + out[1] = '0' + ((mode >> 6) & 0x07); + out[2] = '0' + ((mode >> 3) & 0x07); + out[3] = '0' + (mode & 0x07); + out[4] = '\0'; +} + +/** Resolve a uid to a passwd entry + * + * Resolves a uid to a passwd entry. The memory to hold the + * passwd entry is talloced under ctx, and must be freed when no + * longer required. + * + * @param ctx to allocate passwd entry in. + * @param out Where to write pointer to entry. + * @param uid to resolve. + * @return + * - 0 on success. + * - -1 on failure. + */ +int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid) +{ + static size_t len; + uint8_t *buff; + int ret; + + *out = NULL; + + /* + * We assume this won't change between calls, + * and that the value is the same, so races don't + * matter. + */ + if (len == 0) { +#ifdef _SC_GETPW_R_SIZE_MAX + long int sc_len; + + sc_len = sysconf(_SC_GETPW_R_SIZE_MAX); + if (sc_len <= 0) sc_len = 1024; + len = (size_t)sc_len; +#else + len = 1024; +#endif + } + + buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len); + if (!buff) return -1; + + /* + * In some cases we may need to dynamically + * grow the string buffer. + */ + while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)), + talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) { + buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2); + } + + if ((ret != 0) || !*out) { + fr_strerror_printf("%s", (errno != 0) ? fr_syserror(ret) : "Non-existent user"); + talloc_free(buff); + errno = ret; + return -1; + } + + talloc_set_type(buff, struct passwd); + *out = (struct passwd *)buff; + + return 0; +} + +/** Resolve a username to a passwd entry + * + * Resolves a username to a passwd entry. The memory to hold the + * passwd entry is talloced under ctx, and must be freed when no + * longer required. + * + * @param ctx to allocate passwd entry in. + * @param out Where to write pointer to entry. + * @param name to resolve. + * @return + * - 0 on success. + * - -1 on failure. + */ +int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name) +{ + static size_t len; + uint8_t *buff; + int ret; + + *out = NULL; + + /* + * We assume this won't change between calls, + * and that the value is the same, so races don't + * matter. + */ + if (len == 0) { +#ifdef _SC_GETPW_R_SIZE_MAX + long int sc_len; + + sc_len = sysconf(_SC_GETPW_R_SIZE_MAX); + if (sc_len <= 0) sc_len = 1024; + len = (size_t)sc_len; +#else + sc_len = 1024; +#endif + } + + buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len); + if (!buff) return -1; + + /* + * In some cases we may need to dynamically + * grow the string buffer. + */ + while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)), + talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) { + buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2); + } + + if ((ret != 0) || !*out) { + fr_strerror_printf("%s", (errno != 0) ? fr_syserror(ret) : "Non-existent user"); + talloc_free(buff); + errno = ret; + return -1; + } + + talloc_set_type(buff, struct passwd); + *out = (struct passwd *)buff; + + return 0; +} + +/** Resolve a gid to a group database entry + * + * Resolves a gid to a group database entry. The memory to hold the + * group entry is talloced under ctx, and must be freed when no + * longer required. + * + * @param ctx to allocate passwd entry in. + * @param out Where to write pointer to entry. + * @param gid to resolve. + * @return + * - 0 on success. + * - -1 on failure. + */ +int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid) +{ + static size_t len; + uint8_t *buff; + int ret; + + *out = NULL; + + /* + * We assume this won't change between calls, + * and that the value is the same, so races don't + * matter. + */ + if (len == 0) { +#ifdef _SC_GETGR_R_SIZE_MAX + long int sc_len; + + sc_len = sysconf(_SC_GETGR_R_SIZE_MAX); + if (sc_len <= 0) sc_len = 1024; + len = (size_t)sc_len; +#else + sc_len = 1024; +#endif + } + + buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len); + if (!buff) return -1; + + /* + * In some cases we may need to dynamically + * grow the string buffer. + */ + while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)), + talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) { + buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2); + } + + if ((ret != 0) || !*out) { + fr_strerror_printf("%s", (ret != 0) ? fr_syserror(ret) : "Non-existent group"); + talloc_free(buff); + errno = ret; + return -1; + } + + talloc_set_type(buff, struct group); + *out = (struct group *)buff; + + return 0; +} + +/** Resolve a group name to a group database entry + * + * Resolves a group name to a group database entry. + * The memory to hold the group entry is talloced under ctx, + * and must be freed when no longer required. + * + * @param ctx to allocate passwd entry in. + * @param out Where to write pointer to entry. + * @param name to resolve. + * @return + * - 0 on success. + * - -1 on failure. + */ +int fr_perm_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name) +{ + static size_t len; + uint8_t *buff; + int ret; + + *out = NULL; + + /* + * We assume this won't change between calls, + * and that the value is the same, so races don't + * matter. + */ + if (len == 0) { +#ifdef _SC_GETGR_R_SIZE_MAX + long int sc_len; + + sc_len = sysconf(_SC_GETGR_R_SIZE_MAX); + if (sc_len <= 0) sc_len = 1024; + len = (size_t)sc_len; +#else + len = 1024; +#endif + } + + buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len); + if (!buff) return -1; + + /* + * In some cases we may need to dynamically + * grow the string buffer. + */ + while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)), + talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) { + buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2); + } + + if ((ret != 0) || !*out) { + fr_strerror_printf("%s", (ret != 0) ? fr_syserror(ret) : "Non-existent group"); + talloc_free(buff); + errno = ret; + return -1; + } + + talloc_set_type(buff, struct group); + *out = (struct group *)buff; + + return 0; +} + +/** Resolve a group name to a GID + * + * @param ctx TALLOC_CTX for temporary allocations. + * @param name of group. + * @param out where to write gid. + * @return + * - 0 on success. + * - -1 on failure. + */ +int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name) +{ + int ret; + struct group *result; + + ret = fr_perm_getgrnam(ctx, &result, name); + if (ret < 0) return -1; + + *out = result->gr_gid; + talloc_free(result); + return 0; +} + +/** Print uid to a string + * + * @param ctx TALLOC_CTX for temporary allocations. + * @param uid to resolve. + * @return + * - 0 on success. + * - -1 on failure. + */ +char *fr_perm_uid_to_str(TALLOC_CTX *ctx, uid_t uid) +{ + struct passwd *result; + char *out; + + if (fr_perm_getpwuid(ctx, &result, uid) < 0) return NULL; + out = talloc_typed_strdup(ctx, result->pw_name); + talloc_free(result); + + return out; +} + +/** Print gid to a string + * + * @param ctx TALLOC_CTX for temporary allocations. + * @param gid to resolve. + * @return + * - 0 on success. + * - -1 on failure. + */ +char *fr_perm_gid_to_str(TALLOC_CTX *ctx, uid_t gid){ + struct group *result; + char *out; + + if (fr_perm_getgrgid(ctx, &result, gid) < 0) return NULL; + out = talloc_typed_strdup(ctx, result->gr_name); + talloc_free(result); + + return out; +} + +/** Write a file access error to the fr_strerror buffer, including euid/egid + * + * @note retrieve error with fr_strerror() + * + * @param num Usually errno, unless the error is returned by the function. + */ +void fr_perm_file_error(int num) +{ + char const *error; + struct passwd *user = NULL; + struct group *group = NULL; + + error = fr_syserror(num); + + if (fr_perm_getpwuid(NULL, &user, geteuid()) < 0) goto finish; + if (fr_perm_getgrgid(NULL, &group, getegid()) < 0) goto finish; + + fr_strerror_printf("Effective user/group - %s:%s: %s", user->pw_name, group->gr_name, error); +finish: + talloc_free(user); + talloc_free(group); +} diff --git a/src/lib/util/perm.h b/src/lib/util/perm.h new file mode 100644 index 00000000000..f72b57d09c8 --- /dev/null +++ b/src/lib/util/perm.h @@ -0,0 +1,50 @@ +#pragma once +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** Functions to produce and parse the FreeRADIUS presentation format + * + * @file src/lib/util/perm.h + * + * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSIDH(perm_h, "$Id$") + +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void fr_perm_mode_to_str(char out[static 10], mode_t mode); +void fr_perm_mode_to_oct(char out[static 5], mode_t mode); +int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid); +int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name); +int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid); +int fr_perm_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name); +int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name); +char *fr_perm_uid_to_str(TALLOC_CTX *ctx, uid_t uid); +char *fr_perm_gid_to_str(TALLOC_CTX *ctx, gid_t gid); +void fr_perm_file_error(int num); + +#ifdef __cplusplus +} +#endif diff --git a/src/listen/control/proto_control_unix.c b/src/listen/control/proto_control_unix.c index 9fa8aed0a08..20b62189092 100644 --- a/src/listen/control/proto_control_unix.c +++ b/src/listen/control/proto_control_unix.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -648,8 +649,8 @@ static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid) struct passwd *user; struct group *group; - if (rad_getpwuid(NULL, &user, euid) < 0) goto error; - if (rad_getgrgid(NULL, &group, egid) < 0) { + if (fr_perm_getpwuid(NULL, &user, euid) < 0) goto error; + if (fr_perm_getgrgid(NULL, &group, egid) < 0) { talloc_free(user); goto error; } @@ -719,8 +720,8 @@ static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid) if ((uid != (uid_t)-1) && (st.st_uid != uid)) { struct passwd *need_user, *have_user; - if (rad_getpwuid(NULL, &need_user, uid) < 0) goto error; - if (rad_getpwuid(NULL, &have_user, st.st_uid) < 0) { + if (fr_perm_getpwuid(NULL, &need_user, uid) < 0) goto error; + if (fr_perm_getpwuid(NULL, &have_user, st.st_uid) < 0) { talloc_free(need_user); goto error; } @@ -734,8 +735,8 @@ static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid) if ((gid != (gid_t)-1) && (st.st_gid != gid)) { struct group *need_group, *have_group; - if (rad_getgrgid(NULL, &need_group, gid) < 0) goto error; - if (rad_getgrgid(NULL, &have_group, st.st_gid) < 0) { + if (fr_perm_getgrgid(NULL, &need_group, gid) < 0) goto error; + if (fr_perm_getgrgid(NULL, &have_group, st.st_gid) < 0) { talloc_free(need_group); goto error; } @@ -750,10 +751,10 @@ static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid) char str_need[10], oct_need[5]; char str_have[10], oct_have[5]; - rad_mode_to_str(str_need, perm); - rad_mode_to_oct(oct_need, perm); - rad_mode_to_str(str_have, st.st_mode); - rad_mode_to_oct(oct_have, st.st_mode); + fr_perm_mode_to_str(str_need, perm); + fr_perm_mode_to_oct(oct_need, perm); + fr_perm_mode_to_str(str_have, st.st_mode); + fr_perm_mode_to_oct(oct_have, st.st_mode); fr_strerror_printf("Control socket directory must have permissions %s (%s), current " "permissions are %s (%s)", str_need, oct_need, str_have, oct_have); goto error; @@ -852,8 +853,8 @@ static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid) if (fchmod(sock_fd, perm) < 0) { char str_need[10], oct_need[5]; - rad_mode_to_str(str_need, perm); - rad_mode_to_oct(oct_need, perm); + fr_perm_mode_to_str(str_need, perm); + fr_perm_mode_to_oct(oct_need, perm); fr_strerror_printf("Failed changing socket permissions to %s (%s)", str_need, oct_need); goto sock_error; @@ -863,8 +864,8 @@ static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid) struct passwd *user; struct group *group; - if (rad_getpwuid(NULL, &user, uid) < 0) goto sock_error; - if (rad_getgrgid(NULL, &group, gid) < 0) { + if (fr_perm_getpwuid(NULL, &user, uid) < 0) goto sock_error; + if (fr_perm_getgrgid(NULL, &group, gid) < 0) { talloc_free(user); goto sock_error; } @@ -1133,7 +1134,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *cs) if (inst->uid_name) { struct passwd *pwd; - if (rad_getpwnam(cs, &pwd, inst->uid_name) < 0) { + if (fr_perm_getpwnam(cs, &pwd, inst->uid_name) < 0) { PERROR("Failed getting uid for %s", inst->uid_name); return -1; } @@ -1144,7 +1145,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *cs) } if (inst->gid_name) { - if (rad_getgid(cs, &inst->gid, inst->gid_name) < 0) { + if (fr_perm_gid_from_str(cs, &inst->gid, inst->gid_name) < 0) { PERROR("Failed getting gid for %s", inst->gid_name); return -1; } diff --git a/src/modules/rlm_detail/rlm_detail.c b/src/modules/rlm_detail/rlm_detail.c index 536e744af84..606d8352cab 100644 --- a/src/modules/rlm_detail/rlm_detail.c +++ b/src/modules/rlm_detail/rlm_detail.c @@ -27,9 +27,10 @@ RCSID("$Id$") #define LOG_PREFIX_ARGS inst->name #include +#include #include #include -#include +#include #include #include @@ -397,7 +398,7 @@ static unlang_action_t CC_HINT(nonnull) detail_do(rlm_rcode_t *p_result, module_ if (inst->group != NULL) { gid = strtol(inst->group, &endptr, 10); if (*endptr != '\0') { - if (rad_getgid(request, &gid, inst->group) < 0) { + if (fr_perm_gid_from_str(request, &gid, inst->group) < 0) { RDEBUG2("Unable to find system group '%s'", inst->group); goto skip_group; } diff --git a/src/modules/rlm_linelog/rlm_linelog.c b/src/modules/rlm_linelog/rlm_linelog.c index 53730c0b54e..2284485b1a5 100644 --- a/src/modules/rlm_linelog/rlm_linelog.c +++ b/src/modules/rlm_linelog/rlm_linelog.c @@ -24,9 +24,10 @@ RCSID("$Id$") #include +#include #include #include -#include +#include #ifdef HAVE_FCNTL_H # include @@ -334,7 +335,7 @@ static int mod_instantiate(void *instance, CONF_SECTION *conf) inst->file.group = strtol(inst->file.group_str, &endptr, 10); if (*endptr != '\0') { - if (rad_getgid(inst, &(inst->file.group), inst->file.group_str) < 0) { + if (fr_perm_gid_from_str(inst, &(inst->file.group), inst->file.group_str) < 0) { cf_log_err(conf, "Unable to find system group \"%s\"", inst->file.group_str); return -1; diff --git a/src/modules/rlm_opendirectory/rlm_opendirectory.c b/src/modules/rlm_opendirectory/rlm_opendirectory.c index aa0d95b3a66..22c1e51a437 100644 --- a/src/modules/rlm_opendirectory/rlm_opendirectory.c +++ b/src/modules/rlm_opendirectory/rlm_opendirectory.c @@ -32,6 +32,7 @@ USES_APPLE_DEPRECATED_API #include #include #include +#include #include #include @@ -409,7 +410,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod /* resolve SACL */ uuid_clear(guid_sacl); - if (rad_getgid(request, &gid, kRadiusSACLName) < 0) { + if (fr_perm_gid_from_str(request, &gid, kRadiusSACLName) < 0) { RDEBUG2("The SACL group \"%s\" does not exist on this system", kRadiusSACLName); } else { err = mbr_gid_to_uuid(gid, guid_sacl); @@ -463,7 +464,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod /* resolve user */ uuid_clear(uuid); - rad_getpwnam(request, &userdata, username->vp_strvalue); + fr_perm_getpwnam(request, &userdata, username->vp_strvalue); if (userdata != NULL) { err = mbr_uid_to_uuid(userdata->pw_uid, uuid); if (err != 0) diff --git a/src/modules/rlm_unix/rlm_unix.c b/src/modules/rlm_unix/rlm_unix.c index 7a9df5a73da..8a571f4f1ef 100644 --- a/src/modules/rlm_unix/rlm_unix.c +++ b/src/modules/rlm_unix/rlm_unix.c @@ -33,10 +33,11 @@ USES_APPLE_DEPRECATED_API #define LOG_PREFIX "rlm_unix (%s) - " #define LOG_PREFIX_ARGS inst->name +#include #include #include #include -#include +#include #include #include @@ -115,12 +116,12 @@ static int groupcmp(UNUSED void *instance, request_t *request, UNUSED fr_pair_li username = fr_pair_find_by_da(&request->request_pairs, attr_user_name, 0); if (!username) return -1; - if (rad_getpwnam(request, &pwd, username->vp_strvalue) < 0) { + if (fr_perm_getpwnam(request, &pwd, username->vp_strvalue) < 0) { RPEDEBUG("Failed resolving user name"); return -1; } - if (rad_getgrnam(request, &grp, check->vp_strvalue) < 0) { + if (fr_perm_getgrnam(request, &grp, check->vp_strvalue) < 0) { RPEDEBUG("Failed resolving group name"); talloc_free(pwd); return -1;