comm.c revision 111823
164562Sgshapiro/* 2111823Sgshapiro * Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12111823SgshapiroSM_RCSID("@(#)$Id: comm.c,v 8.54.2.6 2003/01/03 22:14:40 ca Exp $") 1364562Sgshapiro 1464562Sgshapiro#include "libmilter.h" 1590792Sgshapiro#include <sm/errstring.h> 1664562Sgshapiro 1764562Sgshapiro/* 1864562Sgshapiro** MI_RD_CMD -- read a command 1964562Sgshapiro** 2064562Sgshapiro** Parameters: 2164562Sgshapiro** sd -- socket descriptor 2264562Sgshapiro** timeout -- maximum time to wait 2364562Sgshapiro** cmd -- single character command read from sd 2464562Sgshapiro** rlen -- pointer to length of result 2564562Sgshapiro** name -- name of milter 2664562Sgshapiro** 2764562Sgshapiro** Returns: 2864562Sgshapiro** buffer with rest of command 2964562Sgshapiro** (malloc()ed here, should be free()d) 3064562Sgshapiro** hack: encode error in cmd 3164562Sgshapiro*/ 3264562Sgshapiro 3364562Sgshapirochar * 3464562Sgshapiromi_rd_cmd(sd, timeout, cmd, rlen, name) 3564562Sgshapiro socket_t sd; 3664562Sgshapiro struct timeval *timeout; 3764562Sgshapiro char *cmd; 3864562Sgshapiro size_t *rlen; 3964562Sgshapiro char *name; 4064562Sgshapiro{ 4164562Sgshapiro ssize_t len; 4264562Sgshapiro mi_int32 expl; 4364562Sgshapiro ssize_t i; 44111823Sgshapiro FD_RD_VAR(rds, excs); 4564562Sgshapiro int ret; 4664562Sgshapiro int save_errno; 4764562Sgshapiro char *buf; 4864562Sgshapiro char data[MILTER_LEN_BYTES + 1]; 4964562Sgshapiro 5064562Sgshapiro *cmd = '\0'; 5164562Sgshapiro *rlen = 0; 5271345Sgshapiro 5364562Sgshapiro i = 0; 54102528Sgshapiro for (;;) 5564562Sgshapiro { 56111823Sgshapiro FD_RD_INIT(sd, rds, excs); 57111823Sgshapiro ret = FD_RD_READY(sd, rds, excs, timeout); 58102528Sgshapiro if (ret == 0) 59102528Sgshapiro break; 60102528Sgshapiro else if (ret < 0) 61102528Sgshapiro { 62102528Sgshapiro if (errno == EINTR) 63102528Sgshapiro continue; 64102528Sgshapiro break; 65102528Sgshapiro } 66111823Sgshapiro if (FD_IS_RD_EXC(sd, rds, excs)) 6764562Sgshapiro { 6864562Sgshapiro *cmd = SMFIC_SELECT; 6964562Sgshapiro return NULL; 7064562Sgshapiro } 7190792Sgshapiro 7290792Sgshapiro len = MI_SOCK_READ(sd, data + i, sizeof data - i); 7390792Sgshapiro if (MI_SOCK_READ_FAIL(len)) 7464562Sgshapiro { 7564562Sgshapiro smi_log(SMI_LOG_ERR, 7664562Sgshapiro "%s, mi_rd_cmd: read returned %d: %s", 77110560Sgshapiro name, (int) len, sm_errstring(errno)); 7864562Sgshapiro *cmd = SMFIC_RECVERR; 7964562Sgshapiro return NULL; 8064562Sgshapiro } 8164562Sgshapiro if (len == 0) 8264562Sgshapiro { 8364562Sgshapiro *cmd = SMFIC_EOF; 8464562Sgshapiro return NULL; 8564562Sgshapiro } 8664562Sgshapiro if (len >= (ssize_t) sizeof data - i) 8764562Sgshapiro break; 8864562Sgshapiro i += len; 8964562Sgshapiro } 9064562Sgshapiro if (ret == 0) 9164562Sgshapiro { 9264562Sgshapiro *cmd = SMFIC_TIMEOUT; 9364562Sgshapiro return NULL; 9464562Sgshapiro } 9564562Sgshapiro else if (ret < 0) 9664562Sgshapiro { 9764562Sgshapiro smi_log(SMI_LOG_ERR, 9864562Sgshapiro "%s: mi_rd_cmd: select returned %d: %s", 9990792Sgshapiro name, ret, sm_errstring(errno)); 10064562Sgshapiro *cmd = SMFIC_RECVERR; 10164562Sgshapiro return NULL; 10264562Sgshapiro } 10364562Sgshapiro 10464562Sgshapiro *cmd = data[MILTER_LEN_BYTES]; 10564562Sgshapiro data[MILTER_LEN_BYTES] = '\0'; 10664562Sgshapiro (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES); 10764562Sgshapiro expl = ntohl(expl) - 1; 10864562Sgshapiro if (expl <= 0) 10964562Sgshapiro return NULL; 11064562Sgshapiro if (expl > MILTER_CHUNK_SIZE) 11164562Sgshapiro { 11264562Sgshapiro *cmd = SMFIC_TOOBIG; 11364562Sgshapiro return NULL; 11464562Sgshapiro } 11590792Sgshapiro#if _FFR_ADD_NULL 11690792Sgshapiro buf = malloc(expl + 1); 11790792Sgshapiro#else /* _FFR_ADD_NULL */ 11864562Sgshapiro buf = malloc(expl); 11990792Sgshapiro#endif /* _FFR_ADD_NULL */ 12064562Sgshapiro if (buf == NULL) 12164562Sgshapiro { 12264562Sgshapiro *cmd = SMFIC_MALLOC; 12364562Sgshapiro return NULL; 12464562Sgshapiro } 12564562Sgshapiro 12664562Sgshapiro i = 0; 127102528Sgshapiro for (;;) 12864562Sgshapiro { 129111823Sgshapiro FD_RD_INIT(sd, rds, excs); 130111823Sgshapiro ret = FD_RD_READY(sd, rds, excs, timeout); 131102528Sgshapiro if (ret == 0) 132102528Sgshapiro break; 133102528Sgshapiro else if (ret < 0) 134102528Sgshapiro { 135102528Sgshapiro if (errno == EINTR) 136102528Sgshapiro continue; 137102528Sgshapiro break; 138102528Sgshapiro } 139111823Sgshapiro if (FD_IS_RD_EXC(sd, rds, excs)) 14064562Sgshapiro { 14164562Sgshapiro *cmd = SMFIC_SELECT; 14264562Sgshapiro free(buf); 14364562Sgshapiro return NULL; 14464562Sgshapiro } 14590792Sgshapiro len = MI_SOCK_READ(sd, buf + i, expl - i); 14690792Sgshapiro if (MI_SOCK_READ_FAIL(len)) 14764562Sgshapiro { 14864562Sgshapiro smi_log(SMI_LOG_ERR, 14964562Sgshapiro "%s: mi_rd_cmd: read returned %d: %s", 150110560Sgshapiro name, (int) len, sm_errstring(errno)); 15164562Sgshapiro ret = -1; 15264562Sgshapiro break; 15364562Sgshapiro } 15464562Sgshapiro if (len == 0) 15564562Sgshapiro { 15664562Sgshapiro *cmd = SMFIC_EOF; 15764562Sgshapiro free(buf); 15864562Sgshapiro return NULL; 15964562Sgshapiro } 16064562Sgshapiro if (len > expl - i) 16164562Sgshapiro { 16264562Sgshapiro *cmd = SMFIC_RECVERR; 16364562Sgshapiro free(buf); 16464562Sgshapiro return NULL; 16564562Sgshapiro } 16664562Sgshapiro if (len >= expl - i) 16764562Sgshapiro { 16864562Sgshapiro *rlen = expl; 16990792Sgshapiro#if _FFR_ADD_NULL 17090792Sgshapiro /* makes life simpler for common string routines */ 17190792Sgshapiro buf[expl] = '\0'; 17290792Sgshapiro#endif /* _FFR_ADD_NULL */ 17364562Sgshapiro return buf; 17464562Sgshapiro } 17564562Sgshapiro i += len; 17664562Sgshapiro } 17764562Sgshapiro 17864562Sgshapiro save_errno = errno; 17964562Sgshapiro free(buf); 18064562Sgshapiro 18164562Sgshapiro /* select returned 0 (timeout) or < 0 (error) */ 18264562Sgshapiro if (ret == 0) 18364562Sgshapiro { 18464562Sgshapiro *cmd = SMFIC_TIMEOUT; 18564562Sgshapiro return NULL; 18664562Sgshapiro } 18764562Sgshapiro if (ret < 0) 18864562Sgshapiro { 18964562Sgshapiro smi_log(SMI_LOG_ERR, 19064562Sgshapiro "%s: mi_rd_cmd: select returned %d: %s", 19190792Sgshapiro name, ret, sm_errstring(save_errno)); 19264562Sgshapiro *cmd = SMFIC_RECVERR; 19364562Sgshapiro return NULL; 19464562Sgshapiro } 19564562Sgshapiro *cmd = SMFIC_UNKNERR; 19664562Sgshapiro return NULL; 19764562Sgshapiro} 19890792Sgshapiro/* 19964562Sgshapiro** MI_WR_CMD -- write a cmd to sd 20064562Sgshapiro** 20164562Sgshapiro** Parameters: 20264562Sgshapiro** sd -- socket descriptor 20364562Sgshapiro** timeout -- maximum time to wait (currently unused) 20464562Sgshapiro** cmd -- single character command to write 20564562Sgshapiro** buf -- buffer with further data 20664562Sgshapiro** len -- length of buffer (without cmd!) 20764562Sgshapiro** 20864562Sgshapiro** Returns: 20964562Sgshapiro** MI_SUCCESS/MI_FAILURE 21064562Sgshapiro*/ 21164562Sgshapiro 21294334Sgshapiro/* 21394334Sgshapiro** we don't care much about the timeout here, it's very long anyway 214110560Sgshapiro** FD_SETSIZE is checked when socket is created. 21594334Sgshapiro** XXX l == 0 ? 21694334Sgshapiro*/ 21794334Sgshapiro 21894334Sgshapiro#define MI_WR(data) \ 21994334Sgshapiro while (sl > 0) \ 22094334Sgshapiro { \ 221111823Sgshapiro FD_WR_INIT(sd, wrs); \ 222111823Sgshapiro ret = FD_WR_READY(sd, wrs, timeout); \ 22394334Sgshapiro if (ret == 0) \ 22494334Sgshapiro return MI_FAILURE; \ 22594334Sgshapiro if (ret < 0) \ 22694334Sgshapiro { \ 22794334Sgshapiro if (errno == EINTR) \ 22894334Sgshapiro continue; \ 22994334Sgshapiro else \ 23094334Sgshapiro return MI_FAILURE; \ 23194334Sgshapiro } \ 23294334Sgshapiro l = MI_SOCK_WRITE(sd, (void *) ((data) + i), sl); \ 23394334Sgshapiro if (l < 0) \ 23494334Sgshapiro { \ 23594334Sgshapiro if (errno == EINTR) \ 23694334Sgshapiro continue; \ 23794334Sgshapiro else \ 23894334Sgshapiro return MI_FAILURE; \ 23994334Sgshapiro } \ 24094334Sgshapiro i += l; \ 24194334Sgshapiro sl -= l; \ 24294334Sgshapiro } 24394334Sgshapiro 24464562Sgshapiroint 24564562Sgshapiromi_wr_cmd(sd, timeout, cmd, buf, len) 24664562Sgshapiro socket_t sd; 24764562Sgshapiro struct timeval *timeout; 24864562Sgshapiro int cmd; 24964562Sgshapiro char *buf; 25064562Sgshapiro size_t len; 25164562Sgshapiro{ 25264562Sgshapiro size_t sl, i; 25364562Sgshapiro ssize_t l; 25464562Sgshapiro mi_int32 nl; 25564562Sgshapiro int ret; 256111823Sgshapiro FD_WR_VAR(wrs); 25764562Sgshapiro char data[MILTER_LEN_BYTES + 1]; 25864562Sgshapiro 25964562Sgshapiro if (len > MILTER_CHUNK_SIZE) 26064562Sgshapiro return MI_FAILURE; 26164562Sgshapiro nl = htonl(len + 1); /* add 1 for the cmd char */ 26264562Sgshapiro (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES); 26364562Sgshapiro data[MILTER_LEN_BYTES] = (char) cmd; 26464562Sgshapiro i = 0; 26564562Sgshapiro sl = MILTER_LEN_BYTES + 1; 26664562Sgshapiro 26764562Sgshapiro /* use writev() instead to send the whole stuff at once? */ 26864562Sgshapiro 26994334Sgshapiro MI_WR(data); 27064562Sgshapiro if (len > 0 && buf == NULL) 27164562Sgshapiro return MI_FAILURE; 27264562Sgshapiro if (len == 0 || buf == NULL) 27364562Sgshapiro return MI_SUCCESS; 27464562Sgshapiro i = 0; 27564562Sgshapiro sl = len; 27694334Sgshapiro MI_WR(buf); 27764562Sgshapiro return MI_SUCCESS; 27864562Sgshapiro} 279