/* * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: rcbopen.c,v 1.15 2005/06/02 19:00:36 ca Exp $") #include "sm/assert.h" #include "sm/magic.h" #include "sm/memops.h" #include "sm/rpool.h" #include "sm/str-int.h" #include "sm/rcb.h" #include "sm/str2rcb.h" #include "sm/reccom.h" /* ** SM_RCB_OPEN_RCV -- Open rcb for receiving data from file. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** SM_SUCCESS ** ** Last code review: 2005-03-29 17:32:35 ** Last code change: */ sm_ret_T sm_rcb_open_rcv(sm_rcb_P rcb) { SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE); #endif rcb->sm_rcb_len = 0; rcb->sm_rcb_rw = -1; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_RCV; #endif return SM_SUCCESS; } /* ** SM_RCB_OPEN_DEC -- Open rcb for decoding data. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** SM_SUCCESS (unless SM_RCB_END_RCB is set) ** ** Last code review: 2005-03-29 05:21:31 ** Last code change: */ sm_ret_T sm_rcb_open_dec(sm_rcb_P rcb) { #if SM_RCB_END_RCB uint32_t v, tl; #endif SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE); #endif #if SM_RCB_END_RCB if (rcb->sm_rcb_len < 12) return sm_error_perm(SM_EM_RECCOM, EINVAL); if ((rcb->sm_rcb_len % 4) != 0) return sm_error_perm(SM_EM_RECCOM, EINVAL); rcb->sm_rcb_rw = rcb->sm_rcb_len - 12; sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v); if (v != 4) return sm_error_perm(SM_EM_RECCOM, EINVAL); rcb->sm_rcb_rw += sizeof(uint32_t); sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v); if (v != RT_END_OF_RCB) return sm_error_perm(SM_EM_RECCOM, EINVAL); rcb->sm_rcb_rw += sizeof(uint32_t); sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v); sm_buf2uint32(rcb->sm_rcb_base, &tl); if (v != tl) return sm_error_perm(SM_EM_RECCOM, EINVAL); #endif /* SM_RCB_END_RCB */ rcb->sm_rcb_rw = 0; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_DEC; #endif return SM_SUCCESS; } /* ** SM_RCB_OPEN_ENC -- Open rcb for encoding data into it. ** ** Parameters: ** rcb -- sm_rcb_P object. ** n -- 1. maximum size for encoded data, -1: no explicit limit ** (just implicit by max length sm_rcb_max) ** 2. minimum size requested for RCB. ** fixme: should these be two different parameters?? ** Note: all applications use -1 (only test programs use ** different values). ** ** Returns: ** usual sm_error code; ENOMEM, SM_E_OVFLW_NS ** ** Side Effects: none on error. ** ** Last code review: 2005-03-22 17:44:11 ** Last code change: */ sm_ret_T sm_rcb_open_enc(sm_rcb_P rcb, int n) { SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE); #endif rcb->sm_rcb_len = 0; if (n > 0 && (uint)n > rcb->sm_rcb_size) { uint u; u = (uint)n; SM_STR_INCREASE_R(rcb, u); } rcb->sm_rcb_rw = n; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_ENC; #endif return SM_SUCCESS; } /* ** SM_RCB_OPEN_SND -- Open rcb for sending data from it. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** SM_SUCCESS ** ** Last code review: 2005-03-22 23:23:53 ** Last code change: */ sm_ret_T sm_rcb_open_snd(sm_rcb_P rcb) { SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE); #endif rcb->sm_rcb_rw = 0; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_SND; #endif return SM_SUCCESS; } /* ** SM_RCB_CLOSE_RCV -- Close rcb after receiving data from file. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** SM_SUCCESS (unless SM_RCB_END_RCB is set) ** ** Last code review: 2005-03-29 05:20:13 ** Last code change: */ sm_ret_T sm_rcb_close_rcv(sm_rcb_P rcb) { #if SM_RCB_END_RCB uint32_t v, tl; #endif SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_RCV); SM_REQUIRE(rcb->sm_rcb_size >= rcb->sm_rcb_len); SM_REQUIRE(rcb->sm_rcb_size <= rcb->sm_rcb_max); #endif #if SM_RCB_END_RCB if (rcb->sm_rcb_len < 12) return sm_error_perm(SM_EM_RECCOM, EINVAL); if ((rcb->sm_rcb_len % 4) != 0) return sm_error_perm(SM_EM_RECCOM, EINVAL); rcb->sm_rcb_rw = rcb->sm_rcb_len - 12; sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v); if (v != 4) return sm_error_perm(SM_EM_RECCOM, EINVAL); rcb->sm_rcb_rw += sizeof(uint32_t); sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v); if (v != RT_END_OF_RCB) return sm_error_perm(SM_EM_RECCOM, EINVAL); rcb->sm_rcb_rw += sizeof(uint32_t); sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v); sm_buf2uint32(rcb->sm_rcb_base, &tl); if (v != tl) return sm_error_perm(SM_EM_RECCOM, EINVAL); #endif /* SM_RCB_END_RCB */ rcb->sm_rcb_rw = 0; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_NONE; #endif return SM_SUCCESS; } /* ** SM_RCB_CLOSE_DEC -- Close rcb after decoding data. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** SM_SUCCESS ** ** Last code review: 2005-03-29 21:33:33 ** Last code change: */ sm_ret_T sm_rcb_close_dec(sm_rcb_P rcb) { SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_DEC); SM_REQUIRE(rcb->sm_rcb_size >= rcb->sm_rcb_len); SM_REQUIRE(rcb->sm_rcb_size <= rcb->sm_rcb_max); #endif rcb->sm_rcb_rw = 0; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_NONE; #endif return SM_SUCCESS; } /* ** SM_RCB_CLOSE_ENC -- Close rcb after encoding data into it. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** usual sm_error code; EINVAL (SM_RCB_END_RCB: ENOMEM, etc) ** (fails only if rcb is improperly used) ** ** Side Effects: resets state even on error. ** ** Last code review: 2005-03-22 22:58:10 ** Last code change: */ sm_ret_T sm_rcb_close_enc(sm_rcb_P rcb) { uint32_t len; #if SM_RCB_END_RCB sm_ret_T ret; #endif SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_ENC); /* reset state even if an error occurs? */ rcb->sm_rcb_state = SM_RCB_NONE; #endif /* SM_RCB_CHECK */ if (rcb->sm_rcb_len <= sizeof(int)) return sm_error_perm(SM_EM_RECCOM, EINVAL); SM_ASSERT(rcb->sm_rcb_len < UINT32_MAX); #if SM_RCB_END_RCB ret = sm_rcb_put3uint32(rcb, 4, RT_END_OF_RCB, rcb->sm_rcb_len + 12); if (sm_is_err(ret)) return ret; #endif len = (uint32_t) (rcb->sm_rcb_len); sm_uint32_2buf(len, rcb->sm_rcb_base); return SM_SUCCESS; } /* ** SM_RCB_CLOSE_SND -- Close rcb after sending data from it. ** ** Parameters: ** rcb -- sm_rcb_P object. ** ** Returns: ** SM_SUCCESS ** ** Last code review: 2005-03-30 22:51:51 ** Last code change: */ sm_ret_T sm_rcb_close_snd(sm_rcb_P rcb) { SM_IS_RCB(rcb); SM_REQUIRE(rcb->sm_rcb_base != NULL); #if SM_RCB_CHECK SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_SND); #endif rcb->sm_rcb_rw = 0; #if SM_RCB_CHECK rcb->sm_rcb_state = SM_RCB_NONE; #endif return SM_SUCCESS; }