17c478bd9Sstevel@tonic-gate /*
2*e9af4bc0SJohn Beck * Copyright (c) 1999-2004, 2009 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate *
57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate * the sendmail distribution.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate */
107c478bd9Sstevel@tonic-gate
117c478bd9Sstevel@tonic-gate #include <sm/gen.h>
12*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: comm.c,v 8.70 2009/12/16 16:33:48 ca Exp $")
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #include "libmilter.h"
157c478bd9Sstevel@tonic-gate #include <sm/errstring.h>
167c478bd9Sstevel@tonic-gate #include <sys/uio.h>
177c478bd9Sstevel@tonic-gate
187c478bd9Sstevel@tonic-gate static ssize_t retry_writev __P((socket_t, struct iovec *, int, struct timeval *));
197c478bd9Sstevel@tonic-gate static size_t Maxdatasize = MILTER_MAX_DATA_SIZE;
207c478bd9Sstevel@tonic-gate
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate ** SMFI_SETMAXDATASIZE -- set limit for milter data read/write.
237c478bd9Sstevel@tonic-gate **
247c478bd9Sstevel@tonic-gate ** Parameters:
257c478bd9Sstevel@tonic-gate ** sz -- new limit.
267c478bd9Sstevel@tonic-gate **
277c478bd9Sstevel@tonic-gate ** Returns:
287c478bd9Sstevel@tonic-gate ** old limit
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate size_t
smfi_setmaxdatasize(sz)327c478bd9Sstevel@tonic-gate smfi_setmaxdatasize(sz)
337c478bd9Sstevel@tonic-gate size_t sz;
347c478bd9Sstevel@tonic-gate {
357c478bd9Sstevel@tonic-gate size_t old;
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate old = Maxdatasize;
387c478bd9Sstevel@tonic-gate Maxdatasize = sz;
397c478bd9Sstevel@tonic-gate return old;
407c478bd9Sstevel@tonic-gate }
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate ** MI_RD_CMD -- read a command
447c478bd9Sstevel@tonic-gate **
457c478bd9Sstevel@tonic-gate ** Parameters:
467c478bd9Sstevel@tonic-gate ** sd -- socket descriptor
477c478bd9Sstevel@tonic-gate ** timeout -- maximum time to wait
487c478bd9Sstevel@tonic-gate ** cmd -- single character command read from sd
497c478bd9Sstevel@tonic-gate ** rlen -- pointer to length of result
507c478bd9Sstevel@tonic-gate ** name -- name of milter
517c478bd9Sstevel@tonic-gate **
527c478bd9Sstevel@tonic-gate ** Returns:
537c478bd9Sstevel@tonic-gate ** buffer with rest of command
547c478bd9Sstevel@tonic-gate ** (malloc()ed here, should be free()d)
557c478bd9Sstevel@tonic-gate ** hack: encode error in cmd
567c478bd9Sstevel@tonic-gate */
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate char *
mi_rd_cmd(sd,timeout,cmd,rlen,name)597c478bd9Sstevel@tonic-gate mi_rd_cmd(sd, timeout, cmd, rlen, name)
607c478bd9Sstevel@tonic-gate socket_t sd;
617c478bd9Sstevel@tonic-gate struct timeval *timeout;
627c478bd9Sstevel@tonic-gate char *cmd;
637c478bd9Sstevel@tonic-gate size_t *rlen;
647c478bd9Sstevel@tonic-gate char *name;
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate ssize_t len;
677c478bd9Sstevel@tonic-gate mi_int32 expl;
687c478bd9Sstevel@tonic-gate ssize_t i;
697c478bd9Sstevel@tonic-gate FD_RD_VAR(rds, excs);
707c478bd9Sstevel@tonic-gate int ret;
717c478bd9Sstevel@tonic-gate int save_errno;
727c478bd9Sstevel@tonic-gate char *buf;
737c478bd9Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1];
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate *cmd = '\0';
767c478bd9Sstevel@tonic-gate *rlen = 0;
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate i = 0;
797c478bd9Sstevel@tonic-gate for (;;)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate FD_RD_INIT(sd, rds, excs);
827c478bd9Sstevel@tonic-gate ret = FD_RD_READY(sd, rds, excs, timeout);
837c478bd9Sstevel@tonic-gate if (ret == 0)
847c478bd9Sstevel@tonic-gate break;
857c478bd9Sstevel@tonic-gate else if (ret < 0)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate if (errno == EINTR)
887c478bd9Sstevel@tonic-gate continue;
897c478bd9Sstevel@tonic-gate break;
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate if (FD_IS_RD_EXC(sd, rds, excs))
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate *cmd = SMFIC_SELECT;
947c478bd9Sstevel@tonic-gate return NULL;
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate len = MI_SOCK_READ(sd, data + i, sizeof data - i);
987c478bd9Sstevel@tonic-gate if (MI_SOCK_READ_FAIL(len))
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
1017c478bd9Sstevel@tonic-gate "%s, mi_rd_cmd: read returned %d: %s",
1027c478bd9Sstevel@tonic-gate name, (int) len, sm_errstring(errno));
1037c478bd9Sstevel@tonic-gate *cmd = SMFIC_RECVERR;
1047c478bd9Sstevel@tonic-gate return NULL;
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate if (len == 0)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate *cmd = SMFIC_EOF;
1097c478bd9Sstevel@tonic-gate return NULL;
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate if (len >= (ssize_t) sizeof data - i)
1127c478bd9Sstevel@tonic-gate break;
1137c478bd9Sstevel@tonic-gate i += len;
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate if (ret == 0)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate *cmd = SMFIC_TIMEOUT;
1187c478bd9Sstevel@tonic-gate return NULL;
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate else if (ret < 0)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
123*e9af4bc0SJohn Beck "%s: mi_rd_cmd: %s() returned %d: %s",
124*e9af4bc0SJohn Beck name, MI_POLLSELECT, ret, sm_errstring(errno));
1257c478bd9Sstevel@tonic-gate *cmd = SMFIC_RECVERR;
1267c478bd9Sstevel@tonic-gate return NULL;
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate *cmd = data[MILTER_LEN_BYTES];
1307c478bd9Sstevel@tonic-gate data[MILTER_LEN_BYTES] = '\0';
1317c478bd9Sstevel@tonic-gate (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
1327c478bd9Sstevel@tonic-gate expl = ntohl(expl) - 1;
1337c478bd9Sstevel@tonic-gate if (expl <= 0)
1347c478bd9Sstevel@tonic-gate return NULL;
1357c478bd9Sstevel@tonic-gate if (expl > Maxdatasize)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate *cmd = SMFIC_TOOBIG;
1387c478bd9Sstevel@tonic-gate return NULL;
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate #if _FFR_ADD_NULL
1417c478bd9Sstevel@tonic-gate buf = malloc(expl + 1);
1427c478bd9Sstevel@tonic-gate #else /* _FFR_ADD_NULL */
1437c478bd9Sstevel@tonic-gate buf = malloc(expl);
1447c478bd9Sstevel@tonic-gate #endif /* _FFR_ADD_NULL */
1457c478bd9Sstevel@tonic-gate if (buf == NULL)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate *cmd = SMFIC_MALLOC;
1487c478bd9Sstevel@tonic-gate return NULL;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate i = 0;
1527c478bd9Sstevel@tonic-gate for (;;)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate FD_RD_INIT(sd, rds, excs);
1557c478bd9Sstevel@tonic-gate ret = FD_RD_READY(sd, rds, excs, timeout);
1567c478bd9Sstevel@tonic-gate if (ret == 0)
1577c478bd9Sstevel@tonic-gate break;
1587c478bd9Sstevel@tonic-gate else if (ret < 0)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate if (errno == EINTR)
1617c478bd9Sstevel@tonic-gate continue;
1627c478bd9Sstevel@tonic-gate break;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate if (FD_IS_RD_EXC(sd, rds, excs))
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate *cmd = SMFIC_SELECT;
1677c478bd9Sstevel@tonic-gate free(buf);
1687c478bd9Sstevel@tonic-gate return NULL;
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate len = MI_SOCK_READ(sd, buf + i, expl - i);
1717c478bd9Sstevel@tonic-gate if (MI_SOCK_READ_FAIL(len))
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
1747c478bd9Sstevel@tonic-gate "%s: mi_rd_cmd: read returned %d: %s",
1757c478bd9Sstevel@tonic-gate name, (int) len, sm_errstring(errno));
1767c478bd9Sstevel@tonic-gate ret = -1;
1777c478bd9Sstevel@tonic-gate break;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate if (len == 0)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate *cmd = SMFIC_EOF;
1827c478bd9Sstevel@tonic-gate free(buf);
1837c478bd9Sstevel@tonic-gate return NULL;
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate if (len > expl - i)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate *cmd = SMFIC_RECVERR;
1887c478bd9Sstevel@tonic-gate free(buf);
1897c478bd9Sstevel@tonic-gate return NULL;
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate if (len >= expl - i)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate *rlen = expl;
1947c478bd9Sstevel@tonic-gate #if _FFR_ADD_NULL
1957c478bd9Sstevel@tonic-gate /* makes life simpler for common string routines */
1967c478bd9Sstevel@tonic-gate buf[expl] = '\0';
1977c478bd9Sstevel@tonic-gate #endif /* _FFR_ADD_NULL */
1987c478bd9Sstevel@tonic-gate return buf;
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate i += len;
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate save_errno = errno;
2047c478bd9Sstevel@tonic-gate free(buf);
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate /* select returned 0 (timeout) or < 0 (error) */
2077c478bd9Sstevel@tonic-gate if (ret == 0)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate *cmd = SMFIC_TIMEOUT;
2107c478bd9Sstevel@tonic-gate return NULL;
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate if (ret < 0)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
215*e9af4bc0SJohn Beck "%s: mi_rd_cmd: %s() returned %d: %s",
216*e9af4bc0SJohn Beck name, MI_POLLSELECT, ret, sm_errstring(save_errno));
2177c478bd9Sstevel@tonic-gate *cmd = SMFIC_RECVERR;
2187c478bd9Sstevel@tonic-gate return NULL;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate *cmd = SMFIC_UNKNERR;
2217c478bd9Sstevel@tonic-gate return NULL;
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate ** RETRY_WRITEV -- Keep calling the writev() system call
2267c478bd9Sstevel@tonic-gate ** until all the data is written out or an error occurs.
2277c478bd9Sstevel@tonic-gate **
2287c478bd9Sstevel@tonic-gate ** Parameters:
2297c478bd9Sstevel@tonic-gate ** fd -- socket descriptor
2307c478bd9Sstevel@tonic-gate ** iov -- io vector
2317c478bd9Sstevel@tonic-gate ** iovcnt -- number of elements in io vector
2327c478bd9Sstevel@tonic-gate ** must NOT exceed UIO_MAXIOV.
2337c478bd9Sstevel@tonic-gate ** timeout -- maximum time to wait
2347c478bd9Sstevel@tonic-gate **
2357c478bd9Sstevel@tonic-gate ** Returns:
2367c478bd9Sstevel@tonic-gate ** success: number of bytes written
2377c478bd9Sstevel@tonic-gate ** otherwise: MI_FAILURE
2387c478bd9Sstevel@tonic-gate */
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate static ssize_t
retry_writev(fd,iov,iovcnt,timeout)2417c478bd9Sstevel@tonic-gate retry_writev(fd, iov, iovcnt, timeout)
2427c478bd9Sstevel@tonic-gate socket_t fd;
2437c478bd9Sstevel@tonic-gate struct iovec *iov;
2447c478bd9Sstevel@tonic-gate int iovcnt;
2457c478bd9Sstevel@tonic-gate struct timeval *timeout;
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate int i;
2487c478bd9Sstevel@tonic-gate ssize_t n, written;
2497c478bd9Sstevel@tonic-gate FD_WR_VAR(wrs);
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate written = 0;
2527c478bd9Sstevel@tonic-gate for (;;)
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate while (iovcnt > 0 && iov[0].iov_len == 0)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate iov++;
2577c478bd9Sstevel@tonic-gate iovcnt--;
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate if (iovcnt <= 0)
2607c478bd9Sstevel@tonic-gate return written;
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate ** We don't care much about the timeout here,
2647c478bd9Sstevel@tonic-gate ** it's very long anyway; correct solution would be
2657c478bd9Sstevel@tonic-gate ** to take the time before the loop and reduce the
2667c478bd9Sstevel@tonic-gate ** timeout after each invocation.
2677c478bd9Sstevel@tonic-gate ** FD_SETSIZE is checked when socket is created.
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate FD_WR_INIT(fd, wrs);
2717c478bd9Sstevel@tonic-gate i = FD_WR_READY(fd, wrs, timeout);
2727c478bd9Sstevel@tonic-gate if (i == 0)
2737c478bd9Sstevel@tonic-gate return MI_FAILURE;
2747c478bd9Sstevel@tonic-gate if (i < 0)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN)
2777c478bd9Sstevel@tonic-gate continue;
2787c478bd9Sstevel@tonic-gate return MI_FAILURE;
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate n = writev(fd, iov, iovcnt);
2817c478bd9Sstevel@tonic-gate if (n == -1)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN)
2847c478bd9Sstevel@tonic-gate continue;
2857c478bd9Sstevel@tonic-gate return MI_FAILURE;
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate written += n;
2897c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++)
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate if (iov[i].iov_len > (unsigned int) n)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate iov[i].iov_base = (char *)iov[i].iov_base + n;
2947c478bd9Sstevel@tonic-gate iov[i].iov_len -= (unsigned int) n;
2957c478bd9Sstevel@tonic-gate break;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate n -= (int) iov[i].iov_len;
2987c478bd9Sstevel@tonic-gate iov[i].iov_len = 0;
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate if (i == iovcnt)
3017c478bd9Sstevel@tonic-gate return written;
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate ** MI_WR_CMD -- write a cmd to sd
3077c478bd9Sstevel@tonic-gate **
3087c478bd9Sstevel@tonic-gate ** Parameters:
3097c478bd9Sstevel@tonic-gate ** sd -- socket descriptor
3107c478bd9Sstevel@tonic-gate ** timeout -- maximum time to wait
3117c478bd9Sstevel@tonic-gate ** cmd -- single character command to write
3127c478bd9Sstevel@tonic-gate ** buf -- buffer with further data
3137c478bd9Sstevel@tonic-gate ** len -- length of buffer (without cmd!)
3147c478bd9Sstevel@tonic-gate **
3157c478bd9Sstevel@tonic-gate ** Returns:
3167c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
3177c478bd9Sstevel@tonic-gate */
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate int
mi_wr_cmd(sd,timeout,cmd,buf,len)3207c478bd9Sstevel@tonic-gate mi_wr_cmd(sd, timeout, cmd, buf, len)
3217c478bd9Sstevel@tonic-gate socket_t sd;
3227c478bd9Sstevel@tonic-gate struct timeval *timeout;
3237c478bd9Sstevel@tonic-gate int cmd;
3247c478bd9Sstevel@tonic-gate char *buf;
3257c478bd9Sstevel@tonic-gate size_t len;
3267c478bd9Sstevel@tonic-gate {
327*e9af4bc0SJohn Beck size_t sl;
3287c478bd9Sstevel@tonic-gate ssize_t l;
3297c478bd9Sstevel@tonic-gate mi_int32 nl;
3307c478bd9Sstevel@tonic-gate int iovcnt;
3317c478bd9Sstevel@tonic-gate struct iovec iov[2];
3327c478bd9Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1];
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate if (len > Maxdatasize || (len > 0 && buf == NULL))
3357c478bd9Sstevel@tonic-gate return MI_FAILURE;
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate nl = htonl(len + 1); /* add 1 for the cmd char */
3387c478bd9Sstevel@tonic-gate (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
3397c478bd9Sstevel@tonic-gate data[MILTER_LEN_BYTES] = (char) cmd;
3407c478bd9Sstevel@tonic-gate sl = MILTER_LEN_BYTES + 1;
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /* set up the vector for the size / command */
3437c478bd9Sstevel@tonic-gate iov[0].iov_base = (void *) data;
3447c478bd9Sstevel@tonic-gate iov[0].iov_len = sl;
3457c478bd9Sstevel@tonic-gate iovcnt = 1;
3467c478bd9Sstevel@tonic-gate if (len >= 0 && buf != NULL)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate iov[1].iov_base = (void *) buf;
3497c478bd9Sstevel@tonic-gate iov[1].iov_len = len;
3507c478bd9Sstevel@tonic-gate iovcnt = 2;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate l = retry_writev(sd, iov, iovcnt, timeout);
3547c478bd9Sstevel@tonic-gate if (l == MI_FAILURE)
3557c478bd9Sstevel@tonic-gate return MI_FAILURE;
3567c478bd9Sstevel@tonic-gate return MI_SUCCESS;
3577c478bd9Sstevel@tonic-gate }
358