user.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #include "common/user.h"
  19. #include <errno.h>
  20. #include <pwd.h>
  21. #include <stdarg.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include <unistd.h>
  27. #define GETPWUID_R_BUFLEN_MIN 4096
  28. #define GETPWUID_R_BUFLEN_MAX (8 * 1024 * 1024)
  29. /**
  30. * Get the user name associated with a given numeric user ID.
  31. *
  32. * The POSIX APIs to do this require a little more code than you might expect.
  33. * We have to supply a buffer to the getpwuid_r call. But how big should it
  34. * be? We can call sysconf to get a "suggested size," but this may or may not
  35. * be big enough for our particular user. Also, on some platforms, sysconf
  36. * returns -1 for this. So we have a loop which keeps doubling the size of the
  37. * buffer. As a sanity check against buggy libraries, we give up when we reach
  38. * some ridiculous buffer size.
  39. *
  40. * @param uid UID to look up
  41. * @param out (out param) on success, the user name.
  42. *
  43. * @return 0 on success; error code on failure.
  44. */
  45. static int uid_to_string(uid_t uid, char **out)
  46. {
  47. int ret;
  48. struct passwd pwd, *result;
  49. char *buf = NULL, *nbuf;
  50. size_t buflen, nbuflen;
  51. buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
  52. if (buflen < GETPWUID_R_BUFLEN_MIN) {
  53. buflen = GETPWUID_R_BUFLEN_MIN;
  54. }
  55. while (1) {
  56. nbuf = realloc(buf, buflen);
  57. if (!nbuf) {
  58. ret = ENOMEM;
  59. goto done;
  60. }
  61. buf = nbuf;
  62. ret = getpwuid_r(uid, &pwd, buf, buflen, &result);
  63. if (ret == 0)
  64. break;
  65. if (ret != ERANGE) {
  66. fprintf(stderr, "geteuid_string: getpwuid_r(%lld) failed "
  67. "with error %d\n", (long long)uid, ret);
  68. goto done;
  69. }
  70. nbuflen = buflen *2;
  71. if (nbuflen > GETPWUID_R_BUFLEN_MAX) {
  72. nbuflen = GETPWUID_R_BUFLEN_MAX;
  73. }
  74. if (buflen == nbuflen) {
  75. fprintf(stderr, "geteuid_string: getpwuid_r(%lld) still gets "
  76. "ERANGE with buflen %zd\n", (long long)uid, buflen);
  77. ret = ERANGE;
  78. goto done;
  79. }
  80. buflen = nbuflen;
  81. }
  82. if (!result) {
  83. ret = ENOENT;
  84. fprintf(stderr, "geteuid_string: getpwuid_r(%lld): no name "
  85. "found for current effective user id.\n", (long long)uid);
  86. goto done;
  87. }
  88. *out = strdup(result->pw_name);
  89. if (!*out) {
  90. ret = ENOMEM;
  91. goto done;
  92. }
  93. done:
  94. free(buf);
  95. return ret;
  96. }
  97. int geteuid_string(char **out)
  98. {
  99. return uid_to_string(geteuid(), out);
  100. }
  101. // vim: ts=4:sw=4:tw=79:et