/libraries/liblutil/getpeereid.c

https://github.com/ReOpen/ReOpenLDAP · C · 213 lines · 160 code · 30 blank · 23 comment · 35 complexity · 553d2cca4cff88c8f71eb888d11f6642 MD5 · raw file

  1. /* $ReOpenLDAP$ */
  2. /* Copyright 1992-2018 ReOpenLDAP AUTHORS: please see AUTHORS file.
  3. * All rights reserved.
  4. *
  5. * This file is part of ReOpenLDAP.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted only as authorized by the OpenLDAP
  9. * Public License.
  10. *
  11. * A copy of this license is available in the file LICENSE in the
  12. * top-level directory of the distribution or, alternatively, at
  13. * <http://www.OpenLDAP.org/license.html>.
  14. */
  15. #include "reldap.h"
  16. #ifndef HAVE_GETPEEREID
  17. #include <sys/types.h>
  18. #include <ac/unistd.h>
  19. #include <ac/socket.h>
  20. #include <ac/errno.h>
  21. #ifdef HAVE_GETPEERUCRED
  22. #include <ucred.h>
  23. #endif
  24. #ifdef LDAP_PF_LOCAL_SENDMSG
  25. #include <lber.h>
  26. #ifdef HAVE_SYS_UIO_H
  27. #include <sys/uio.h>
  28. #endif
  29. #include <sys/stat.h>
  30. #endif
  31. #ifdef HAVE_SYS_UCRED_H
  32. #ifdef HAVE_GRP_H
  33. #include <grp.h> /* for NGROUPS on Tru64 5.1 */
  34. #endif
  35. #include <sys/ucred.h>
  36. #endif
  37. #include <stdlib.h>
  38. int lutil_getpeereid(int s, uid_t *euid, gid_t *egid
  39. #ifdef LDAP_PF_LOCAL_SENDMSG
  40. ,
  41. struct berval *peerbv
  42. #endif
  43. ) {
  44. #ifdef LDAP_PF_LOCAL
  45. #if defined(HAVE_GETPEERUCRED)
  46. ucred_t *uc = NULL;
  47. if (getpeerucred(s, &uc) == 0) {
  48. *euid = ucred_geteuid(uc);
  49. *egid = ucred_getegid(uc);
  50. ucred_free(uc);
  51. return 0;
  52. }
  53. #elif defined(SO_PEERCRED)
  54. struct ucred peercred;
  55. ber_socklen_t peercredlen = sizeof peercred;
  56. if ((getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&peercred,
  57. &peercredlen) == 0) &&
  58. (peercredlen == sizeof peercred)) {
  59. *euid = peercred.uid;
  60. *egid = peercred.gid;
  61. return 0;
  62. }
  63. #elif defined(LOCAL_PEERCRED)
  64. struct xucred peercred;
  65. ber_socklen_t peercredlen = sizeof peercred;
  66. if ((getsockopt(s, LOCAL_PEERCRED, 1, (void *)&peercred, &peercredlen) ==
  67. 0) &&
  68. (peercred.cr_version == XUCRED_VERSION)) {
  69. *euid = peercred.cr_uid;
  70. *egid = peercred.cr_gid;
  71. return 0;
  72. }
  73. #elif defined(LDAP_PF_LOCAL_SENDMSG) && defined(MSG_WAITALL)
  74. int err, fd;
  75. struct iovec iov;
  76. struct msghdr msg = {0};
  77. #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
  78. #ifndef CMSG_SPACE
  79. #define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
  80. #endif
  81. #ifndef CMSG_LEN
  82. #define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
  83. #endif
  84. struct {
  85. struct cmsghdr cm;
  86. int fd;
  87. } control_st;
  88. struct cmsghdr *cmsg;
  89. #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
  90. struct stat st;
  91. struct sockaddr_un lname, rname;
  92. ber_socklen_t llen, rlen;
  93. rlen = sizeof(rname);
  94. llen = sizeof(lname);
  95. memset(&lname, 0, sizeof(lname));
  96. getsockname(s, (struct sockaddr *)&lname, &llen);
  97. iov.iov_base = peerbv->bv_val;
  98. iov.iov_len = peerbv->bv_len;
  99. msg.msg_iov = &iov;
  100. msg.msg_iovlen = 1;
  101. peerbv->bv_len = 0;
  102. #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
  103. msg.msg_control = &control_st;
  104. msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int); /* no padding! */
  105. cmsg = CMSG_FIRSTHDR(&msg);
  106. #else
  107. msg.msg_accrights = (char *)&fd;
  108. msg.msg_accrightslen = sizeof(fd);
  109. #endif
  110. /*
  111. * AIX returns a bogus file descriptor if recvmsg() is
  112. * called with MSG_PEEK (is this a bug?). Hence we need
  113. * to receive the Abandon PDU.
  114. */
  115. err = recvmsg(s, &msg, MSG_WAITALL);
  116. if (err >= 0 &&
  117. #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
  118. cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
  119. cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS
  120. #else
  121. msg.msg_accrightslen == sizeof(int)
  122. #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/
  123. ) {
  124. int mode = S_IFIFO | S_ISUID | S_IRWXU;
  125. /* We must receive a valid descriptor, it must be a pipe,
  126. * it must only be accessible by its owner, and it must
  127. * have the name of our socket written on it.
  128. */
  129. peerbv->bv_len = err;
  130. #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
  131. fd = (*(int *)CMSG_DATA(cmsg));
  132. #endif
  133. err = fstat(fd, &st);
  134. if (err == 0)
  135. rlen = read(fd, &rname, rlen);
  136. close(fd);
  137. if (err == 0 && st.st_mode == mode && llen == rlen &&
  138. !memcmp(&lname, &rname, llen)) {
  139. *euid = st.st_uid;
  140. *egid = st.st_gid;
  141. return 0;
  142. }
  143. }
  144. #elif defined(SOCKCREDSIZE)
  145. struct msghdr msg;
  146. ber_socklen_t crmsgsize;
  147. void *crmsg;
  148. struct cmsghdr *cmp;
  149. struct sockcred *sc;
  150. memset(&msg, 0, sizeof msg);
  151. crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
  152. if (crmsgsize == 0)
  153. goto sc_err;
  154. crmsg = malloc(crmsgsize);
  155. if (crmsg == NULL)
  156. goto sc_err;
  157. memset(crmsg, 0, crmsgsize);
  158. msg.msg_control = crmsg;
  159. msg.msg_controllen = crmsgsize;
  160. if (recvmsg(s, &msg, 0) < 0) {
  161. free(crmsg);
  162. goto sc_err;
  163. }
  164. if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
  165. free(crmsg);
  166. goto sc_err;
  167. }
  168. cmp = CMSG_FIRSTHDR(&msg);
  169. if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
  170. printf("nocreds\n");
  171. goto sc_err;
  172. }
  173. sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
  174. *euid = sc->sc_euid;
  175. *egid = sc->sc_egid;
  176. free(crmsg);
  177. return 0;
  178. sc_err:
  179. #endif
  180. #endif /* LDAP_PF_LOCAL */
  181. return -1;
  182. }
  183. #endif /* HAVE_GETPEEREID */