Solaris Trusted Extensions Developer's Guide

Using Multilevel Ports With UDP

The PORTMAPPER service described in the previous section is implemented by using UDP. Unlike TCP, UDP sockets are not connection oriented, so some ambiguity might arise about which credentials to use when replying to a client on a multilevel port. Therefore, the client's request socket must be explicitly associated with the server's reply packet. To make this association, use the SO_RECVUCRED socket option.

When SO_RECVUCRED is set on a UDP socket, the kernel UDP module can pass a label in a ucred structure as ancillary data to an application. The level and type values of the ucred are SOL_SOCKET and SCM_UCRED, respectively.

An application can handle this ucred structure in one of these ways:

The following code excerpt shows the reuse case.

/*
 * Find the SCM_UCRED in src and place a pointer to that
 * option alone in dest. Note that these two 'netbuf'
 * structures might be the same one, so the code has to
 * be careful about referring to src after changing dest.
 */
static void
extract_cred(const struct netbuf *src, struct netbuf *dest)
{
    char *cp = src->buf;
    unsigned int len = src->len;
    const struct T_opthdr *opt;
    unsigned int olen;

    while (len >= sizeof (*opt)) {
        /* LINTED: pointer alignment */
        opt = (const struct T_opthdr *)cp;
        olen = opt->len;
        if (olen > len || olen < sizeof (*opt) ||
            !IS_P2ALIGNED(olen, sizeof (t_uscalar_t)))
            break;
        if (opt->level == SOL_SOCKET &&
            opt->name == SCM_UCRED) {
            dest->buf = cp;
            dest->len = olen;
            return;
        }
        cp += olen;
        len -= olen;
    }
    dest->len = 0;
}

The following code excerpt shows how to access the user credential from the receiving buffer:

void
examine_udp_label()
{
    struct msghdr   recv_msg;
    struct cmsghdr  *cmsgp;
    char message[MAX_MSGLEN+1];
    char inmsg[MAX_MSGLEN+1];
    int on = 1;

    setsockopt(sockfd, SOL_SOCKET, SO_RECVUCRED, (void *)&on,
        sizeof (int));

    [...]

    while (1) {
       if (recvmsg(sockfd, &recv_msg, 0) < 0) {
           (void) fprintf(stderr, "recvmsg_errno:   %d\n", errno);
           exit(1);
           }

           /*
            * Check ucred in ancillary data
            */
           ucred = NULL;

           for (cmsgp = CMSG_FIRSTHDR(&recv_msg); cmsgp;
               cmsgp = CMSG_NXTHDR(&recv_msg, cmsgp)) {
               if (cmsgp->cmsg_level == SOL_SOCKET &&
                  cmsgp->cmsg_type == SCM_UCRED) {
                  ucred = (ucred_t *)CMSG_DATA(cmsgp);
                     break;
                     }

               if (ucred == NULL) {
                   (void) sprintf(&message[0],
                       "No ucred info in ancillary data with UDP");
               } else {
                   /*
                    * You might want to extract the label from the
                    * ucred by using ucred_getlabel(3C) here.
                    */
               }

           }

           [...]

           if (message != NULL)
               (void) strlcpy(&inmsg[0], message, MAX_MSGLEN);
           /*
            * Use the received message so that it will contain
            * the correct label
            */
           iov.iov_len = strlen(inmsg);
           ret = sendmsg(sockfd, &recv_msg, 0);
       }
}