Re: SO_PASSCRED broken in 2.4 ? - mystery tackled

From: Jakob Østergaard (jakob@ostenfeld.dtu.dk)
Date: Sun Jul 02 2000 - 14:36:28 EST


On Sun, 02 Jul 2000, kuznet@ms2.inr.ac.ru wrote:

> Hello!
>
> > However, the following ``fix'' can be applied:
> > ------------------------------
> > ...
> > antsd = socket(AF_UNIX, SOCK_STREAM, 0);
> > ...
> > addr.sun_family = AF_UNSPEC; /* used to be AF_UNIX */
> > ...
> > ------------------------------
>
> I am sorry, but after this connect will return EINVAL.

Yes, I'm sorry too ;)
That was a damn stupid mistake on my part.

>
> It would be better if you showed all the related pieces
> of your program, doing operations between socket...sendmsg
> and socket...recvmsg on server side.

The entire source is available from http://ostenfeld.dtu.dk/~jakob/jobd/

It's a job distribution system for Beowulfs, the server needs the AF_UNIX
credentials to authenticate the local user.

The idea is, that a server has bound to a local UNIX socket, and will await
client connections. A server will listen for connections, accept() them, read
credentials, read data, and process the request.

I hope you can make out the idea from the code snippets below. This mail
is getting big for a list mail.

Server does: (this is C++, LOCALSOCK is a string(), thus the .c_str())
----------------------------
  localsock = socket(AF_UNIX, SOCK_STREAM, 0);
  if(localsock == -1) {
    log_info("Sorry, cannot create local socket");
    return;
  }
  
  unlink(LOCALSOCK.c_str());
  struct sockaddr_un addr;
  addr.sun_family = AF_UNIX;
  strcpy(addr.sun_path, LOCALSOCK.c_str());
  int rc = bind(localsock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
  if(rc) {
    log_info("Binding on local socket \"" + LOCALSOCK + "\" failed.");
    close(localsock);
    localsock = -1;
    return;
  }
  chmod(LOCALSOCK.c_str(), 0666);

  listen(localsock, 5);
----------------------------

Success so far.

Client does: (plain ANSI C)
----------------------------
 /* Connect and get a host suggestion */
  antsd = socket(AF_UNIX, SOCK_STREAM, 0);
  if(antsd == -1)
    fail("Cannot create AF_UNIX socket");

  addr.sun_family = AF_UNIX;
  strcpy(addr.sun_path, ANTSD_SOCKET);

  opt_val = 1;
  rc = setsockopt(antsd, SOL_SOCKET, SO_PASSCRED, &opt_val, sizeof(opt_val));
  if(rc)
    fail("Couldn't set SO_PASSCRED on antsd socket");

  rc = connect(antsd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un));
  if(rc)
    fail("Cannot connect to local antsd socket - antsd not running on localhost ?");
----------------------------

Client also succeedes.

Then server does: (after a select())
----------------------------
  int sock = accept(localsock, 0, 0);
  if(sock == -1) {
    log_info("Accepting connection from local socket failed");
    return;
  }

  connections.insert(sock);
  log_info("Accepted new connection on local socket");

  struct linger lng = {0, 0};
  int rc = setsockopt(sock, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng));
  if(rc)
    log_info("Cannot unset SO_LINGER on socket");

  unsigned bint = 1;
  rc = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &bint, sizeof(bint));
  if(rc)
    log_info("Cannot set SO_PASSCRED on socket");

  listen(localsock, 5);
----------------------------

All works.

Now Client sends data to the server. Just a plain send().
----------------------------
    /* Send request */
    rc = send(antsd, type, strlen(type), 0);
    if(rc != strlen(type))
      fail("Cannot send to local antsd socket");
----------------------------

Success again.

And finally server fails the recvmsg() in:
----------------------------
      const unsigned cmsg_bufsize = sizeof(struct ucred); // we only need sizeof(struct ucred) ourselves
      struct msghdr msg;
      struct cmsghdr * cmsgh;
      char ancbuf[CMSG_SPACE(cmsg_bufsize)];

      memset(&msg, 0, sizeof(msg));
      memset(&ancbuf, 0, CMSG_SPACE(cmsg_bufsize));
      msg.msg_control = ancbuf;
      msg.msg_controllen = cmsg_bufsize;

      int rc = recvmsg(*ci, &msg, 0);
      if(rc < 0) {
        log_info(std::string("Couldn't read ancillary data from jsh connection: ") + strerror(errno));
        expired.insert(*ci);
        continue;
      }
----------------------------

I get this error from the server:
  Couldn't read ancillary data from jsh connection: Operation not supported

If this is an error in my code, I sincerely apologize for clobbering up lkml
with this. I repeat though, that this code worked in 2.2 (currently runs in
production on four systems at work). I've had one success report from someone
else too, who installed and ran the code on a larger cluster.

Thanks a lot,

-- 
................................................................
: jakob@ostenfeld.dtu.dk  : And I see the elder races,         :
:.........................: putrid forms of man                :
:   Jakob Østergaard      : See him rise and claim the earth,  :
:        OZ9ABN           : his downfall is at hand.           :
:.........................:............{Konkhra}...............:

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jul 07 2000 - 21:00:11 EST