The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
perm.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Implementation of filed semaphores that release on exit
18  *
19  * @file src/lib/util/perm.c
20  *
21  * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22  */
23 RCSID("$Id: e8ea254e769cfeedb1382a39faf547c22ba617e3 $")
24 
25 #include <freeradius-devel/util/perm.h>
26 #include <freeradius-devel/util/strerror.h>
27 #include <freeradius-devel/util/syserror.h>
28 
29 /** Convert mode_t into humanly readable permissions flags
30  *
31  * @author Jonathan Leffler.
32  *
33  * @param mode to convert.
34  * @param out Where to write the string to, must be exactly 10 bytes long.
35  */
36 char const *fr_perm_mode_to_str(char out[static 10], mode_t mode)
37 {
38  static char const *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
39 
40  strcpy(&out[0], rwx[(mode >> 6) & 0x07]);
41  strcpy(&out[3], rwx[(mode >> 3) & 0x07]);
42  strcpy(&out[6], rwx[(mode & 7)]);
43  if (mode & S_ISUID) out[2] = (mode & 0100) ? 's' : 'S';
44  if (mode & S_ISGID) out[5] = (mode & 0010) ? 's' : 'l';
45  if (mode & S_ISVTX) out[8] = (mode & 0100) ? 't' : 'T';
46  out[9] = '\0';
47 
48  return out;
49 }
50 
51 char const *fr_perm_mode_to_oct(char out[static 5], mode_t mode)
52 {
53  out[0] = '0' + ((mode >> 9) & 0x07);
54  out[1] = '0' + ((mode >> 6) & 0x07);
55  out[2] = '0' + ((mode >> 3) & 0x07);
56  out[3] = '0' + (mode & 0x07);
57  out[4] = '\0';
58 
59  return out;
60 }
61 
62 /** Resolve a uid to a passwd entry
63  *
64  * Resolves a uid to a passwd entry. The memory to hold the
65  * passwd entry is talloced under ctx, and must be freed when no
66  * longer required.
67  *
68  * @param ctx to allocate passwd entry in.
69  * @param out Where to write pointer to entry.
70  * @param uid to resolve.
71  * @return
72  * - 0 on success.
73  * - -1 on failure.
74  */
75 int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
76 {
77  static size_t len;
78  uint8_t *buff;
79  int ret;
80 
81  *out = NULL;
82 
83  /*
84  * We assume this won't change between calls,
85  * and that the value is the same, so races don't
86  * matter.
87  */
88  if (len == 0) {
89 #ifdef _SC_GETPW_R_SIZE_MAX
90  long int sc_len;
91 
92  sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
93  if (sc_len <= 0) sc_len = 1024;
94  len = (size_t)sc_len;
95 #else
96  len = 1024;
97 #endif
98  }
99 
100  buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
101  if (!buff) return -1;
102 
103  /*
104  * In some cases we may need to dynamically
105  * grow the string buffer.
106  */
107  while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
108  talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
109  buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
110  }
111 
112  if ((ret != 0) || !*out) {
113  fr_strerror_printf("%s", (errno != 0) ? fr_syserror(ret) : "Non-existent user");
114  talloc_free(buff);
115  errno = ret;
116  return -1;
117  }
118 
119  talloc_set_type(buff, struct passwd);
120  *out = (struct passwd *)buff;
121 
122  return 0;
123 }
124 
125 /** Resolve a username to a passwd entry
126  *
127  * Resolves a username to a passwd entry. The memory to hold the
128  * passwd entry is talloced under ctx, and must be freed when no
129  * longer required.
130  *
131  * @param ctx to allocate passwd entry in.
132  * @param out Where to write pointer to entry.
133  * @param name to resolve.
134  * @return
135  * - 0 on success.
136  * - -1 on failure.
137  */
138 int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
139 {
140  static size_t len;
141  uint8_t *buff;
142  int ret;
143 
144  *out = NULL;
145 
146  /*
147  * We assume this won't change between calls,
148  * and that the value is the same, so races don't
149  * matter.
150  */
151  if (len == 0) {
152 #ifdef _SC_GETPW_R_SIZE_MAX
153  long int sc_len;
154 
155  sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
156  if (sc_len <= 0) sc_len = 1024;
157  len = (size_t)sc_len;
158 #else
159  sc_len = 1024;
160 #endif
161  }
162 
163  buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
164  if (!buff) return -1;
165 
166  /*
167  * In some cases we may need to dynamically
168  * grow the string buffer.
169  */
170  while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
171  talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
172  buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
173  }
174 
175  if ((ret != 0) || !*out) {
176  fr_strerror_printf("%s", (errno != 0) ? fr_syserror(ret) : "Non-existent user");
177  talloc_free(buff);
178  errno = ret;
179  return -1;
180  }
181 
182  talloc_set_type(buff, struct passwd);
183  *out = (struct passwd *)buff;
184 
185  return 0;
186 }
187 
188 /** Resolve a gid to a group database entry
189  *
190  * Resolves a gid to a group database entry. The memory to hold the
191  * group entry is talloced under ctx, and must be freed when no
192  * longer required.
193  *
194  * @param ctx to allocate passwd entry in.
195  * @param out Where to write pointer to entry.
196  * @param gid to resolve.
197  * @return
198  * - 0 on success.
199  * - -1 on failure.
200  */
201 int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
202 {
203  static size_t len;
204  uint8_t *buff;
205  int ret;
206 
207  *out = NULL;
208 
209  /*
210  * We assume this won't change between calls,
211  * and that the value is the same, so races don't
212  * matter.
213  */
214  if (len == 0) {
215 #ifdef _SC_GETGR_R_SIZE_MAX
216  long int sc_len;
217 
218  sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
219  if (sc_len <= 0) sc_len = 1024;
220  len = (size_t)sc_len;
221 #else
222  sc_len = 1024;
223 #endif
224  }
225 
226  buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
227  if (!buff) return -1;
228 
229  /*
230  * In some cases we may need to dynamically
231  * grow the string buffer.
232  */
233  while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)),
234  talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
235  buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
236  }
237 
238  if ((ret != 0) || !*out) {
239  fr_strerror_printf("%s", (ret != 0) ? fr_syserror(ret) : "Non-existent group");
240  talloc_free(buff);
241  errno = ret;
242  return -1;
243  }
244 
245  talloc_set_type(buff, struct group);
246  *out = (struct group *)buff;
247 
248  return 0;
249 }
250 
251 /** Resolve a group name to a group database entry
252  *
253  * Resolves a group name to a group database entry.
254  * The memory to hold the group entry is talloced under ctx,
255  * and must be freed when no longer required.
256  *
257  * @param ctx to allocate passwd entry in.
258  * @param out Where to write pointer to entry.
259  * @param name to resolve.
260  * @return
261  * - 0 on success.
262  * - -1 on failure.
263  */
264 int fr_perm_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
265 {
266  static size_t len;
267  uint8_t *buff;
268  int ret;
269 
270  *out = NULL;
271 
272  /*
273  * We assume this won't change between calls,
274  * and that the value is the same, so races don't
275  * matter.
276  */
277  if (len == 0) {
278 #ifdef _SC_GETGR_R_SIZE_MAX
279  long int sc_len;
280 
281  sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
282  if (sc_len <= 0) sc_len = 1024;
283  len = (size_t)sc_len;
284 #else
285  len = 1024;
286 #endif
287  }
288 
289  buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
290  if (!buff) return -1;
291 
292  /*
293  * In some cases we may need to dynamically
294  * grow the string buffer.
295  */
296  while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)),
297  talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
298  buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
299  }
300 
301  if ((ret != 0) || !*out) {
302  fr_strerror_printf("%s", (ret != 0) ? fr_syserror(ret) : "Non-existent group");
303  talloc_free(buff);
304  errno = ret;
305  return -1;
306  }
307 
308  talloc_set_type(buff, struct group);
309  *out = (struct group *)buff;
310 
311  return 0;
312 }
313 
314 /** Resolve a user name to a GID
315  *
316  * @param[in] ctx TALLOC_CTX for temporary allocations.
317  * @param[in] out where to write gid.
318  * @param[in] name of user.
319  * @return
320  * - 0 on success.
321  * - -1 on failure.
322  */
323 int fr_perm_uid_from_str(TALLOC_CTX *ctx, uid_t *out, char const *name)
324 {
325  int ret;
326  struct passwd *result;
327 
328  ret = fr_perm_getpwnam(ctx, &result, name);
329  if (ret < 0) return -1;
330 
331  *out = result->pw_uid;
332  talloc_free(result);
333  return 0;
334 }
335 
336 /** Resolve a group name to a GID
337  *
338  * @param[in] ctx TALLOC_CTX for temporary allocations.
339  * @param[in] out where to write gid.
340  * @param[in] name of group.
341  * @return
342  * - 0 on success.
343  * - -1 on failure.
344  */
345 int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name)
346 {
347  int ret;
348  struct group *result;
349 
350  ret = fr_perm_getgrnam(ctx, &result, name);
351  if (ret < 0) return -1;
352 
353  *out = result->gr_gid;
354  talloc_free(result);
355  return 0;
356 }
357 
358 /** Print uid to a string
359  *
360  * @param ctx TALLOC_CTX for temporary allocations.
361  * @param uid to resolve.
362  * @return
363  * - 0 on success.
364  * - -1 on failure.
365  */
366 char *fr_perm_uid_to_str(TALLOC_CTX *ctx, uid_t uid)
367 {
368  struct passwd *result;
369  char *out;
370 
371  if (fr_perm_getpwuid(ctx, &result, uid) < 0) return NULL;
372  out = talloc_typed_strdup(ctx, result->pw_name);
373  talloc_free(result);
374 
375  return out;
376 }
377 
378 /** Print gid to a string
379  *
380  * @param ctx TALLOC_CTX for temporary allocations.
381  * @param gid to resolve.
382  * @return
383  * - 0 on success.
384  * - -1 on failure.
385  */
386 char *fr_perm_gid_to_str(TALLOC_CTX *ctx, uid_t gid){
387  struct group *result;
388  char *out;
389 
390  if (fr_perm_getgrgid(ctx, &result, gid) < 0) return NULL;
391  out = talloc_typed_strdup(ctx, result->gr_name);
392  talloc_free(result);
393 
394  return out;
395 }
396 
397 /** Write a file access error to the fr_strerror buffer, including euid/egid
398  *
399  * @note retrieve error with fr_strerror()
400  *
401  * @param num Usually errno, unless the error is returned by the function.
402  */
403 void fr_perm_file_error(int num)
404 {
405  char const *error;
406  struct passwd *user = NULL;
407  struct group *group = NULL;
408 
409  error = fr_syserror(num);
410 
411  if (fr_perm_getpwuid(NULL, &user, geteuid()) < 0) goto finish;
412  if (fr_perm_getgrgid(NULL, &group, getegid()) < 0) goto finish;
413 
414  fr_strerror_printf("Effective user/group - %s:%s: %s", user->pw_name, group->gr_name, error);
415 finish:
416  talloc_free(user);
417  talloc_free(group);
418 }
strcpy(log_entry->msg, buffer)
#define RCSID(id)
Definition: build.h:481
talloc_free(reap)
unsigned char uint8_t
Definition: merged_model.c:30
unsigned int mode_t
Definition: merged_model.c:21
unsigned long int size_t
Definition: merged_model.c:25
int fr_perm_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
Resolve a group name to a group database entry.
Definition: perm.c:264
char const * fr_perm_mode_to_oct(char out[static 5], mode_t mode)
Definition: perm.c:51
char const * fr_perm_mode_to_str(char out[static 10], mode_t mode)
Convert mode_t into humanly readable permissions flags.
Definition: perm.c:36
char * fr_perm_gid_to_str(TALLOC_CTX *ctx, uid_t gid)
Print gid to a string.
Definition: perm.c:386
int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
Resolve a gid to a group database entry.
Definition: perm.c:201
int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
Resolve a username to a passwd entry.
Definition: perm.c:138
int fr_perm_uid_from_str(TALLOC_CTX *ctx, uid_t *out, char const *name)
Resolve a user name to a GID.
Definition: perm.c:323
int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
Resolve a uid to a passwd entry.
Definition: perm.c:75
int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name)
Resolve a group name to a GID.
Definition: perm.c:345
void fr_perm_file_error(int num)
Write a file access error to the fr_strerror buffer, including euid/egid.
Definition: perm.c:403
char * fr_perm_uid_to_str(TALLOC_CTX *ctx, uid_t uid)
Print uid to a string.
Definition: perm.c:366
static char const * name
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition: talloc.c:445
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static size_t char ** out
Definition: value.h:997