Esempio n. 1
0
/*
 *  Create a credential info object from a Munge context
 */
static munge_info_t *
cred_info_create(munge_ctx_t ctx)
{
	munge_err_t e;
	munge_info_t *mi = cred_info_alloc();

	e = munge_ctx_get(ctx, MUNGE_OPT_ENCODE_TIME, &mi->encoded);
	if (e != EMUNGE_SUCCESS)
		error ("auth_munge: Unable to retrieve encode time: %s",
		       munge_ctx_strerror(ctx));

	e = munge_ctx_get(ctx, MUNGE_OPT_DECODE_TIME, &mi->decoded);
	if (e != EMUNGE_SUCCESS)
		error ("auth_munge: Unable to retrieve decode time: %s",
		       munge_ctx_strerror(ctx));

	e = munge_ctx_get(ctx, MUNGE_OPT_CIPHER_TYPE, &mi->cipher);
	if (e != EMUNGE_SUCCESS)
		error ("auth_munge: Unable to retrieve cipher type: %s",
		       munge_ctx_strerror(ctx));

	e = munge_ctx_get(ctx, MUNGE_OPT_MAC_TYPE, &mi->mac);
	if (e != EMUNGE_SUCCESS)
		error ("auth_munge: Unable to retrieve mac type: %s",
		       munge_ctx_strerror(ctx));

	e = munge_ctx_get(ctx, MUNGE_OPT_ZIP_TYPE, &mi->zip);
	if (e != EMUNGE_SUCCESS)
		error ("auth_munge: Unable to retrieve zip type: %s",
		       munge_ctx_strerror(ctx));

	return mi;
}
/* NOTE: Caller must xfree the signature returned by sig_pp */
extern int
crypto_sign(void * key, char *buffer, int buf_size, char **sig_pp,
	    unsigned int *sig_size_p)
{
	int retry = RETRY_COUNT, auth_ttl;
	char *cred;
	munge_err_t err;
	munge_ctx_t ctx = (munge_ctx_t) key;

	auth_ttl = slurm_get_auth_ttl();
	if (auth_ttl)
		(void) munge_ctx_set(ctx, MUNGE_OPT_TTL, auth_ttl);

    again:
	err = munge_encode(&cred, ctx, buffer, buf_size);
	if (err != EMUNGE_SUCCESS) {
		if ((err == EMUNGE_SOCKET) && retry--) {
			debug("Munge encode failed: %s (retrying ...)",
			      munge_ctx_strerror(ctx));
			usleep(RETRY_USEC);	/* Likely munged too busy */
			goto again;
		}
		if (err == EMUNGE_SOCKET)  /* Also see MUNGE_OPT_TTL above */
			error("If munged is up, restart with --num-threads=10");
		return err;
	}

	*sig_size_p = strlen(cred) + 1;
	*sig_pp = xstrdup(cred);
	free(cred);
	return 0;
}
extern int
crypto_verify_sign(void * key, char *buffer, unsigned int buf_size,
		   char *signature, unsigned int sig_size)
{
	int retry = RETRY_COUNT;
	uid_t uid;
	gid_t gid;
	void *buf_out = NULL;
	int   buf_out_size;
	int   rc = 0;
	munge_err_t err;
	munge_ctx_t ctx = (munge_ctx_t) key;

    again:
	err = munge_decode(signature, ctx, &buf_out, &buf_out_size,
			   &uid, &gid);

	if (err != EMUNGE_SUCCESS) {
		if ((err == EMUNGE_SOCKET) && retry--) {
			debug("Munge decode failed: %s (retrying ...)",
			      munge_ctx_strerror(ctx));
			usleep(RETRY_USEC);	/* Likely munged too busy */
			goto again;
		}
		if (err == EMUNGE_SOCKET)
			error("If munged is up, restart with --num-threads=10");

#ifdef MULTIPLE_SLURMD
		if (err != EMUNGE_CRED_REPLAYED) {
			rc = err;
			goto end_it;
		} else {
			debug2("We had a replayed crypto, but this "
			       "is expected in multiple slurmd mode.");
		}
#else
		if (err == EMUNGE_CRED_REPLAYED)
			rc = ESIG_CRED_REPLAYED;
		else
			rc = err;
		goto end_it;
#endif
	}


	if ((uid != slurm_user) && (uid != 0)) {
		error("crypto/munge: Unexpected uid (%d) != SLURM uid (%d)",
		      (int) uid, (int) slurm_user);
		rc = ESIG_BAD_USERID;
	}
	else if (buf_size != buf_out_size)
		rc = ESIG_BUF_SIZE_MISMATCH;
	else if (memcmp(buffer, buf_out, buf_size))
		rc = ESIG_BUF_DATA_MISMATCH;
end_it:
	if (buf_out)
		free(buf_out);
	return rc;
}
extern void *
crypto_read_private_key(const char *path)
{
	munge_ctx_t ctx;
	munge_err_t err;
	char *socket;
	int auth_ttl, rc;

	if ((ctx = munge_ctx_create()) == NULL) {
		error ("crypto_read_private_key: munge_ctx_create failed");
		return (NULL);
	}

	socket = _auth_opts_to_socket();
	if (socket) {
		rc = munge_ctx_set(ctx, MUNGE_OPT_SOCKET, socket);
		xfree(socket);
		if (rc != EMUNGE_SUCCESS) {
			error("munge_ctx_set failure");
			munge_ctx_destroy(ctx);
			return NULL;
		}
	}

	auth_ttl = slurm_get_auth_ttl();
	if (auth_ttl)
		(void) munge_ctx_set(ctx, MUNGE_OPT_TTL, auth_ttl);

	/*
	 *   Only allow slurmd_user (usually root) to decode job
	 *   credentials created by
	 *   slurmctld. This provides a slight layer of extra security,
	 *   as non-privileged users cannot get at the contents of job
	 *   credentials.
	 */
	err = munge_ctx_set(ctx, MUNGE_OPT_UID_RESTRICTION,
			    slurm_get_slurmd_user_id());

	if (err != EMUNGE_SUCCESS) {
		error("Unable to set uid restriction on munge credentials: %s",
		      munge_ctx_strerror (ctx));
		munge_ctx_destroy(ctx);
		return(NULL);
	}

	return ((void *) ctx);
}
Esempio n. 5
0
/*
 * Derived from the rcmd() libc call, with modified interface.
 * Is MT-safe if gethostbyname_r is defined.  
 * Connection can time out.
 *
 *	ahost (IN)		target hostname
 *      port (IN)               port to connect to
 *	remuser (IN)		remote username
 *	cmd (IN)		remote command to execute under shell
 *	fd2p (IN)		if non NULL, return stderr file descriptor here
 *	int (RETURN)		socket for I/O on success
 */
int 
mcmd(char **ahost, int port, char *remuser, char *cmd, int *fd2p, char *munge_socket)
{
    struct sockaddr m_socket;
    struct sockaddr_in *getp;
    struct sockaddr_in sin, from;
    struct sockaddr_storage ss;
    struct hostent *h_ent = NULL;
    struct in_addr m_in;
    unsigned int rand, randl;
    unsigned int randy = 0; 
    int s, s2, rv, mcount, lport;
    char c;
    char num[6] = {0};
    char *mptr;
    char *mbuf;
    char *tmbuf;
    char *m;
    char *mpvers;
    char num_seq[12] = {0};
    socklen_t len;
    sigset_t blockme;
    sigset_t oldset;
#ifdef HAVE_GETHOSTBYNAME_R_6
    struct hostent h_entry;
    int h_ent_bsize = HBUF_LEN;
    char h_ent_buf[HBUF_LEN] = {0};
#endif
    int h_ent_err = 0;
    unsigned char *hptr;
    char haddrdot[MAXHOSTNAMELEN + MRSH_LOCALHOST_KEYLEN + 1] = {0};
    munge_ctx_t ctx;

    sigemptyset(&blockme);
    sigaddset(&blockme, SIGURG);
    sigaddset(&blockme, SIGPIPE);
    SET_PTHREAD();

    if (fd2p != NULL) { 
        /*
         * Generate a random number to send in our package to the 
         * server.  We will see it again and compare it when the
         * server sets up the stderr socket and sends it to us.
         * We need to loop for the tiny possibility we read 0 :P
         */
        int rand_fd;
          
        if ((rand_fd = open ("/dev/urandom", O_RDONLY | O_NONBLOCK)) < 0) {
            perror("mcmd: Open of /dev/urandom failed");
            exit(1);
        }
	  
        do {
            if ((rv = read (rand_fd, &randy, sizeof(uint32_t))) < 0) {
                perror("mcmd: Read of /dev/urandom failed");
                close(rand_fd);
                exit(1);
            }
            if (rv < (int) (sizeof(uint32_t))) {
                perror("mcmd: Read returned too few bytes");
                close(rand_fd);
                exit(1);
            }
        } while (randy == 0);
        
        close(rand_fd);
    }

    /* Convert to decimal string, is 0 if we don't want stderr. */
    snprintf(num_seq, sizeof(num_seq),"%d",randy);

    /*
     * Start setup of the stdin/stdout socket...
     */
    lport = 0;
    len = sizeof(struct sockaddr_in);

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("mcmd: socket call stdout failed");
        exit(1);
    }

    memset (&ss, '\0', sizeof(ss));
    ss.ss_family = AF_INET;

    if (bind(s, (struct sockaddr *)&ss, len) < 0) { 
        perror("mcmd: bind failed");
        goto bad;
    }

    sin.sin_family = AF_INET;

#ifdef HAVE_GETHOSTBYNAME_R_6
    (void) gethostbyname_r(*ahost, &h_entry, &h_ent_buf[0], 
                           h_ent_bsize, &h_ent, &h_ent_err);
#else
    h_ent = gethostbyname(*ahost);
    h_ent_err = h_errno; 
#endif
    if (h_ent == NULL) {
        switch (h_ent_err) {
            case HOST_NOT_FOUND:
                fprintf(stderr,"mcmd: Hostname not found.\n");
                goto bad;
            case NO_ADDRESS:
                fprintf(stderr,"mcmd: Can't find IP address.\n");
                goto bad;
            case NO_RECOVERY:
                fprintf(stderr,"mcmd: A non-recoverable error.\n");
                goto bad;
            case TRY_AGAIN:
                fprintf(stderr,"mcmd: Error on name server.\n");
                goto bad;
            default:
                fprintf(stderr,"mcmd: Unknown error.\n");
                goto bad;
        }
    }

    memcpy(&sin.sin_addr.s_addr, *h_ent->h_addr_list, h_ent->h_length);
    sin.sin_port = port;
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        perror("mcmd: connect failed");
        goto bad;
    }

    /* save address in buffer */
    if ((strcmp(*ahost, "localhost") == 0)
        || (strcmp(*ahost, "127.0.0.1") == 0)) {
        /* Special case for localhost  */

        char hostname[MAXHOSTNAMELEN+1];

        memset(hostname, '\0', MAXHOSTNAMELEN+1);
        if (gethostname(hostname, MAXHOSTNAMELEN) < 0) {
            perror("mcmd: gethostname call failed");
            exit(1);
        }

        strncpy(haddrdot, MRSH_LOCALHOST_KEY, MRSH_LOCALHOST_KEYLEN);
        strncat(haddrdot, hostname, MAXHOSTNAMELEN);
    }
    else {
        memcpy(&m_in.s_addr, *h_ent->h_addr_list, h_ent->h_length);
        hptr = (unsigned char *) &m_in;
        sprintf(haddrdot, "%u.%u.%u.%u", hptr[0], hptr[1], hptr[2], hptr[3]);
    }

    lport = 0;
    s2 = -1;
    if (fd2p != NULL) {
        /*
         * Start the socket setup for the stderr.
         */
        struct sockaddr_in sin2;

        if ((s2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            perror("mcmd: socket call for stderr failed");
            goto bad;
        }

        memset (&sin2, 0, sizeof(sin2));
        sin2.sin_family = AF_INET;
        sin2.sin_addr.s_addr = htonl(INADDR_ANY);
        sin2.sin_port = 0;
        if (bind(s2, (struct sockaddr *)&sin2, sizeof(sin2)) < 0) {
            perror("mcmd: bind failed");
            close(s2);
            goto bad;
        }
		
        len = sizeof(struct sockaddr);

        /*
         * Retrieve our port number so we can hand it to the server
         * for the return (stderr) connection...
         */
        if (getsockname(s2,&m_socket,&len) < 0) {
            perror("mcmd: getsockname failed");
            close(s2);
            goto bad;
        }

        getp = (struct sockaddr_in *)&m_socket;
        lport = ntohs(getp->sin_port);

        if (listen(s2, 5) < 0) {
            perror("mcmd: listen() failed");
            close(s2);
            goto bad;
        }
    }

    /* put port in buffer. will be 0 if user didn't want stderr */
    snprintf(num,sizeof(num),"%d",lport);

    /*
     * We call munge_encode which will take what we write in and
     * return a pointer to an munged buffer.  What we get back is
     * a null terminated string of encrypted characters.
     * 
     * The format of the unmunged buffer is as follows (each a
     * string terminated with a '\0' (null):
     *
     * stderr_port_number & random_number are 0 if user did not
     * request stderr socket
     *
     *                                     SIZE            EXAMPLE
     *                                     ==========      =============
     * remote_user_name                    variable        "mhaskell"
     * '\0'
     * protocol version                    < 12 bytes      "1.2"
     * '\0'
     * IP address of requestor [1]         7-15 bytes      "134.9.11.155" 
     * '\0'
     * stderr_port_number                  4-8 bytes       "50111"
     * '\0'
     * random_number                       1-8 bytes       "1f79ca0e"
     * '\0'
     * users_command                       variable        "ls -al"
     * '\0' '\0'
     *
     * (The last extra null is accounted for in the following
     * line's last strlen() call.)
     *
     * [1] - With the exception when 127.0.0.1 or "localhost" are
     * input by the user. In that situation, the MRSH_LOCALHOST_KEY
     * and hostname are concatenated and the size may be much larger
     * than 7-15 bytes.
     */

    mpvers = MRSH_PROTOCOL_VERSION;
    
    mcount = ((strlen(remuser)+1) + (strlen(mpvers)+1) + 
              (strlen(haddrdot)+1) + (strlen(num)+1) + 
              (strlen(num_seq)+1) + strlen(cmd)+2);
    tmbuf = mbuf = malloc(mcount);
    if (tmbuf == NULL) {
        perror("mcmd: Error from malloc");
        close(s2);
        goto bad;
    }

    /*
     * The following memset() call takes the extra trailing null
     * as part of its count as well.
     */
    memset(mbuf,0,mcount);

    mptr = strcpy(mbuf, remuser);
    mptr += strlen(remuser)+1;
    mptr = strcpy(mptr, mpvers);
    mptr += strlen(mpvers)+1;
    mptr = strcpy(mptr, haddrdot);
    mptr += strlen(haddrdot)+1;
    mptr = strcpy(mptr, num);
    mptr += strlen(num)+1;
    mptr = strcpy(mptr, num_seq);
    mptr += strlen(num_seq)+1;
    mptr = strcpy(mptr, cmd);

    if ((ctx = munge_ctx_create()) == NULL) {
        fprintf(stderr, "munge_ctx_create: %s\n", strerror(errno));
        close(s2);
        free(tmbuf);
        goto bad;
    }

    if (munge_socket) {
        if ((rv = munge_ctx_set (ctx, 
                                 MUNGE_OPT_SOCKET, 
                                 munge_socket)) != EMUNGE_SUCCESS) {
            fprintf(stderr,"munge_ctx_set: %s\n", munge_ctx_strerror(ctx));
            munge_ctx_destroy(ctx);
            close(s2);
            free(tmbuf);
            goto bad;
        }
    }

    if ((rv = munge_encode(&m,ctx,mbuf,mcount)) != EMUNGE_SUCCESS) {
        fprintf(stderr,"munge_encode: %s\n", munge_ctx_strerror(ctx));
        munge_ctx_destroy(ctx);
        close(s2);
        free(tmbuf);
        goto bad;
    }
    
    munge_ctx_destroy(ctx);

    mcount = (strlen(m)+1);

    /*
     * Write stderr port in the clear in case we can't decode for
     * some reason (i.e. bad credentials).  May be 0 if user
     * doesn't want stderr.
     */
    if (fd2p != NULL) {
        rv = fd_write_n(s, num, strlen(num)+1);
        if (rv != (ssize_t)(strlen(num)+1)) {
            free(m);
            free(tmbuf);
            if (rv == -1) {
                if (errno == EPIPE)
                    perror("mcmd: Lost connection (EPIPE)");
                else
                    perror("mcmd: Write of stderr port");
            }
            else
                fprintf(stderr, "mcmd: write incorrect number of bytes.\n");
            close(s2);
            goto bad;
        }
    }
    else {
        write(s, "", 1);
        lport = 0;
    }
    
    /*
     * Write the munge_encoded blob to the socket.
     */
    if ((rv = fd_write_n(s, m, mcount)) != mcount) {
        free(m);
        free(tmbuf);
        if (rv == -1) {
            if (errno == EPIPE)
                perror("mcmd: Lost connection (EPIPE)");
            else
                perror("mcmd: Write of munge data");
        }
        else
            fprintf(stderr, "mcmd: write incorrect number of bytes.\n");
        close(s2);
        goto bad;
    }

    free(m);
    free(tmbuf);

    if (fd2p != NULL) {
        /* 
         * Wait for stderr connection from daemon.  
         */
        int maxfd, s3; 
        fd_set reads;
        
        errno = 0;
        FD_ZERO(&reads);
        FD_SET(s, &reads);
        FD_SET(s2, &reads);
        maxfd = (s > s2) ? s : s2;
        if (select(maxfd + 1, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) {
            if (errno != 0)
                perror("mcmd: Select failed (setting up stderr)");
            else {
                char buf[100];
                int rv = read(s, buf, 100);
                if (rv == 0)
                    fprintf(stderr, "mcmd: Connection closed by remote host.\n");
                else if (rv > 0) 
                    fprintf(stderr, "mcmd: Protocol failure in circuit setup.\n");
                else /* rv < 0 */
                    fprintf(stderr, "mcmd: %s\n", strerror(errno));
            }
            close(s2);
            goto bad;
        }

        errno = 0;
        len = sizeof(from); /* arg to accept */
        
        if ((s3 = accept(s2, (struct sockaddr *)&from, &len)) < 0) {
            perror("mcmd: accept (stderr) failed");
            close(s2);
            goto bad;
        }

        if (from.sin_family != AF_INET) {
            fprintf(stderr, "mcmd: bad family type: %d\n", from.sin_family);
            goto bad2;      
        }

        close(s2);

        /*
         * The following fixes a race condition between the daemon
         * and the client.  The daemon is waiting for a null to
         * proceed.  We do this to make sure that we have our
         * socket is up prior to the daemon running the command.
         */
        if (write(s,"",1) != 1) { 
            perror("mcmd: Could not communicate to daemon to proceed");
            close(s3);
            goto bad;
        }

        /*
         * Read from our stderr.  The server should have placed
         * our random number we generated onto this socket.
         */
        rv = fd_read_n(s3, &rand, sizeof(rand));
        if (rv <= 0) {
            if (rv == 0)
                perror("mcmd: Connection closed by remote host");
            else
                perror("mcmd: Bad read of verification number");
            close(s3);
            goto bad;
        }

        randl = ntohl(rand);
        if (randl != randy) {
            char tmpbuf[LINEBUFSIZE] = {0};
            char *tptr = &tmpbuf[0];

            memcpy(tptr,(char *) &rand,sizeof(rand));
            tptr += sizeof(rand);
            if ((fd_read_line (s3, tptr, LINEBUFSIZE - sizeof(rand))) < 0) {
                perror("mcmd: Read error from remote host");
                close(s3);
                goto bad;
            }
            /* Legacy rsh may consider the first byte an error code,
             * so don't output this byte.
             */
            if (tmpbuf[0] == '\01')
              tptr = &tmpbuf[1];
            else
              tptr = &tmpbuf[0];
            fprintf(stderr,"mcmd error returned: %s\n", tptr);
            close(s3);
            goto bad;
        }

        /*
         * Set the stderr file descriptor for the user...
         */
        *fd2p = s3;
    }

    if ((rv = read(s, &c, 1)) < 0) {
        perror("mcmd: read: protocol failure"); 
        goto bad2;
    }

    if (rv != 1) {
        fprintf(stderr, "mcmd: read: protocol failure: invalid response.\n");
        goto bad2;
    }

    if (c != '\0') {
        /* retrieve error string from remote server */
        char tmpbuf[LINEBUFSIZE];
      
        if (fd_read_line (s, &tmpbuf[0], LINEBUFSIZE ) < 0) {
            perror("mcmd: Error from remote host");
            goto bad2;
        }
        fprintf(stderr,"mcmd error returned: %s\n",&tmpbuf[0]);
        goto bad2;
    }
    RESTORE_PTHREAD();
    return (s);

 bad2:
    if (lport)
        close(*fd2p);
 bad:
    close(s);
    RESTORE_PTHREAD();
    exit(1);
}
Esempio n. 6
0
int PBSD_munge_authenticate(

  int psock,  /* I */
  int handle) /* I */

  {
  int                 rc;

  munge_ctx_t         mctx = NULL;
  munge_err_t         mret = EMUNGE_SNAFU;
  char               *mcred = NULL;

  /* user id and name stuff */
  struct passwd      *pwent;
  uid_t               myrealuid;
  struct batch_reply *reply;
  unsigned short      user_port = 0;
  struct sockaddr_in  sockname;
  socklen_t           socknamelen = sizeof(sockname);
  struct tcp_chan    *chan;

  if ((mctx = munge_ctx_create()) == NULL)
    {
    return(-1);
    }

  if ((mret = munge_encode (&mcred, mctx, NULL, 0)) != EMUNGE_SUCCESS)
    {
    const char *merrmsg = NULL;
    if (!(merrmsg = munge_ctx_strerror(mctx)))
      {
      merrmsg = munge_strerror(mret);
      }

    fprintf(stderr, "munge_encode failed: %s (%d)\n", merrmsg, mret);
    munge_ctx_destroy(mctx);
    return(PBSE_MUNGE_NOT_FOUND); /*TODO more fine-grained error codes? */
    }
  
  munge_ctx_destroy(mctx);

  /* We got the certificate. Now make the PBS_BATCH_AltAuthenUser request */
  myrealuid = getuid();
  pwent = getpwuid(myrealuid);
  
  rc = getsockname(psock, (struct sockaddr *)&sockname, &socknamelen);
  
  if (rc == -1)
    {
    fprintf(stderr, "getsockname failed: %d\n", errno);
    return(-1);
    }
  
  user_port = ntohs(sockname.sin_port);
  
  if ((chan = DIS_tcp_setup(psock)) == NULL)
    {
    }
  else if ((rc = encode_DIS_ReqHdr(chan, PBS_BATCH_AltAuthenUser, pwent->pw_name)) ||
           (rc = diswui(chan, user_port)) ||
           (rc = diswst(chan, mcred)) ||
           (rc = encode_DIS_ReqExtend(chan, NULL)) ||
           (rc = DIS_tcp_wflush(chan)))
    {
    PBSD_munge_cred_destroy(&mcred);
    /* ERROR */
    return(rc);
    }
  else
    {
    int local_err = PBSE_NONE;
    PBSD_munge_cred_destroy(&mcred);
    /* read the reply */
    if ((reply = PBSD_rdrpy(&local_err, handle)) != NULL)
      free(reply);
    
    return(PBSE_NONE);
    }

  return(-1);
  }
Esempio n. 7
0
/*
 * Derived from the mcmd() libc call, with modified interface.
 * This version is MT-safe.  Errors are displayed in pdsh-compat format.
 * Connection can time out.
 *      ahost (IN)              target hostname
 *      addr (IN)               4 byte internet address
 *      locuser (IN)            local username
 *      remuser (IN)            remote username
 *      cmd (IN)                remote command to execute under shell
 *      rank (IN)               not used 
 *      fd2p (IN)               if non NULL, return stderr file descriptor here
 *      int (RETURN)            -1 on error, socket for I/O on success
 *
 * Originally by Mike Haskell for mrsh, modified slightly to work with pdsh by:
 * - making mcmd always thread safe
 * - using "err" function output errors.
 * - passing in address as addr intead of calling gethostbyname
 * - using default mshell port instead of calling getservbyname
 * 
 */
static int 
mcmd(char *ahost, char *addr, char *locuser, char *remuser, char *cmd, 
        int rank, int *fd2p, void **argp)
{
    struct sockaddr m_socket;
    struct sockaddr_in *getp;
    struct sockaddr_in sin, from;
    struct sockaddr_storage ss;
    struct in_addr m_in;
    unsigned int rand, randl;
    unsigned char *hptr;
    int s, s2, rv, mcount, lport;
    char c;
    char num[6] = {0};
    char *mptr;
    char *mbuf;
    char *tmbuf;
    char *m;
    char *mpvers;
    char num_seq[12] = {0};
    socklen_t len;
    sigset_t blockme;
    sigset_t oldset;
    char haddrdot[MAXHOSTNAMELEN + MRSH_LOCALHOST_KEYLEN + 1] = {0};
    munge_ctx_t ctx;
    struct xpollfd xpfds[2];

    memset (xpfds, 0, sizeof (xpfds));
    memset (&sin, 0, sizeof (sin));

    sigemptyset(&blockme);
    sigaddset(&blockme, SIGURG);
    sigaddset(&blockme, SIGPIPE);
    SET_PTHREAD();

    /* Convert randy to decimal string, 0 if we dont' want stderr */
    if (fd2p != NULL)
        snprintf(num_seq, sizeof(num_seq),"%d",randy);
    else
        snprintf(num_seq, sizeof(num_seq),"%d",0);

    /*
     * Start setup of the stdin/stdout socket...
     */
    lport = 0;
    len = sizeof(struct sockaddr_in);

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        err("%p: %S: mcmd: socket call stdout failed: %m\n", ahost);
        EXIT_PTHREAD();
    }

    memset (&ss, '\0', sizeof(ss));
    ss.ss_family = AF_INET;

    if (bind(s, (struct sockaddr *)&ss, len) < 0) {
        err("%p: %S: mcmd: bind failed: %m\n", ahost);
        goto bad;
    }

    sin.sin_family = AF_INET;

    memcpy(&sin.sin_addr.s_addr, addr, IP_ADDR_LEN); 

    sin.sin_port = htons(MRSH_PORT);
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        err("%p: %S: mcmd: connect failed: %m\n", ahost);
        goto bad;
    }

    lport = 0;
    s2 = -1;
    if (fd2p != NULL) {
        /*
         * Start the socket setup for the stderr.
         */
        struct sockaddr_in sin2;

        if ((s2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            err("%p: %S: mcmd: socket call for stderr failed: %m\n", ahost);
            goto bad;
        }

        memset (&sin2, 0, sizeof(sin2));
        sin2.sin_family = AF_INET;
        sin2.sin_addr.s_addr = htonl(INADDR_ANY);
        sin2.sin_port = 0;
        if (bind(s2,(struct sockaddr *)&sin2, sizeof(sin2)) < 0) {
            err("%p: %S: mcmd: bind failed: %m\n", ahost);
            close(s2);
            goto bad;
        }

        len = sizeof(struct sockaddr);

        /*
         * Retrieve our port number so we can hand it to the server
         * for the return (stderr) connection...
         */

        /* getsockname is thread safe */
        if (getsockname(s2,&m_socket,&len) < 0) {
            err("%p: %S: mcmd: getsockname failed: %m\n", ahost);
            close(s2);
            goto bad;
        }

        getp = (struct sockaddr_in *)&m_socket;
        lport = ntohs(getp->sin_port);

        if (listen(s2, 5) < 0) {
            err("%p: %S: mcmd: listen() failed: %m\n", ahost);
            close(s2);
            goto bad;
        }
    }

    /* put port in buffer. will be 0 if user didn't want stderr */
    snprintf(num,sizeof(num),"%d",lport);

    /* 
     * Use special keyed string if target is localhost, otherwise,
     *  encode the IP addr string.
     */
    if (!encode_localhost_string (ahost, haddrdot, sizeof (haddrdot))) {
        /* inet_ntoa is not thread safe, so we use the following, 
         * which is more or less ripped from glibc
         */
        memcpy(&m_in.s_addr, addr, IP_ADDR_LEN);
        hptr = (unsigned char *)&m_in;
        sprintf(haddrdot, "%u.%u.%u.%u", hptr[0], hptr[1], hptr[2], hptr[3]);
    }

    /*
     * We call munge_encode which will take what we write in and return a
     * pointer to an munged buffer.  What we get back is a null terminated
     * string of encrypted characters.
     * 
     * The format of the unmunged buffer is as follows (each a string terminated 
     * with a '\0' (null):
     *
     * stderr_port_number & /dev/urandom_client_produce_number are 0
     * if user did not request stderr socket
     *                                            SIZE            EXAMPLE
     *                                            ==========      =============
     * remote_user_name                           variable        "mhaskell"
     * '\0'
     * protocol version                           < 12 bytes      "1.2"
     * '\0'
     * dotted_decimal_address_of_this_server      7-15 bytes      "134.9.11.155"
     * '\0'
     * stderr_port_number                         4-8 bytes       "50111"
     * '\0'
     * /dev/urandom_client_produced_number        1-8 bytes       "1f79ca0e"
     * '\0'
     * users_command                              variable        "ls -al"
     * '\0' '\0'
     *
     * (The last extra null is accounted for in the following line's 
     *  last strlen() call.)
     *
     */

    mpvers = MRSH_PROTOCOL_VERSION;

    mcount = ((strlen(remuser)+1) + (strlen(mpvers)+1) + 
              (strlen(haddrdot)+1) + (strlen(num)+1) + 
              (strlen(num_seq)+1) + strlen(cmd)+2);

    tmbuf = mbuf = malloc(mcount);
    if (tmbuf == NULL) {
        err("%p: %S: mcmd: Error from malloc\n", ahost);
        close(s2);
        goto bad;
    }

    /*
     * The following memset() call takes the extra trailing null as
     * part of its count as well.
     */
    memset(mbuf,0,mcount);

    mptr = strcpy(mbuf, remuser);
    mptr += strlen(remuser)+1;
    mptr = strcpy(mptr, mpvers);
    mptr += strlen(mpvers)+1;
    mptr = strcpy(mptr, haddrdot);
    mptr += strlen(haddrdot)+1;
    mptr = strcpy(mptr, num);
    mptr += strlen(num)+1;
    mptr = strcpy(mptr, num_seq);
    mptr += strlen(num_seq)+1;
    mptr = strcpy(mptr, cmd);

    ctx = munge_ctx_create();

    if ((rv = munge_encode(&m,ctx,mbuf,mcount)) != EMUNGE_SUCCESS) {
        err("%p: %S: mcmd: munge_encode: %s\n", ahost, munge_ctx_strerror(ctx));
        munge_ctx_destroy(ctx);
        if (s2 >= 0) 
            close(s2);
        free(tmbuf);
        goto bad;
    }

    munge_ctx_destroy(ctx);

    mcount = (strlen(m)+1);

    /*
     * Write stderr port in the clear in case we can't decode for
     * some reason (i.e. bad credentials).  May be 0 if user 
     * doesn't want stderr
     */
    if (fd2p != NULL) {
        rv = fd_write_n(s, num, strlen(num)+1);
        if (rv != (strlen(num) + 1)) {
            free(m);
            free(tmbuf);
            if (errno == EPIPE)
                err("%p: %S: mcmd: Lost connection (EPIPE): %m", ahost);
            else
                err("%p: %S: mcmd: Write of stderr port failed: %m\n", ahost);
            close(s2);
            goto bad;
        }
    } else {
        write(s, "", 1);
        lport = 0;
    }

    /*
     * Write the munge_encoded blob to the socket.
     */
    rv = fd_write_n(s, m, mcount);
    if (rv != mcount) {
        free(m);
        free(tmbuf);
        if (errno == EPIPE)
            err("%p: %S: mcmd: Lost connection: %m\n", ahost);
        else
            err("%p: %S: mcmd: Write to socket failed: %m\n", ahost);
        close(s2);
        goto bad;
    }

    free(m);
    free(tmbuf);

    if (fd2p != NULL) {
        /*
         * Wait for stderr connection from daemon.
         */
        int s3;

        errno = 0;
        xpfds[0].fd = s;
        xpfds[1].fd = s2;
        xpfds[0].events = xpfds[1].events = XPOLLREAD;
        if (  ((rv = xpoll(xpfds, 2, -1)) < 0) 
            || rv != 1 
            || (xpfds[0].revents > 0)) {
            if (errno != 0)
                err("%p: %S: mcmd: xpoll (setting up stderr): %m\n", ahost);
            else
                err("%p: %S: mcmd: xpoll: protocol failure in circuit setup\n",
                     ahost);
            (void) close(s2);
            goto bad;
        }

        errno = 0;
        len = sizeof(from); /* arg to accept */

        if ((s3 = accept(s2, (struct sockaddr *)&from, &len)) < 0) {
            err("%p: %S: mcmd: accept (stderr) failed: %m\n", ahost);
            close(s2);
            goto bad;
        }

        if (from.sin_family != AF_INET) {
            err("%p: %S: mcmd: bad family type: %d\n", ahost, from.sin_family);
            goto bad2;
        }

        close(s2);

        /*
         * The following fixes a race condition between the daemon
         * and the client.  The daemon is waiting for a null to
         * proceed.  We do this to make sure that we have our
         * socket is up prior to the daemon running the command.
         */
        if (write(s,"",1) < 0) {
            err("%p: %S: mcmd: Could not communicate to daemon to proceed: %m\n", ahost);
            close(s3);
            goto bad;
        }

        /*
         * Read from our stderr.  The server should have placed our
         * random number we generated onto this socket.
         */
        rv = fd_read_n(s3, &rand, sizeof(rand));
        if (rv != (ssize_t) (sizeof(rand))) {
            err("%p: %S: mcmd: Bad read of expected verification "
                    "number off of stderr socket: %m\n", ahost);
            close(s3);
            goto bad;
        }

        randl = ntohl(rand);
        if (randl != randy) {
            char tmpbuf[LINEBUFSIZE] = {0};
            char *tptr = &tmpbuf[0];

            memcpy(tptr,(char *) &rand,sizeof(rand));
            tptr += sizeof(rand);
            if (fd_read_line (s3, tptr, LINEBUFSIZE) < 0)
                err("%p: %S: mcmd: Read error from remote host: %m\n", ahost);
            else
                err("%p: %S: mcmd: Error: %s\n", ahost, &tmpbuf[0]);
            close(s3);
            goto bad;
        }

        /*
         * Set the stderr file descriptor for the user...
         */
        *fd2p = s3;
    }

    if ((rv = read(s, &c, 1)) < 0) {
        err("%p: %S: mcmd: read: protocol failure: %m\n", ahost);
        goto bad2;
    }

    if (rv != 1) {
        err("%p: %S: mcmd: read: protocol failure: invalid response\n", ahost);
        goto bad2;
    }

    if (c != '\0') {
        /* retrieve error string from remote server */
        char tmpbuf[LINEBUFSIZE];

        if (fd_read_line (s, &tmpbuf[0], LINEBUFSIZE) < 0)
            err("%p: %S: mcmd: Error from remote host\n", ahost);
        else
            err("%p: %S: mcmd: Error: %s\n", ahost, tmpbuf);
        goto bad2;
    }
    RESTORE_PTHREAD();

    return (s);

bad2:
    if (lport)
        close(*fd2p);
bad:
    close(s);
    EXIT_PTHREAD();
}
Esempio n. 8
0
/*
 * Decode the munge encoded credential `m_str' placing results, if validated,
 * into slurm credential `c'
 */
static int
_decode_cred(slurm_auth_credential_t *c, char *socket)
{
	int retry = 2;
	munge_err_t e;
	munge_ctx_t ctx;

	if (c == NULL)
		return SLURM_ERROR;

	xassert(c->magic == MUNGE_MAGIC);

	if (c->verified)
		return SLURM_SUCCESS;

	if ((ctx = munge_ctx_create()) == NULL) {
		error("munge_ctx_create failure");
		return SLURM_ERROR;
	}
	if (socket &&
	    (munge_ctx_set(ctx, MUNGE_OPT_SOCKET, socket) != EMUNGE_SUCCESS)) {
		error("munge_ctx_set failure");
		munge_ctx_destroy(ctx);
		return SLURM_ERROR;
	}

    again:
	c->buf = NULL;
	e = munge_decode(c->m_str, ctx, &c->buf, &c->len, &c->uid, &c->gid);
	if (e != EMUNGE_SUCCESS) {
		if (c->buf) {
			free(c->buf);
			c->buf = NULL;
		}
		if ((e == EMUNGE_SOCKET) && retry--) {
			error ("Munge decode failed: %s (retrying ...)",
				munge_ctx_strerror(ctx));
#ifdef MULTIPLE_SLURMD
			sleep(1);
#endif
			goto again;
		}
#ifdef MULTIPLE_SLURMD
		/* In multple slurmd mode this will happen all the
		 * time since we are authenticating with the same
		 * munged.
		 */
		if (e != EMUNGE_CRED_REPLAYED) {
#endif
			/*
			 *  Print any valid credential data
			 */
			error ("Munge decode failed: %s",
			       munge_ctx_strerror(ctx));
			_print_cred(ctx);
			if (e == EMUNGE_CRED_REWOUND)
				error("Check for out of sync clocks");

			c->cr_errno = e + MUNGE_ERRNO_OFFSET;
#ifdef MULTIPLE_SLURMD
		} else {
			debug2("We had a replayed cred, "
			       "but this is expected in multiple "
			       "slurmd mode.");
			e = 0;
		}
#endif
		goto done;
	}

	c->verified = true;

     done:
	munge_ctx_destroy(ctx);
	return e ? SLURM_ERROR : SLURM_SUCCESS;
}
Esempio n. 9
0
/*
 * Allocate a credential.  This function should return NULL if it cannot
 * allocate a credential.  Whether the credential is populated with useful
 * data at this time is implementation-dependent.
 */
slurm_auth_credential_t *
slurm_auth_create( void *argv[], char *socket )
{
	int retry = 2;
	slurm_auth_credential_t *cred = NULL;
	munge_err_t e = EMUNGE_SUCCESS;
	munge_ctx_t ctx = munge_ctx_create();
	SigFunc *ohandler;

	if (ctx == NULL) {
		error("munge_ctx_create failure");
		return NULL;
	}

#if 0
	/* This logic can be used to determine what socket is used by default.
	 * A typical name is "/var/run/munge/munge.socket.2" */
{
	char *old_socket;
	if (munge_ctx_get(ctx, MUNGE_OPT_SOCKET, &old_socket) != EMUNGE_SUCCESS)
		error("munge_ctx_get failure");
	else
		info("Default Munge socket is %s", old_socket);
}
#endif
	if (socket &&
	    (munge_ctx_set(ctx, MUNGE_OPT_SOCKET, socket) != EMUNGE_SUCCESS)) {
		error("munge_ctx_set failure");
		munge_ctx_destroy(ctx);
		return NULL;
	}

	cred = xmalloc(sizeof(*cred));
	cred->verified = false;
	cred->m_str    = NULL;
	cred->buf      = NULL;
	cred->len      = 0;
	cred->cr_errno = SLURM_SUCCESS;

	xassert(cred->magic = MUNGE_MAGIC);

	/*
	 *  Temporarily block SIGALARM to avoid misleading
	 *    "Munged communication error" from libmunge if we
	 *    happen to time out the connection in this secion of
	 *    code.
	 */
	ohandler = xsignal(SIGALRM, SIG_BLOCK);

    again:
	e = munge_encode(&cred->m_str, ctx, cred->buf, cred->len);
	if (e != EMUNGE_SUCCESS) {
		if ((e == EMUNGE_SOCKET) && retry--) {
			error ("Munge encode failed: %s (retrying ...)",
				munge_ctx_strerror(ctx));
#ifdef MULTIPLE_SLURMD
			sleep(1);
#endif
			goto again;
		}

		error("Munge encode failed: %s", munge_ctx_strerror(ctx));
		xfree( cred );
		cred = NULL;
		plugin_errno = e + MUNGE_ERRNO_OFFSET;
	}

	xsignal(SIGALRM, ohandler);

	munge_ctx_destroy(ctx);

	return cred;
}
Esempio n. 10
0
File: remunge.c Progetto: dun/munge
void
parse_cmdline (conf_t conf, int argc, char **argv)
{
/*  Parses the command-line, altering the configuration [conf] as specified.
 */
    char          *prog;
    int            c;
    char          *p;
    int            i;
    long int       l;
    unsigned long  u;
    int            multiplier;
    munge_err_t    e;

    opterr = 0;                         /* suppress default getopt err msgs */

    prog = (prog = strrchr (argv[0], '/')) ? prog + 1 : argv[0];

    for (;;) {

        c = getopt_long (argc, argv, short_opts, long_opts, NULL);

        if (c == -1) {                  /* reached end of option list */
            break;
        }
        switch (c) {
            case 'h':
                display_help (prog);
                exit (EMUNGE_SUCCESS);
                break;
            case 'L':
                display_license ();
                exit (EMUNGE_SUCCESS);
                break;
            case 'V':
                display_version ();
                exit (EMUNGE_SUCCESS);
                break;
            case 'q':
                g_got_quiet = 1;
                break;
            case 'c':
                i = munge_enum_str_to_int (MUNGE_ENUM_CIPHER, optarg);
                if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_CIPHER, i)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid cipher type \"%s\"", optarg);
                }
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_CIPHER_TYPE, i);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set cipher type: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 'C':
                display_strings ("Cipher types", MUNGE_ENUM_CIPHER);
                exit (EMUNGE_SUCCESS);
                break;
            case 'm':
                i = munge_enum_str_to_int (MUNGE_ENUM_MAC, optarg);
                if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_MAC, i)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid MAC type \"%s\"", optarg);
                }
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_MAC_TYPE, i);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set MAC type: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 'M':
                display_strings ("MAC types", MUNGE_ENUM_MAC);
                exit (EMUNGE_SUCCESS);
                break;
            case 'z':
                i = munge_enum_str_to_int (MUNGE_ENUM_ZIP, optarg);
                if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_ZIP, i)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid compression type \"%s\"", optarg);
                }
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_ZIP_TYPE, i);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set compression type: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 'Z':
                display_strings ("Compression types", MUNGE_ENUM_ZIP);
                exit (EMUNGE_SUCCESS);
                break;
            case 'e':
                conf->do_decode = 0;
                break;
            case 'd':
                conf->do_decode = 1;
                break;
            case 'l':
                errno = 0;
                l = strtol (optarg, &p, 10);
                if ((optarg == p) || ((*p != '\0') && (*(p+1) != '\0'))
                        || (l < 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid number of bytes '%s'", optarg);
                }
                if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum number of %d bytes", INT_MAX);
                }
                if (!(multiplier = get_si_multiple (*p))) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid number specifier '%c'", *p);
                }
                if (l > (INT_MAX / multiplier)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum number of %d bytes", INT_MAX);
                }
                conf->num_payload = (int) (l * multiplier);
                break;
            case 'u':
                if (query_uid (optarg, (uid_t *) &i) < 0) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Unrecognized user \"%s\"", optarg);
                }
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_UID_RESTRICTION, i);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set UID restriction: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 'g':
                if (query_gid (optarg, (gid_t *) &i) < 0) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Unrecognized group \"%s\"", optarg);
                }
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_GID_RESTRICTION, i);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set GID restriction: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 't':
                errno = 0;
                l = strtol (optarg, &p, 10);
                if ((optarg == p) || (*p != '\0') || (l < -1)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid time-to-live '%s'", optarg);
                }
                if ((errno == ERANGE) && (l == LONG_MAX)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Overflowed maximum time-to-live of %ld seconds",
                        LONG_MAX);
                }
                if (l > UINT_MAX) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum time-to-live of %u seconds",
                        UINT_MAX);
                }
                if (l == -1) {
                    l = MUNGE_TTL_MAXIMUM;
                }
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_TTL, (int) l);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set time-to-live: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 'S':
                e = munge_ctx_set (conf->ctx, MUNGE_OPT_SOCKET, optarg);
                if (e != EMUNGE_SUCCESS) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to set munge socket name: %s",
                        munge_ctx_strerror (conf->ctx));
                }
                break;
            case 'D':
                errno = 0;
                l = strtol (optarg, &p, 10);
                if ((optarg == p) || ((*p != '\0') && (*(p+1) != '\0'))
                        || (l <= 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid duration '%s'", optarg);
                }
                if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum duration of %d seconds", INT_MAX);
                }
                if (!(multiplier = get_time_multiple (*p))) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid duration specifier '%c'", *p);
                }
                if (l > (INT_MAX / multiplier)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum duration of %d seconds", INT_MAX);
                }
                conf->num_seconds = (int) (l * multiplier);
                break;
            case 'N':
                errno = 0;
                u = strtoul (optarg, &p, 10);
                if ((optarg == p) || ((*p != '\0') && (*(p+1) != '\0'))
                        || (u == 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid number of credentials '%s'", optarg);
                }
                if ((errno == ERANGE) && (u == ULONG_MAX)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum number of %lu credentials",
                        ULONG_MAX);
                }
                if (!(multiplier = get_si_multiple (*p))) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid number specifier '%c'", *p);
                }
                if (u > (ULONG_MAX / multiplier)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum number of %lu credentials",
                        ULONG_MAX);
                }
                conf->num_creds = u * multiplier;
                break;
            case 'T':
                errno = 0;
                l = strtol (optarg, &p, 10);
                if ((optarg == p) || (*p != '\0') || (l <= 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid number of threads '%s'", optarg);
                }
                if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)
                        || (l > conf->max_threads)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum number of %d thread%s",
                        conf->max_threads,
                        (conf->max_threads == 1) ? "" : "s");
                }
                conf->num_threads = (int) l;
                break;
            case 'W':
                errno = 0;
                l = strtol (optarg, &p, 10);
                if ((optarg == p) || (*p != '\0') || (l <= 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid number of seconds '%s'", optarg);
                }
                if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Exceeded maximum number of %d seconds", INT_MAX);
                }
                conf->warn_time = (int) l;
                break;
            case '?':
                if (optopt > 0) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid option \"-%c\"", optopt);
                }
                else if (optind > 1) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Invalid option \"%s\"", argv[optind - 1]);
                }
                else {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to process command-line");
                }
                break;
            case ':':
                if ((optind > 1)
                        && (strncmp (argv[optind - 1], "--", 2) == 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Missing argument for option \"%s\"",
                        argv[optind - 1]);
                }
                else if (optopt > 0) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Missing argument for option \"-%c\"", optopt);
                }
                else {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Failed to process command-line");
                }
                break;
            default:
                if ((optind > 1)
                        && (strncmp (argv[optind - 1], "--", 2) == 0)) {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Unimplemented option \"%s\"", argv[optind - 1]);
                }
                else {
                    log_err (EMUNGE_SNAFU, LOG_ERR,
                        "Unimplemented option \"-%c\"", c);
                }
                break;
        }
    }
    if (argv[optind]) {
        log_err (EMUNGE_SNAFU, LOG_ERR,
            "Unrecognized parameter \"%s\"", argv[optind]);
    }
    /*  Create arbitrary payload of the specified length.
     */
    if (conf->num_payload > 0) {
        if (!(conf->payload = malloc (conf->num_payload + 1))) {
            log_err (EMUNGE_NO_MEMORY, LOG_ERR,
                "Failed to allocate credential payload of %d byte%s",
                conf->num_payload, (conf->num_payload == 1 ? "" : "s"));
        }
        for (i = 0, c = 'A'; i < conf->num_payload; i++) {
            if ((conf->payload[i] = c++) == 'Z') {
                c = 'A';
            }
        }
        conf->payload[conf->num_payload] = '\0';
    }
    return;
}
Esempio n. 11
0
File: remunge.c Progetto: dun/munge
void *
remunge (conf_t conf)
{
/*  Worker thread responsible for encoding/decoding/validating credentials.
 */
    tdata_t         tdata;
    int             cancel_state;
    unsigned long   n;
    unsigned long   got_encode_err;
    unsigned long   got_decode_err;
    struct timeval  t_start;
    struct timeval  t_stop;
    double          delta;
    munge_err_t     e;
    char           *cred;
    void           *data;
    int             dlen;
    uid_t           uid;
    gid_t           gid;

    tdata = create_tdata (conf);

    pthread_cleanup_push ((thread_cleanup_f) remunge_cleanup, tdata);

    if ((errno = pthread_mutex_lock (&conf->mutex)) != 0) {
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock mutex");
    }
    while (conf->num_creds - conf->shared.num_creds_done > 0) {

        pthread_testcancel ();

        if ((errno = pthread_setcancelstate
                    (PTHREAD_CANCEL_DISABLE, &cancel_state)) != 0) {
            log_errno (EMUNGE_SNAFU, LOG_ERR,
                "Failed to disable thread cancellation");
        }
        n = ++conf->shared.num_creds_done;

        if ((errno = pthread_mutex_unlock (&conf->mutex)) != 0) {
            log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock mutex");
        }
        got_encode_err = 0;
        got_decode_err = 0;
        data = NULL;

        GET_TIMEVAL (t_start);
        e = munge_encode(&cred, tdata->ectx, conf->payload, conf->num_payload);
        GET_TIMEVAL (t_stop);

        delta = DIFF_TIMEVAL (t_stop, t_start);
        if (delta > conf->warn_time) {
            output_msg ("Credential #%lu encoding took %0.3f seconds",
                n, delta);
        }
        if (e != EMUNGE_SUCCESS) {
            output_msg ("Credential #%lu encoding failed: %s (err=%d)",
                n, munge_ctx_strerror (tdata->ectx), e);
            ++got_encode_err;
        }
        else if (conf->do_decode) {

            GET_TIMEVAL (t_start);
            e = munge_decode (cred, tdata->dctx, &data, &dlen, &uid, &gid);
            GET_TIMEVAL (t_stop);

            delta = DIFF_TIMEVAL (t_stop, t_start);
            if (delta > conf->warn_time) {
                output_msg ("Credential #%lu decoding took %0.3f seconds",
                    n, delta);
            }
            if (e != EMUNGE_SUCCESS) {
                output_msg ("Credential #%lu decoding failed: %s (err=%d)",
                    n, munge_ctx_strerror (tdata->dctx), e);
                ++got_decode_err;
            }

/*  FIXME:
 *    The following block does some validating of the decoded credential.
 *    It should have a cmdline option to enable this validation check.
 *    The decode ctx should also be checked against the encode ctx.
 *    This becomes slightly more difficult in that it must also take
 *    into account the default field settings.
 *
 *    This block should be moved into a separate function (or more).
 *    The [cred], [data], [dlen], [uid], and [gid] vars could be placed
 *    into the tdata struct to facilitate parameter passing.
 */
#if 0
            else if (conf->do_validate) {
                if (getuid () != uid) {
                output_msg (
                    "Credential #%lu UID %d does not match process UID %d",
                    n, uid, getuid ());
                }
                if (getgid () != gid) {
                    output_msg (
                        "Credential #%lu GID %d does not match process GID %d",
                        n, gid, getgid ());
                }
                if (conf->num_payload != dlen) {
                    output_msg (
                        "Credential #%lu payload length mismatch (%d/%d)",
                        n, conf->num_payload, dlen);
                }
                else if (data && memcmp (conf->payload, data, dlen) != 0) {
                    output_msg ("Credential #%lu payload mismatch", n);
                }
            }
#endif /* 0 */

            /*  The 'data' parm can still be set on certain munge errors.
             */
            if (data != NULL) {
                free (data);
            }
        }
        if (cred != NULL) {
            free (cred);
        }
        if ((errno = pthread_setcancelstate
                    (cancel_state, &cancel_state)) != 0) {
            log_errno (EMUNGE_SNAFU, LOG_ERR,
                "Failed to enable thread cancellation");
        }
        if ((errno = pthread_mutex_lock (&conf->mutex)) != 0) {
            log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock mutex");
        }
        conf->shared.num_encode_errs += got_encode_err;
        conf->shared.num_decode_errs += got_decode_err;
    }
    pthread_cleanup_pop (1);
    return (NULL);
}