PageRenderTime 26ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/ocamlnet-3.5.1/src/rpc-auth-local/rpclocal.c

#
C | 255 lines | 181 code | 41 blank | 33 comment | 28 complexity | 0c1cbc33f86894b04b9f98e626d747d9 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* $Id: rpclocal.c 1686 2012-01-17 12:20:40Z gerd $
  2. * ----------------------------------------------------------------------
  3. *
  4. */
  5. #define _GNU_SOURCE
  6. /* Required on some systems to enable struct ucred in sys/socket.h */
  7. #include "config.h"
  8. #include "caml/mlvalues.h"
  9. #include "caml/alloc.h"
  10. #include "caml/memory.h"
  11. #include "caml/fail.h"
  12. #ifndef _WIN32
  13. #include <unistd.h>
  14. #include <sys/types.h>
  15. #include <sys/socket.h>
  16. #include <sys/un.h>
  17. #include <sys/uio.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <limits.h>
  21. #endif
  22. #ifdef HAVE_GETPEERUCRED
  23. #include <ucred.h>
  24. #endif
  25. /**********************************************************************/
  26. /* From unixsupport.h */
  27. /**********************************************************************/
  28. #define Nothing ((value) 0)
  29. extern void unix_error (int errcode, char * cmdname, value arg) Noreturn;
  30. extern void uerror (char * cmdname, value arg) Noreturn;
  31. /**********************************************************************/
  32. /* Inspired by PostgreSQL's fe-connect.c */
  33. value netsys_get_peer_credentials(value fd) {
  34. CAMLparam1(fd);
  35. CAMLlocal1(result);
  36. #if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(HAVE_GETPEERUCRED)
  37. uid_t uid;
  38. gid_t gid;
  39. #else
  40. int uid;
  41. int gid;
  42. #endif
  43. #if defined(HAVE_GETPEEREID)
  44. /* BSD, AIX, Cygwin */
  45. /* http://cr.yp.to/docs/secureipc.html */
  46. if (getpeereid(Int_val(fd), &uid, &gid) != 0) {
  47. uerror("getpeereid", Nothing);
  48. }
  49. #elif defined(SO_PEERCRED)
  50. /* Linux */
  51. {
  52. socklen_t len;
  53. struct ucred credentials;
  54. len = sizeof(struct ucred);
  55. if (getsockopt(Int_val(fd),
  56. SOL_SOCKET,
  57. SO_PEERCRED,
  58. &credentials,
  59. &len) == -1) {
  60. uerror("getsockopt",Nothing);
  61. };
  62. uid = credentials.uid; /* Effective user ID */
  63. gid = credentials.gid; /* Effective group ID */
  64. }
  65. #elif defined(HAVE_GETPEERUCRED)
  66. /* Solaris */
  67. {
  68. ucred_t *ucred;
  69. ucred = NULL; /* must be initialized to NULL */
  70. if (getpeerucred(Int_val(fd), &ucred) == -1) {
  71. uerror("getpeerucred",Nothing);
  72. };
  73. if ((uid = ucred_geteuid(ucred)) == -1) {
  74. uerror("ucred_geteuid",Nothing);
  75. ucred_free(ucred);
  76. };
  77. if ((gid = ucred_getegid(ucred)) == -1) {
  78. uerror("ucred_getegid",Nothing);
  79. ucred_free(ucred);
  80. };
  81. ucred_free(ucred);
  82. }
  83. #else
  84. invalid_argument("get_peer_credentials");
  85. #endif
  86. /* Allocate a pair, and put the result into it: */
  87. result = alloc_tuple(2);
  88. Store_field(result, 0, Val_int(uid));
  89. Store_field(result, 1, Val_int(gid));
  90. CAMLreturn(result);
  91. }
  92. /**********************************************************************/
  93. /*
  94. * Another way of getting the credentials is too peek the next message
  95. * and look at the ancillary data. But this works only if the sender
  96. * has set the ancillary data, or if the operating system supports that
  97. * the receiver can request credentials.
  98. */
  99. #if 0
  100. value netsys_peek_peer_credentials(value fd) {
  101. CAMLparam1(fd);
  102. CAMLlocal1(result);
  103. int uid;
  104. int gid;
  105. #ifdef SO_PASSCRED
  106. /* Linux */
  107. {
  108. int one = 1;
  109. struct msghdr msg;
  110. struct cmsghdr *cmp;
  111. struct ucred *sc;
  112. char buf[CMSG_SPACE(sizeof(*sc))];
  113. struct iovec iov;
  114. char iovbuf[1];
  115. if (setsockopt(Int_val(fd),
  116. SOL_SOCKET,
  117. SO_PASSCRED,
  118. &one,
  119. sizeof(one)) < 0) {
  120. uerror("setsockopt", Nothing);
  121. };
  122. memset(&msg, 0, sizeof msg);
  123. msg.msg_name = NULL;
  124. msg.msg_namelen = 0;
  125. msg.msg_iov = &iov;
  126. msg.msg_iovlen = 1;
  127. msg.msg_control = buf;
  128. msg.msg_controllen = sizeof(buf);
  129. iov.iov_base = iovbuf;
  130. iov.iov_len = 1;
  131. /* Linux requires that at least one byte must be transferred.
  132. * So we initialize the iovector for exactly one byte.
  133. */
  134. if (recvmsg(Int_val(fd), &msg, MSG_PEEK) < 0) {
  135. uerror("recvmsg", Nothing);
  136. };
  137. if (msg.msg_controllen == 0 ||
  138. (msg.msg_flags & MSG_CTRUNC) != 0) {
  139. raise_not_found();
  140. };
  141. cmp = CMSG_FIRSTHDR(&msg);
  142. if (cmp->cmsg_level != SOL_SOCKET ||
  143. cmp->cmsg_type != SCM_CREDENTIALS) {
  144. raise_not_found();
  145. };
  146. sc = (struct ucred *) CMSG_DATA(cmp);
  147. uid = sc->uid;
  148. gid = sc->gid;
  149. }
  150. #else
  151. #ifdef LOCAL_CREDS
  152. /* NetBSD */
  153. /* The following code has been copied from libc: rpc/svc_vc.c
  154. * TODO: The following code does not work. No idea why.
  155. * msg_controllen is always 0. Maybe the socket option must be
  156. * set earlier (but that would be very strange).
  157. */
  158. {
  159. int one = 1;
  160. struct msghdr msg;
  161. struct cmsghdr *cmp;
  162. void *crmsg = NULL;
  163. struct sockcred *sc;
  164. socklen_t crmsgsize;
  165. struct iovec iov;
  166. char buf;
  167. if (setsockopt(Int_val(fd),
  168. SOL_SOCKET,
  169. LOCAL_CREDS,
  170. &one,
  171. sizeof(one)) < 0) {
  172. uerror("setsockopt", Nothing);
  173. };
  174. memset(&msg, 0, sizeof msg);
  175. crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX));
  176. crmsg = stat_alloc(crmsgsize);
  177. memset(crmsg, 0, crmsgsize);
  178. msg.msg_control = crmsg;
  179. msg.msg_controllen = crmsgsize;
  180. msg.msg_iov = &iov;
  181. msg.msg_iovlen = 1;
  182. iov.iov_base = &buf;
  183. iov.iov_len = 1;
  184. if (recvmsg(Int_val(fd), &msg, MSG_PEEK) < 0) {
  185. stat_free(crmsg);
  186. uerror("recvmsg", Nothing);
  187. };
  188. if (msg.msg_controllen == 0 ||
  189. (msg.msg_flags & MSG_CTRUNC) != 0) {
  190. stat_free(crmsg);
  191. raise_not_found();
  192. };
  193. cmp = CMSG_FIRSTHDR(&msg);
  194. if (cmp->cmsg_level != SOL_SOCKET ||
  195. cmp->cmsg_type != SCM_CREDS) {
  196. stat_free(crmsg);
  197. raise_not_found();
  198. };
  199. sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
  200. uid = sc->sc_euid;
  201. gid = sc->sc_egid;
  202. free(crmsg);
  203. }
  204. #else
  205. invalid_argument("peek_peer_credentials");
  206. #endif
  207. #endif
  208. /* Allocate a pair, and put the result into it: */
  209. result = alloc_tuple(2);
  210. Store_field(result, 0, Val_int(uid));
  211. Store_field(result, 1, Val_int(gid));
  212. CAMLreturn(result);
  213. }
  214. #endif