예제 #1
0
파일: auth_des.c 프로젝트: hkoehler/ntirpc
/*
 * 3. Validate
 */
static bool
authdes_validate(AUTH *auth, struct opaque_auth *rverf)
{
	/* LINTED pointer alignment */
	struct ad_private *ad = AUTH_PRIVATE(auth);
	struct authdes_verf verf;
	int status;
	uint32_t *ixdr;
	des_block buf;

	if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT)
		return (false);

	/* LINTED pointer alignment */
	ixdr = (uint32_t *) rverf->oa_base;
	buf.key.high = (uint32_t) *ixdr++;
	buf.key.low = (uint32_t) *ixdr++;
	verf.adv_int_u = (uint32_t) *ixdr++;

	/*
	 * Decrypt the timestamp
	 */
	status =
	    ecb_crypt((char *)&auth->ah_key, (char *)&buf,
		      (u_int) sizeof(des_block), DES_DECRYPT | DES_HW);

	if (DES_FAILED(status)) {
		__warnx(TIRPC_DEBUG_FLAG_AUTH,
			"authdes_validate: DES decryption failure");
		return (false);
	}

	/*
	 * xdr the decrypted timestamp
	 */
	/* LINTED pointer alignment */
	ixdr = (uint32_t *) buf.c;
	verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1;
	verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr);

	/*
	 * validate
	 */
	if (bcmp
	    ((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp,
	     sizeof(struct timeval)) != 0) {
		__warnx(TIRPC_DEBUG_FLAG_AUTH,
			"authdes_validate: verifier mismatch");
		return (false);
	}

	/*
	 * We have a nickname now, let's use it
	 */
	ad->ad_nickname = verf.adv_nickname;
	ad->ad_cred.adc_namekind = ADN_NICKNAME;
	return (true);
}
예제 #2
0
/*
 * System (Unix) longhand authenticator
 */
enum auth_stat
__svcauth_sys(struct svc_req *rqst, struct rpc_msg *msg)
{
	struct authsys_parms *aup;
	int32_t *buf;
	struct authsys_area *area;
	uint_t auth_len;
	uint_t str_len, gid_len;
	int i;

	/* LINTED pointer cast */
	area = (struct authsys_area *)rqst->rq_clntcred;
	aup = &area->area_aup;
	aup->aup_machname = area->area_machname;
	aup->aup_gids = area->area_gids;
	auth_len = msg->rm_call.cb_cred.oa_length;
	if (auth_len == 0)
		return (AUTH_BADCRED);

	/* LINTED pointer cast */
	buf = (int32_t *)msg->rm_call.cb_cred.oa_base;

	aup->aup_time = IXDR_GET_INT32(buf);
	str_len = IXDR_GET_U_INT32(buf);
	if (str_len > MAX_MACHINE_NAME)
		return (AUTH_BADCRED);
	(void) memcpy(aup->aup_machname, buf, str_len);
	aup->aup_machname[str_len] = 0;
	str_len = RNDUP(str_len);
	buf += str_len / (int)sizeof (int32_t);
	aup->aup_uid = IXDR_GET_INT32(buf);
	aup->aup_gid = IXDR_GET_INT32(buf);
	gid_len = IXDR_GET_U_INT32(buf);
	if (gid_len > NGRPS)
		return (AUTH_BADCRED);
	aup->aup_len = gid_len;
	for (i = 0; i < gid_len; i++) {
		aup->aup_gids[i] = (gid_t)IXDR_GET_INT32(buf);
	}
	/*
	 * five is the smallest unix credentials structure -
	 * timestamp, hostname len (0), uid, gid, and gids len (0).
	 */
	if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len)
		return (AUTH_BADCRED);

	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
	rqst->rq_xprt->xp_verf.oa_length = 0;

	return (AUTH_OK);
}
예제 #3
0
bool_t xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp)
{
#if defined(SOLARIS) && !defined(_LP64)
  register long *buf;
#else
  register int32_t *buf;
#endif

  if (xdrs->x_op == XDR_ENCODE) {
    buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
    if (buf == NULL) {
      if (!xdr_long (xdrs, &objp->clientId))
        return FALSE;
      if (!xdr_bool (xdrs, &objp->lockDevice))
        return FALSE;
      if (!xdr_u_long (xdrs, &objp->lock_timeout))
        return FALSE;

    } else {
      IXDR_PUT_INT32(buf, objp->clientId);
      IXDR_PUT_BOOL(buf, objp->lockDevice);
      IXDR_PUT_U_INT32(buf, objp->lock_timeout);
    }
    if (!xdr_string (xdrs, &objp->device, ~0))
      return FALSE;
    return TRUE;
  } else if (xdrs->x_op == XDR_DECODE) {
    buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
    if (buf == NULL) {
      if (!xdr_long (xdrs, &objp->clientId))
        return FALSE;
      if (!xdr_bool (xdrs, &objp->lockDevice))
        return FALSE;
      if (!xdr_u_long (xdrs, &objp->lock_timeout))
        return FALSE;

    } else {
      objp->clientId = IXDR_GET_INT32(buf);
      objp->lockDevice = IXDR_GET_BOOL(buf);
      objp->lock_timeout = IXDR_GET_U_INT32(buf);
    }
    if (!xdr_string (xdrs, &objp->device, ~0))
      return FALSE;
    return TRUE;
  }

  if (!xdr_long (xdrs, &objp->clientId))
    return FALSE;
  if (!xdr_bool (xdrs, &objp->lockDevice))
    return FALSE;
  if (!xdr_u_long (xdrs, &objp->lock_timeout))
    return FALSE;
  if (!xdr_string (xdrs, &objp->device, ~0))
    return FALSE;
  return TRUE;
}
예제 #4
0
/*
 * XDR a call message
 */
bool_t
xdr_callmsg(XDR *xdrs, struct rpc_msg *cmsg)
{
	rpc_inline_t *buf;
	struct opaque_auth *oa;

	if (xdrs->x_op == XDR_ENCODE) {
		if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES)
			return (FALSE);
		if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES)
			return (FALSE);
		buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
			+ RNDUP(cmsg->rm_call.cb_cred.oa_length)
			+ 2 * BYTES_PER_XDR_UNIT
			+ RNDUP(cmsg->rm_call.cb_verf.oa_length));
		if (buf != NULL) {
			IXDR_PUT_INT32(buf, cmsg->rm_xid);
			IXDR_PUT_ENUM(buf, cmsg->rm_direction);
			if (cmsg->rm_direction != CALL)
				return (FALSE);
			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers);
			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION)
				return (FALSE);
			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog);
			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers);
			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc);
			oa = &cmsg->rm_call.cb_cred;
			IXDR_PUT_ENUM(buf, oa->oa_flavor);
			IXDR_PUT_INT32(buf, oa->oa_length);
			if (oa->oa_length) {
				(void) memcpy(buf, oa->oa_base, oa->oa_length);
				buf += RNDUP(oa->oa_length) / sizeof (int32_t);
			}
			oa = &cmsg->rm_call.cb_verf;
			IXDR_PUT_ENUM(buf, oa->oa_flavor);
			IXDR_PUT_INT32(buf, oa->oa_length);
			if (oa->oa_length) {
				(void) memcpy(buf, oa->oa_base, oa->oa_length);
				/*
				 * no real need....
				 * buf += RNDUP(oa->oa_length) / sizeof
				 * (int32_t);
				 */
			}
			return (TRUE);
		}
	}
	if (xdrs->x_op == XDR_DECODE) {
		buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
		if (buf != NULL) {
			cmsg->rm_xid = IXDR_GET_INT32(buf);
			cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
			if (cmsg->rm_direction != CALL)
				return (FALSE);
			cmsg->rm_call.cb_rpcvers = IXDR_GET_INT32(buf);
			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION)
				return (FALSE);
			cmsg->rm_call.cb_prog = IXDR_GET_INT32(buf);
			cmsg->rm_call.cb_vers = IXDR_GET_INT32(buf);
			cmsg->rm_call.cb_proc = IXDR_GET_INT32(buf);
			oa = &cmsg->rm_call.cb_cred;
			oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
			oa->oa_length = IXDR_GET_INT32(buf);
			if (oa->oa_length) {
				if (oa->oa_length > MAX_AUTH_BYTES)
					return (FALSE);
				if (oa->oa_base == NULL) {
					oa->oa_base = malloc(oa->oa_length);
					if (oa->oa_base == NULL) {
						syslog(LOG_ERR,
							"xdr_callmsg : "
							"out of memory.");
						return (FALSE);
					}
				}
				buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
				if (buf == NULL) {
					if (xdr_opaque(xdrs, oa->oa_base,
					    oa->oa_length) == FALSE)
						return (FALSE);
				} else {
					(void) memcpy(oa->oa_base,
					    buf, (size_t)oa->oa_length);
					/*
					 * no real need....
					 * buf += RNDUP(oa->oa_length) /
					 *	(int)sizeof (int32_t);
					 */
				}
			}
			oa = &cmsg->rm_call.cb_verf;
			buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
			if (buf == NULL) {
				if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
				    xdr_u_int(xdrs, &oa->oa_length) == FALSE)
					return (FALSE);
			} else {
				oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
				oa->oa_length = IXDR_GET_INT32(buf);
			}
			if (oa->oa_length) {
				if (oa->oa_length > MAX_AUTH_BYTES)
					return (FALSE);
				if (oa->oa_base == NULL) {
					oa->oa_base = malloc(oa->oa_length);
					if (oa->oa_base == NULL) {
						syslog(LOG_ERR,
							"xdr_callmsg : "
							"out of memory.");
						return (FALSE);
					}
				}
				buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
				if (buf == NULL) {
					if (xdr_opaque(xdrs, oa->oa_base,
					    oa->oa_length) == FALSE)
						return (FALSE);
				} else {
					(void) memcpy(oa->oa_base,
					    buf, (size_t)oa->oa_length);
					/*
					 * no real need...
					 * buf += RNDUP(oa->oa_length) /
					 *	(int)sizeof (int32_t);
					 */
				}
			}
			return (TRUE);
		}
예제 #5
0
/*
 * Unix longhand authenticator
 */
enum auth_stat
_svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
{
	enum auth_stat stat;
	XDR xdrs;
	int32_t *buf;
	uint32_t time;
	struct xucred *xcr;
	u_int auth_len;
	size_t str_len, gid_len;
	u_int i;

	xcr = rqst->rq_clntcred;
	auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
	xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,
	    XDR_DECODE);
	buf = XDR_INLINE(&xdrs, auth_len);
	if (buf != NULL) {
		time = IXDR_GET_UINT32(buf);
		str_len = (size_t)IXDR_GET_UINT32(buf);
		if (str_len > MAX_MACHINE_NAME) {
			stat = AUTH_BADCRED;
			goto done;
		}
		str_len = RNDUP(str_len);
		buf += str_len / sizeof (int32_t);
		xcr->cr_uid = IXDR_GET_UINT32(buf);
		xcr->cr_groups[0] = IXDR_GET_UINT32(buf);
		gid_len = (size_t)IXDR_GET_UINT32(buf);
		if (gid_len > NGRPS) {
			stat = AUTH_BADCRED;
			goto done;
		}
		for (i = 0; i < gid_len; i++) {
			if (i + 1 < XU_NGROUPS)
				xcr->cr_groups[i + 1] = IXDR_GET_INT32(buf);
			else
				buf++;
		}
		if (gid_len + 1 > XU_NGROUPS)
			xcr->cr_ngroups = XU_NGROUPS;
		else
			xcr->cr_ngroups = gid_len + 1;

		/*
		 * five is the smallest unix credentials structure -
		 * timestamp, hostname len (0), uid, gid, and gids len (0).
		 */
		if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
			(void) printf("bad auth_len gid %ld str %ld auth %u\n",
			    (long)gid_len, (long)str_len, auth_len);
			stat = AUTH_BADCRED;
			goto done;
		}
	} else if (! xdr_authunix_parms(&xdrs, &time, xcr)) {
		stat = AUTH_BADCRED;
		goto done;
	}

	rqst->rq_verf = _null_auth;
	stat = AUTH_OK;
done:
	XDR_DESTROY(&xdrs);

	return (stat);
}
예제 #6
0
static int
rpc_helper_cb(struct pkt_buff *pkt, uint32_t protoff,
	      struct myct *myct, uint32_t ctinfo)
{
	int dir = CTINFO2DIR(ctinfo);
	unsigned int offset = protoff, datalen;
	uint32_t *data, *port_ptr = NULL, xid;
	uint16_t port;
	uint8_t proto = nfct_get_attr_u8(myct->ct, ATTR_L4PROTO);
	enum msg_type rm_dir;
	struct rpc_info *rpc_info = myct->priv_data;
	union nfct_attr_grp_addr addr, daddr;
	struct nf_expect *exp = NULL;
	int ret = NF_ACCEPT;

	/* Until there's been traffic both ways, don't look into TCP packets. */
	if (proto == IPPROTO_TCP
	    && ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED_REPLY) {
		pr_debug("TCP RPC: Conntrackinfo = %u\n", ctinfo);
		return ret;
	}
	if (proto == IPPROTO_TCP) {
		struct tcphdr *th =
			(struct tcphdr *) (pktb_network_header(pkt) + protoff);
		offset += th->doff * 4;
	} else {
		offset += sizeof(struct udphdr);
	}
	/* Skip broken headers */
	if (offset % 4) {
		pr_debug("RPC: broken header: offset %u%%4 != 0\n", offset);
		return ret;
	}

	/* Take into Record Fragment header */
	if (proto == IPPROTO_TCP)
		offset += 4;

	datalen = pktb_len(pkt);
	data = (uint32_t *)(pktb_network_header(pkt) + offset);

	/* rpc_msg {
	 *	xid
	 *	direction
	 *	xdr_union {
	 *		call_body
	 *		reply_body
	 *	}
	 * }
	 */

	 /* Check minimal msg size: xid + direction */
	if (datalen < OFFSET(offset, 2*4)) {
		pr_debug("RPC: too short packet: %u < %u\n",
			 datalen, offset);
		return ret;
	}
	xid = IXDR_GET_INT32(data);
	rm_dir = IXDR_GET_INT32(data);

	/* Check direction */
	if (!((rm_dir == CALL && dir == MYCT_DIR_ORIG)
	      || (rm_dir == REPLY && dir == MYCT_DIR_REPL))) {
		pr_debug("RPC: rm_dir != dir %u != %u\n", rm_dir, dir);
		goto out;
	}

	if (rm_dir == CALL) {
		if (rpc_call(data, offset, datalen, rpc_info) < 0)
			goto out;

		rpc_info->xid = xid;

		return ret;
	} else {
		/* Check XID */
		if (xid != rpc_info->xid) {
			pr_debug("RPC REPL: XID does not match: %u != %u\n",
				 xid, rpc_info->xid);
			goto out;
		}
		if (rpc_reply(data, offset, datalen, rpc_info, &port_ptr) < 0)
			goto out;

		port = IXDR_GET_INT32(port_ptr);
		port = htons(port);

		/* We refer to the reverse direction ("!dir") tuples here,
		 * because we're expecting something in the other direction.
		 * Doesn't matter unless NAT is happening.  */
		cthelper_get_addr_dst(myct->ct, !dir, &daddr);
		cthelper_get_addr_src(myct->ct, !dir, &addr);

		exp = nfexp_new();
		if (exp == NULL)
			goto out;

		if (cthelper_expect_init(exp, myct->ct, 0, &addr, &daddr,
					 rpc_info->pm_prot,
					 NULL, &port, NF_CT_EXPECT_PERMANENT)) {
			pr_debug("RPC: failed to init expectation\n");
			goto out_exp;
		}

		/* Now, NAT might want to mangle the packet, and register the
		 * (possibly changed) expectation itself. */
		if (nfct_get_attr_u32(myct->ct, ATTR_STATUS) & IPS_NAT_MASK) {
			ret = nf_nat_rpc(pkt, dir, exp, rpc_info->pm_prot,
					 port_ptr);
			goto out_exp;
		}

		/* Can't expect this?  Best to drop packet now. */
		if (cthelper_add_expect(exp) < 0) {
			pr_debug("RPC: cannot add expectation: %s\n",
				 strerror(errno));
			ret = NF_DROP;
		}
	}

out_exp:
	nfexp_destroy(exp);
out:
	rpc_info->xid = 0;
	return ret;
}
예제 #7
0
static int
rpc_reply(uint32_t *data, uint32_t offset, uint32_t datalen,
	  struct rpc_info *rpc_info, uint32_t **port_ptr)
{
	uint16_t port;
	uint32_t p, r;

	/* RPC REPLY message body */

	/* reply_body {
	 *	reply_stat
	 *	xdr_union {
	 *		accepted_reply
	 *		rejected_reply
	 *	}
	 * }
	 * accepted_reply {
	 *	opaque_auth verf
	 *	accept_stat
	 *	xdr_union {
	 *		port
	 *		struct mismatch_info
	 *	}
	 * }
	 */

	/* Check size: reply status */
	if (datalen < OFFSET(offset, 4)) {
		pr_debug("RPC REPL: too short, missing rp_stat: %u < %u\n",
			 datalen, offset);
		return -1;
	}
	p = IXDR_GET_INT32(data);
	/* Check accepted request */
	if (p != MSG_ACCEPTED) {
		pr_debug("RPC REPL: not accepted %u != %u\n",
			 p, MSG_ACCEPTED);
		return -1;
	}
	/* Check and skip verifier */
	if (datalen < OFFSET(offset, 2*4)) {
		pr_debug("RPC REPL: too short, missing verf: %u < %u\n",
			 datalen, offset);
		return -1;
	}
	r = IXDR_GET_INT32(data);
	p = IXDR_GET_INT32(data);
	pr_debug("RPC REPL: verf: %u %u (%u, %u)\n",
		 r, p, datalen, offset);
	if (p > MAX_AUTH_BYTES) {
		pr_debug("RPC REPL: invalid sized verf %u > %u\n",
			 p, MAX_AUTH_BYTES);
		return -1;
	}
	r = ROUNDUP(p);
	/* verifier + ac_stat + port */
	if (datalen != OFFSET(offset, r) + 2*4) {
		pr_debug("RPC REPL: invalid size to carry verf and "
			 "success: %u != %u\n",
			 datalen, offset + 2*4);
		return -1;
	}
	data += r/4;
	/* Check success */
	p = IXDR_GET_INT32(data);
	if (p != SUCCESS) {
		pr_debug("RPC REPL: not success %u != %u\n",
			 p, SUCCESS);
		return -1;
	}
	/* Get port */
	*port_ptr = data;
	port = IXDR_GET_INT32(data); /* -Wunused-but-set-parameter */
	if (port == 0) {
		pr_debug("RPC REPL: port is zero\n");
		return -1;
	}
	pr_debug("RPC REPL: processed: xid %u, prog %u, vers %u, "
		 "prot %u, port %u\n",
		 rpc_info->xid, rpc_info->pm_prog, rpc_info->pm_vers,
		 rpc_info->pm_prot, port);
	return 0;
}
예제 #8
0
static int
rpc_call(const uint32_t *data, uint32_t offset, uint32_t datalen,
	 struct rpc_info *rpc_info)
{
	uint32_t p, r;

	/* RPC CALL message body */

	/* call_body {
	 *	rpcvers
	 *	prog
	 *	vers
	 *	proc
	 *	opaque_auth cred
	 *	opaque_auth verf
	 *	pmap
	 * }
	 *
	 * opaque_auth {
	 *	flavour
	 *	opaque[len] <= MAX_AUTH_BYTES
	 * }
	 */
	if (datalen < OFFSET(offset, 4*4 + 2*2*4)) {
		pr_debug("RPC CALL: too short packet: %u < %u\n",
			 datalen, offset);
		return -1;
	}
	/* Check rpcversion */
	p = IXDR_GET_INT32(data);
	if (p != SUPPORTED_RPC_VERSION) {
		pr_debug("RPC CALL: wrong rpcvers %u != %u\n",
			 p, SUPPORTED_RPC_VERSION);
		return -1;
	}
	/* Skip non-portmap requests */
	p = IXDR_GET_INT32(data);
	if (p != PMAPPROG) {
		pr_debug("RPC CALL: not portmap %u != %lu\n",
			 p, PMAPPROG);
		return -1;
	}
	/* Check portmap version */
	p = IXDR_GET_INT32(data);
	if (p != PMAPVERS) {
		pr_debug("RPC CALL: wrong portmap version %u != %lu\n",
			 p, PMAPVERS);
		return -1;
	}
	/* Skip non PMAPPROC_GETPORT requests */
	p = IXDR_GET_INT32(data);
	if (p != PMAPPROC_GETPORT) {
		pr_debug("RPC CALL: not PMAPPROC_GETPORT %u != %lu\n",
			 p, PMAPPROC_GETPORT);
		return -1;
	}
	/* Check and skip credentials */
	r = IXDR_GET_INT32(data);
	p = IXDR_GET_INT32(data);
	pr_debug("RPC CALL: cred: %u %u (%u, %u)\n",
		 r, p, datalen, offset);
	if (p > MAX_AUTH_BYTES) {
		pr_debug("RPC CALL: invalid sized cred %u > %u\n",
			 p, MAX_AUTH_BYTES);
		return -1;
	}
	r = ROUNDUP(p);
	if (datalen < OFFSET(offset, r)) {
		pr_debug("RPC CALL: too short to carry cred: %u < %u, %u\n",
			 datalen, offset, r);
		return -1;
	}
	data += r/4;
	/* Check and skip verifier */
	r = IXDR_GET_INT32(data);
	p = IXDR_GET_INT32(data);
	pr_debug("RPC CALL: verf: %u %u (%u, %u)\n",
		 r, p, datalen, offset);
	if (p > MAX_AUTH_BYTES) {
		pr_debug("RPC CALL: invalid sized verf %u > %u\n",
			 p, MAX_AUTH_BYTES);
		return -1;
	}
	r = ROUNDUP(p);
	if (datalen < OFFSET(offset, r)) {
		pr_debug("RPC CALL: too short to carry verf: %u < %u, %u\n",
			 datalen, offset, r);
		return -1;
	}
	data += r/4;
	/* pmap {
	 *	prog
	 *	vers
	 *	prot
	 *	port
	 * }
	 */
	/* Check CALL size */
	if (datalen != offset + 4*4) {
		pr_debug("RPC CALL: invalid size to carry pmap: %u != %u\n",
			 datalen, offset + 4*4);
		return -1;
	}
	rpc_info->pm_prog = IXDR_GET_INT32(data);
	rpc_info->pm_vers = IXDR_GET_INT32(data);
	rpc_info->pm_prot = IXDR_GET_INT32(data);
	/* Check supported protocols */
	if (!(rpc_info->pm_prot == IPPROTO_TCP
	      || rpc_info->pm_prot == IPPROTO_UDP)) {
		pr_debug("RPC CALL: unsupported protocol %u",
			 rpc_info->pm_prot);
		return -1;
	}
	p = IXDR_GET_INT32(data);
	/* Check port: must be zero */
	if (p != 0) {
		pr_debug("RPC CALL: port is nonzero %u\n",
			 ntohl(p));
		return -1;
	}
	pr_debug("RPC CALL: processed: xid %u, prog %u, vers %u, prot %u\n",
		 rpc_info->xid, rpc_info->pm_prog,
		 rpc_info->pm_vers, rpc_info->pm_prot);

	return 0;
}
예제 #9
0
/*
 * Unix longhand authenticator
 */
enum auth_stat
_svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
{
	enum auth_stat stat;
	XDR xdrs;
	struct authunix_parms *aup;
	int32_t *buf;
	struct area {
		struct authunix_parms area_aup;
		char area_machname[MAX_MACHINE_NAME+1];
		int area_gids[NGRPS];
	} *area;
	u_int auth_len;
	size_t str_len, gid_len;
	u_int i;

	assert(rqst != NULL);
	assert(msg != NULL);

	area = (struct area *) rqst->rq_clntcred;
	aup = &area->area_aup;
	aup->aup_machname = area->area_machname;
	aup->aup_gids = area->area_gids;
	auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
	xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE);
	buf = XDR_INLINE(&xdrs, auth_len);
	if (buf != NULL) {
		aup->aup_time = IXDR_GET_INT32(buf);
		str_len = (size_t)IXDR_GET_U_INT32(buf);
		if (str_len > MAX_MACHINE_NAME) {
			stat = AUTH_BADCRED;
			goto done;
		}
		memmove(aup->aup_machname, buf, str_len);
		aup->aup_machname[str_len] = 0;
		str_len = RNDUP(str_len);
		buf += str_len / sizeof (int32_t);
		aup->aup_uid = (int)IXDR_GET_INT32(buf);
		aup->aup_gid = (int)IXDR_GET_INT32(buf);
		gid_len = (size_t)IXDR_GET_U_INT32(buf);
		if (gid_len > NGRPS) {
			stat = AUTH_BADCRED;
			goto done;
		}
		aup->aup_len = gid_len;
		for (i = 0; i < gid_len; i++) {
			aup->aup_gids[i] = (int)IXDR_GET_INT32(buf);
		}
		/*
		 * five is the smallest unix credentials structure -
		 * timestamp, hostname len (0), uid, gid, and gids len (0).
		 */
		if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
			printf("bad auth_len gid %ld str %ld auth %u\n",
			    (long)gid_len, (long)str_len, auth_len);
			stat = AUTH_BADCRED;
			goto done;
		}
	} else if (! xdr_authunix_parms(&xdrs, aup)) {
		xdrs.x_op = XDR_FREE;
		xdr_authunix_parms(&xdrs, aup);
		stat = AUTH_BADCRED;
		goto done;
	}

       /* get the verifier */
	if ((u_int)msg->rm_call.cb_verf.oa_length) {
		rqst->rq_xprt->xp_verf.oa_flavor =
			msg->rm_call.cb_verf.oa_flavor;
		rqst->rq_xprt->xp_verf.oa_base =
			msg->rm_call.cb_verf.oa_base;
		rqst->rq_xprt->xp_verf.oa_length =
			msg->rm_call.cb_verf.oa_length;
	} else {
		rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
		rqst->rq_xprt->xp_verf.oa_length = 0;
	}
	stat = AUTH_OK;
done:
	XDR_DESTROY(&xdrs);
	return (stat);
}
예제 #10
0
bool_t
xdr_rpcbs_rmtcalllist(XDR *xdrs, rpcbs_rmtcalllist *objp)
{
	int32_t *buf;
	struct rpcbs_rmtcalllist **pnext;

	if (xdrs->x_op == XDR_ENCODE) {
	buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
	if (buf == NULL) {
		if (!xdr_u_int32_t(xdrs, &objp->prog)) {
			return (FALSE);
		}
		if (!xdr_u_int32_t(xdrs, &objp->vers)) {
			return (FALSE);
		}
		if (!xdr_u_int32_t(xdrs, &objp->proc)) {
			return (FALSE);
		}
		if (!xdr_int(xdrs, &objp->success)) {
			return (FALSE);
		}
		if (!xdr_int(xdrs, &objp->failure)) {
			return (FALSE);
		}
		if (!xdr_int(xdrs, &objp->indirect)) {
			return (FALSE);
		}
	} else {
		IXDR_PUT_U_INT32(buf, objp->prog);
		IXDR_PUT_U_INT32(buf, objp->vers);
		IXDR_PUT_U_INT32(buf, objp->proc);
		IXDR_PUT_INT32(buf, objp->success);
		IXDR_PUT_INT32(buf, objp->failure);
		IXDR_PUT_INT32(buf, objp->indirect);
	}
	if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
		return (FALSE);
	}
	pnext = &objp->next;
	if (!xdr_pointer(xdrs, (char **) pnext,
			sizeof (rpcbs_rmtcalllist),
			(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
		return (FALSE);
	}
	return (TRUE);
	} else if (xdrs->x_op == XDR_DECODE) {
	buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
	if (buf == NULL) {
		if (!xdr_u_int32_t(xdrs, &objp->prog)) {
			return (FALSE);
		}
		if (!xdr_u_int32_t(xdrs, &objp->vers)) {
			return (FALSE);
		}
		if (!xdr_u_int32_t(xdrs, &objp->proc)) {
			return (FALSE);
		}
		if (!xdr_int(xdrs, &objp->success)) {
			return (FALSE);
		}
		if (!xdr_int(xdrs, &objp->failure)) {
			return (FALSE);
		}
		if (!xdr_int(xdrs, &objp->indirect)) {
			return (FALSE);
		}
	} else {
		objp->prog = (rpcprog_t)IXDR_GET_U_INT32(buf);
		objp->vers = (rpcvers_t)IXDR_GET_U_INT32(buf);
		objp->proc = (rpcproc_t)IXDR_GET_U_INT32(buf);
		objp->success = (int)IXDR_GET_INT32(buf);
		objp->failure = (int)IXDR_GET_INT32(buf);
		objp->indirect = (int)IXDR_GET_INT32(buf);
	}
	if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
		return (FALSE);
	}
	if (!xdr_pointer(xdrs, (char **) pnext,
			sizeof (rpcbs_rmtcalllist),
			(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
		return (FALSE);
	}
	return (TRUE);
	}
	if (!xdr_u_int32_t(xdrs, &objp->prog)) {
		return (FALSE);
	}
	if (!xdr_u_int32_t(xdrs, &objp->vers)) {
		return (FALSE);
	}
	if (!xdr_u_int32_t(xdrs, &objp->proc)) {
		return (FALSE);
	}
	if (!xdr_int(xdrs, &objp->success)) {
		return (FALSE);
	}
	if (!xdr_int(xdrs, &objp->failure)) {
		return (FALSE);
	}
	if (!xdr_int(xdrs, &objp->indirect)) {
		return (FALSE);
	}
	if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
		return (FALSE);
	}
	if (!xdr_pointer(xdrs, (char **) pnext,
			sizeof (rpcbs_rmtcalllist),
			(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
		return (FALSE);
	}
	return (TRUE);
}
예제 #11
0
static int check_rpc_packet(const u_int32_t *data, const void *matchinfo,
			int *hotdrop, int dir, struct ip_conntrack *ct,
			int offset, struct list_head request_p_list)
{
	const struct ipt_rpc_info *rpcinfo = matchinfo;
	struct request_p *req_p;
	u_int32_t xid;


	/* Get XID */
	xid = *data;

 	/* This does sanity checking on RPC payloads,
	 * and permits only the RPC "get port" (3)
	 * in authorised procedures in client
	 * communications with the portmapper.
	 */

	data += 5;

	/* Get RPC requestor */
	if (IXDR_GET_INT32(data) != 3) {
		DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
		if(rpcinfo->strict == 1)
			*hotdrop = 1;
		return 0;
	}
	DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");

	data++;

	/* Jump Credentials and Verfifier */
	data = data + IXDR_GET_INT32(data) + 2;
	data = data + IXDR_GET_INT32(data) + 2;

	/* Get RPC procedure */
	if (match_rpcs((char *)&rpcinfo->c_procs,
	    rpcinfo->i_procs, IXDR_GET_INT32(data)) == 0) {
		DEBUGP("RPC packet contains illegal procedure request [%u]. [drop]\n",
			(unsigned int)IXDR_GET_INT32(data));

		/* If the RPC conntrack half entry already exists .. */

		switch (ct->tuplehash[0].tuple.dst.protonum) {
			case IPPROTO_UDP:
				WRITE_LOCK(&ipct_rpc_udp_lock);
			case IPPROTO_TCP:
				WRITE_LOCK(&ipct_rpc_tcp_lock);
		}
		req_p = LIST_FIND(&request_p_list, request_p_cmp,
				  struct request_p *, xid,
				  ct->tuplehash[dir].tuple.src.ip,
				  ct->tuplehash[dir].tuple.src.u.all);

		if (req_p) {
			DEBUGP("found req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
				xid, ct->tuplehash[dir].tuple.dst.protonum,
				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
				ntohs(ct->tuplehash[dir].tuple.src.u.all));

			/* .. remove it */
			if (del_timer(&req_p->timeout))
				req_p->timeout.expires = 0;

       			LIST_DELETE(&request_p_list, req_p);
			DEBUGP("RPC req_p removed. [done]\n");

		} else {
			DEBUGP("no req_p found for xid=%u proto=%u %u.%u.%u.%u:%u\n",
				xid, ct->tuplehash[dir].tuple.dst.protonum,
				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
				ntohs(ct->tuplehash[dir].tuple.src.u.all));

		}
		switch (ct->tuplehash[0].tuple.dst.protonum) {
			case IPPROTO_UDP:
				WRITE_UNLOCK(&ipct_rpc_udp_lock);
			case IPPROTO_TCP:
				WRITE_UNLOCK(&ipct_rpc_tcp_lock);
		}

		if(rpcinfo->strict == 1)
			*hotdrop = 1;
		return 0;
	}
예제 #12
0
		}
		switch (ct->tuplehash[0].tuple.dst.protonum) {
			case IPPROTO_UDP:
				WRITE_UNLOCK(&ipct_rpc_udp_lock);
			case IPPROTO_TCP:
				WRITE_UNLOCK(&ipct_rpc_tcp_lock);
		}

		if(rpcinfo->strict == 1)
			*hotdrop = 1;
		return 0;
	}

	DEBUGP("RPC packet contains authorised procedure request [%u]. [match]\n",
		(unsigned int)IXDR_GET_INT32(data));
	return (1 && (!offset));
}


static int match(const struct sk_buff *skb, const struct net_device *in,
		 const struct net_device *out, const void *matchinfo,
		 int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	const u_int32_t *data;
	enum ip_conntrack_dir dir;
	const struct tcphdr *tcp;
	const struct ipt_rpc_info *rpcinfo = matchinfo;
	int port, portsok;
예제 #13
0
bool xdr_rquota(XDR * xdrs, rquota * objp)
{
	register int32_t *buf;

	if (xdrs->x_op == XDR_ENCODE) {
		buf = xdr_inline_encode(xdrs, 10 * BYTES_PER_XDR_UNIT);
		if (buf != NULL) {
			/* most likely */
			IXDR_PUT_INT32(buf, objp->rq_bsize);
			IXDR_PUT_BOOL(buf, objp->rq_active);
			IXDR_PUT_U_INT32(buf, objp->rq_bhardlimit);
			IXDR_PUT_U_INT32(buf, objp->rq_bsoftlimit);
			IXDR_PUT_U_INT32(buf, objp->rq_curblocks);
			IXDR_PUT_U_INT32(buf, objp->rq_fhardlimit);
			IXDR_PUT_U_INT32(buf, objp->rq_fsoftlimit);
			IXDR_PUT_U_INT32(buf, objp->rq_curfiles);
			IXDR_PUT_U_INT32(buf, objp->rq_btimeleft);
			IXDR_PUT_U_INT32(buf, objp->rq_ftimeleft);
		} else {
			if (!XDR_PUTINT32(xdrs, objp->rq_bsize))
				return false;
			if (!XDR_PUTBOOL(xdrs, objp->rq_active))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_bhardlimit))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_bsoftlimit))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_curblocks))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_fhardlimit))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_fsoftlimit))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_curfiles))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_btimeleft))
				return false;
			if (!XDR_PUTUINT32(xdrs, objp->rq_ftimeleft))
				return false;
		}
		return true;
	}

	if (xdrs->x_op == XDR_DECODE) {
		buf = xdr_inline_decode(xdrs, 10 * BYTES_PER_XDR_UNIT);
		if (buf != NULL) {
			/* most likely */
			objp->rq_bsize = IXDR_GET_INT32(buf);
			objp->rq_active = IXDR_GET_BOOL(buf);
			objp->rq_bhardlimit = IXDR_GET_U_INT32(buf);
			objp->rq_bsoftlimit = IXDR_GET_U_INT32(buf);
			objp->rq_curblocks = IXDR_GET_U_INT32(buf);
			objp->rq_fhardlimit = IXDR_GET_U_INT32(buf);
			objp->rq_fsoftlimit = IXDR_GET_U_INT32(buf);
			objp->rq_curfiles = IXDR_GET_U_INT32(buf);
			objp->rq_btimeleft = IXDR_GET_U_INT32(buf);
			objp->rq_ftimeleft = IXDR_GET_U_INT32(buf);
		} else {
			if (!XDR_GETINT32(xdrs, &objp->rq_bsize))
				return false;
			if (!XDR_GETBOOL(xdrs, &objp->rq_active))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_bhardlimit))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_bsoftlimit))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_curblocks))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_fhardlimit))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_fsoftlimit))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_curfiles))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_btimeleft))
				return false;
			if (!XDR_GETUINT32(xdrs, &objp->rq_ftimeleft))
				return false;
		}
		return true;
	}

	if (!xdr_int(xdrs, &objp->rq_bsize))
		return false;
	if (!xdr_bool(xdrs, &objp->rq_active))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_bhardlimit))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_bsoftlimit))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_curblocks))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_fhardlimit))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_fsoftlimit))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_curfiles))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_btimeleft))
		return false;
	if (!xdr_u_int(xdrs, &objp->rq_ftimeleft))
		return false;
	return true;
}
예제 #14
0
/*
 * XDR a call message
 */
bool_t
xdr_callmsg (XDR *xdrs, struct rpc_msg *cmsg)
{
  int32_t *buf;
  struct opaque_auth *oa;

  if (xdrs->x_op == XDR_ENCODE)
    {
      if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES)
	{
	  return (FALSE);
	}
      if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES)
	{
	  return (FALSE);
	}
      buf = XDR_INLINE (xdrs, 8 * BYTES_PER_XDR_UNIT
			+ RNDUP (cmsg->rm_call.cb_cred.oa_length)
			+ 2 * BYTES_PER_XDR_UNIT
			+ RNDUP (cmsg->rm_call.cb_verf.oa_length));
      if (buf != NULL)
	{
	  (void) IXDR_PUT_LONG (buf, cmsg->rm_xid);
	  (void) IXDR_PUT_ENUM (buf, cmsg->rm_direction);
	  if (cmsg->rm_direction != CALL)
	    return FALSE;
	  (void) IXDR_PUT_LONG (buf, cmsg->rm_call.cb_rpcvers);
	  if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION)
	    return FALSE;
	  (void) IXDR_PUT_LONG (buf, cmsg->rm_call.cb_prog);
	  (void) IXDR_PUT_LONG (buf, cmsg->rm_call.cb_vers);
	  (void) IXDR_PUT_LONG (buf, cmsg->rm_call.cb_proc);
	  oa = &cmsg->rm_call.cb_cred;
	  (void) IXDR_PUT_ENUM (buf, oa->oa_flavor);
	  (void) IXDR_PUT_INT32 (buf, oa->oa_length);
	  if (oa->oa_length)
	    {
	      memcpy ((caddr_t) buf, oa->oa_base, oa->oa_length);
	      buf = (int32_t *) ((char *) buf + RNDUP (oa->oa_length));
	    }
	  oa = &cmsg->rm_call.cb_verf;
	  (void) IXDR_PUT_ENUM (buf, oa->oa_flavor);
	  (void) IXDR_PUT_INT32 (buf, oa->oa_length);
	  if (oa->oa_length)
	    {
	      memcpy ((caddr_t) buf, oa->oa_base, oa->oa_length);
	      /* no real need....
	         buf = (long *) ((char *) buf + RNDUP(oa->oa_length));
	       */
	    }
	  return TRUE;
	}
    }
  if (xdrs->x_op == XDR_DECODE)
    {
      buf = XDR_INLINE (xdrs, 8 * BYTES_PER_XDR_UNIT);
      if (buf != NULL)
	{
	  cmsg->rm_xid = IXDR_GET_LONG (buf);
	  cmsg->rm_direction = IXDR_GET_ENUM (buf, enum msg_type);
	  if (cmsg->rm_direction != CALL)
	    {
	      return FALSE;
	    }
	  cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG (buf);
	  if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION)
	    {
	      return FALSE;
	    }
	  cmsg->rm_call.cb_prog = IXDR_GET_LONG (buf);
	  cmsg->rm_call.cb_vers = IXDR_GET_LONG (buf);
	  cmsg->rm_call.cb_proc = IXDR_GET_LONG (buf);
	  oa = &cmsg->rm_call.cb_cred;
	  oa->oa_flavor = IXDR_GET_ENUM (buf, enum_t);
	  oa->oa_length = IXDR_GET_INT32 (buf);
	  if (oa->oa_length)
	    {
	      if (oa->oa_length > MAX_AUTH_BYTES)
		return FALSE;
	      if (oa->oa_base == NULL)
		{
		  oa->oa_base = (caddr_t)
		    mem_alloc (oa->oa_length);
		}
	      buf = XDR_INLINE (xdrs, RNDUP (oa->oa_length));
	      if (buf == NULL)
		{
		  if (INTUSE(xdr_opaque) (xdrs, oa->oa_base,
					  oa->oa_length) == FALSE)
		    return FALSE;
		}
	      else
		{
		  memcpy (oa->oa_base, (caddr_t) buf, oa->oa_length);
		  /* no real need....
		     buf = (long *) ((char *) buf
		     + RNDUP(oa->oa_length));
		   */
		}
	    }
	  oa = &cmsg->rm_call.cb_verf;
	  buf = XDR_INLINE (xdrs, 2 * BYTES_PER_XDR_UNIT);
	  if (buf == NULL)
	    {
	      if (INTUSE(xdr_enum) (xdrs, &oa->oa_flavor) == FALSE ||
		  INTUSE(xdr_u_int) (xdrs, &oa->oa_length) == FALSE)
		{
		  return FALSE;
		}
	    }
	  else
	    {
	      oa->oa_flavor = IXDR_GET_ENUM (buf, enum_t);
	      oa->oa_length = IXDR_GET_INT32 (buf);
	    }
	  if (oa->oa_length)
	    {
	      if (oa->oa_length > MAX_AUTH_BYTES)
		return FALSE;
	      if (oa->oa_base == NULL)
		{
		  oa->oa_base = (caddr_t)
		    mem_alloc (oa->oa_length);
		}
	      buf = XDR_INLINE (xdrs, RNDUP (oa->oa_length));
	      if (buf == NULL)
		{
		  if (INTUSE(xdr_opaque) (xdrs, oa->oa_base,
					  oa->oa_length) == FALSE)
		    return FALSE;
		}
	      else
		{
		  memcpy (oa->oa_base, (caddr_t) buf, oa->oa_length);
		  /* no real need...
		     buf = (long *) ((char *) buf
		     + RNDUP(oa->oa_length));
		   */
		}
	    }
	  return TRUE;
	}
예제 #15
0
static int check_rpc_packet(const u_int32_t *data,
			int dir, struct ip_conntrack *ct,
			struct list_head request_p_list)
{
        int ret = NF_ACCEPT;
	u_int32_t xid;
	struct request_p *req_p;
	struct ip_conntrack_expect *exp;

	/* Translstion's buffer for XDR */
	u_int16_t port_buf;


	/* Get XID */
	xid = *data;

 	/* This does sanity checking on RPC payloads,
	 * and permits only the RPC "get port" (3)
	 * in authorised procedures in client
	 * communications with the portmapper.
	 */

	/* perform direction dependant RPC work */
	if (dir == IP_CT_DIR_ORIGINAL) {

		data += 5;

		/* Get RPC requestor */
		if (IXDR_GET_INT32(data) != 3) {
			DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
			return NF_ACCEPT;
		}
		DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");

		data++;

		/* Jump Credentials and Verfifier */
		data = data + IXDR_GET_INT32(data) + 2;
		data = data + IXDR_GET_INT32(data) + 2;

		/* Get RPC procedure */
		DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
			(unsigned int)IXDR_GET_INT32(data));

		/* Get RPC protocol and store against client parameters */
		data = data + 2;
		alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
				ct->tuplehash[dir].tuple.src.u.all);

		DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
			xid, IXDR_GET_INT32(data),
			NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
			ntohs(ct->tuplehash[dir].tuple.src.u.all));

		DEBUGP("allocated RPC request for protocol %u. [done]\n",
			(unsigned int)IXDR_GET_INT32(data));

	} else {

		/* Check for returning packet's stored counterpart */
		req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
				  struct request_p *, xid,
				  ct->tuplehash[!dir].tuple.src.ip,
				  ct->tuplehash[!dir].tuple.src.u.all);

		/* Drop unexpected packets */
		if (!req_p) {
			DEBUGP("packet is not expected. [skip]\n");
			return NF_ACCEPT;
		}

		/* Verifies if packet is really an RPC reply packet */
		data++;
		if (IXDR_GET_INT32(data) != 1) {
			DEBUGP("packet is not a valid RPC reply. [skip]\n");
			return NF_ACCEPT;
		}

		/* Is status accept? */
		data++;
		if (IXDR_GET_INT32(data)) {
			DEBUGP("packet is not an RPC accept. [skip]\n");
			return NF_ACCEPT;
		}

		/* Get Verifier length. Jump verifier */
		data++;
		data = data + IXDR_GET_INT32(data) + 2;

		/* Is accpet status "success"? */
		if (IXDR_GET_INT32(data)) {
			DEBUGP("packet is not an RPC accept status of success. [skip]\n");
			return NF_ACCEPT;
		}

		/* Get server port number */	  
		data++;
		port_buf = (u_int16_t) IXDR_GET_INT32(data);

		/* If a packet has made it this far then it deserves an
		 * expectation ...  if port == 0, then this service is 
		 * not going to be registered.
		 */
		if (port_buf) {
			DEBUGP("port found: %u\n", port_buf);

                        exp = ip_conntrack_expect_alloc();
                        if (!exp) {
                          ret = NF_DROP;
                          goto out;
                        }

			/* Watch out, Radioactive-Man! */
			exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
			exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
			exp->mask.src.ip = 0xffffffff;
			exp->mask.dst.ip = 0xffffffff;

			switch (req_p->proto) {
				case IPPROTO_UDP:
					exp->tuple.src.u.udp.port = 0;
					exp->tuple.dst.u.udp.port = htons(port_buf);
					exp->tuple.dst.protonum = IPPROTO_UDP;
					exp->mask.src.u.udp.port = 0;
					exp->mask.dst.u.udp.port = htons(0xffff);
					exp->mask.dst.protonum = 0xff;
					break;

				case IPPROTO_TCP:
					exp->tuple.src.u.tcp.port = 0;
					exp->tuple.dst.u.tcp.port = htons(port_buf);
					exp->tuple.dst.protonum = IPPROTO_TCP;
					exp->mask.src.u.tcp.port = 0;
					exp->mask.dst.u.tcp.port = htons(0xffff);
					exp->mask.dst.protonum = 0xff;
					break;
			}
			exp->expectfn = NULL;
			exp->master = ct;

			DEBUGP("expect related ip   %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
				NIPQUAD(exp->tuple.src.ip),
				NIPQUAD(exp->tuple.dst.ip),
				port_buf, req_p->proto);

			DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
				NIPQUAD(exp->mask.src.ip),
				NIPQUAD(exp->mask.dst.ip),
				exp->mask.dst.protonum);

			if (ip_conntrack_expect_related(exp) != 0) {
		                ip_conntrack_expect_free(exp);
        		        ret = NF_DROP;
        		}
		}

out:
		req_cl(req_p);

		DEBUGP("packet evaluated. [expect]\n");
	}

	return ret;
}