#define __KAVCLIENTSTUB_C #include #include #include #include #include #include #include "kavsockets.h" #include "kavcommand.h" #include "kavclientstub.h" #include "kaverrors.h" int kavProcess(const char *fname, const char *sock, const char *sender, const char *rcpts, const char *qid, const char *clid, const char *serverip, struct kavHeaderList **headers, char **rejectMsg) { int ret = 0; int s, sockFamily; struct kavCommandStruct *request = 0; struct kavCommandStruct *response = 0; // connect to kavmd if ((s = kavSocketConnect(sock, &sockFamily)) == -1) return (-1); // create the structure used for sending the scan request if ((request = kavCommandConstruct(CMD_FAMILY_REQUEST)) == 0) { kavSocketClose(s); return (CMD_MTA_ACTION_TEMPFAIL); } // fill the request structure with data if (fillRequest(sender, rcpts, qid, clid, serverip, request) == -1) { kavSocketClose(s); kavCommandDestroy(&request); return (CMD_MTA_ACTION_TEMPFAIL); } // create the structure used for receiving the response if ((response = kavCommandConstruct(CMD_FAMILY_RESPONSE)) == 0) { kavSocketClose(s); kavCommandDestroy(&request); return (CMD_MTA_ACTION_TEMPFAIL); } // connect to server switch (sockFamily) { case KAV_SOCK_INET: ret = processRemote( fname, s, request, response); break; case KAV_SOCK_UNIX: ret = processLocal( fname, s, request, response); break; } if (ret != CMD_MTA_ACTION_TEMPFAIL) { // if not temp. failure, process the response: // - identify return code // - extract headers // - extract reject message if (processResponse(response, headers, rejectMsg) == -1) ret = CMD_MTA_ACTION_TEMPFAIL; } // cleanup kavSocketClose(s); kavCommandDestroy(&response); kavCommandDestroy(&request); return (ret); } static int processLocal(const char *fname, int sock, struct kavCommandStruct *request, struct kavCommandStruct *response) { // remote scan does not need a file path kavCommandParamAdd(request, CMD_REQUEST_SCAN_LOCAL, fname, strlen(fname)); // serialize the structure on socket "s" if (kavCommandSerialize(request, sock) == -1) return (CMD_MTA_ACTION_TEMPFAIL); // deserialize the answer from socket "sock" if (kavCommandDeserialize(response, sock) == -1) return (CMD_MTA_ACTION_TEMPFAIL); return (response->maction); } static int processRemote(const char *fname, int sock, struct kavCommandStruct *request, struct kavCommandStruct *response) { // remote scan does not need a file path kavCommandParamAdd(request, CMD_REQUEST_SCAN_REMOTE, "", 0); // serialize the structure on socket "s" if (kavCommandSerialize(request, sock) == -1) return (CMD_MTA_ACTION_TEMPFAIL); // since this is a remote scan request, the file // needs to be sent through the socket if (sendFile(fname, sock) == -1) return (CMD_MTA_ACTION_TEMPFAIL); // deserialize the answer from socket "sock" if (kavCommandDeserialize(response, sock) == -1) return (CMD_MTA_ACTION_TEMPFAIL); // receive the processed file if (recvFile(fname, sock) == -1) return (CMD_MTA_ACTION_TEMPFAIL); return (response->maction); } int fillRequest(const char *sender, const char *rcpts, const char *qid, const char *clid, const char *serverip, struct kavCommandStruct *request) { // add sender information if (sender != 0 && sender[0] != '\0') if (kavCommandParamAdd(request, CMD_PARAM_SENDER, sender, strlen(sender)) == 0) return (-1); // add recipients information if (rcpts != 0 && rcpts[0] != '\0') { char *strtok_context; char *r = strtok_r((char *) rcpts, ", ", &strtok_context); do { if (kavCommandParamAdd(request, CMD_PARAM_RECIPIENT, r, strlen(r)) == 0) return (-1); r = strtok_r(0, ", ", &strtok_context); } while (r != 0); } // add queue id information if (qid != 0 && qid[0] != '\0') if (kavCommandParamAdd(request, CMD_PARAM_QID, qid, strlen(qid)) == 0) return (-1); // add client id/ip information if (clid != 0 && clid[0] != '\0') if (kavCommandParamAdd(request, CMD_PARAM_CLIENTID, clid, strlen(clid)) == 0) return (-1); // add server ip information if (serverip != 0 && serverip[0] != '\0') if (kavCommandParamAdd(request, CMD_PARAM_SRVIP, serverip, strlen(serverip)) == 0) return (-1); return (0); } static int processResponse(struct kavCommandStruct *response, struct kavHeaderList **headers, char **rejectMsg) { struct kavParamList *p = 0; // extract reject message and headers for (p = response->params; p != 0; p = p->next) { if (p->data.id == CMD_PARAM_HEADER) { // add header to header list if (headerAdd(headers, p->data.value, p->data.size) == 0) { headersDestroy(headers); if (*rejectMsg != 0) { free(*rejectMsg); *rejectMsg = 0; } } } else if (p->data.id == CMD_PARAM_REJECTMSG) { // if rejectMsg was already set, just ignore it if (*rejectMsg != 0) continue; if ((*rejectMsg = malloc(p->data.size + 1)) != 0) { strncpy(*rejectMsg, p->data.value, p->data.size); rejectMsg[p->data.size] = 0; } else { kavSetError("Cannot allocate memory"); return (-1); } } } return (0); } static int sendFile(const char *fname, const int sock) { char buf[BUFSIZE]; int fd; int size; // open file while ((fd = open(fname, O_RDWR)) == -1 && errno == EINTR) { } if (fd == -1) { kavSetError(strerror(errno)); return (-1); } // get file size size = lseek(fd, 0, SEEK_END); // reset file offset lseek(fd, 0, SEEK_SET); // send size size = htonl(size); if (kavSocketWrite(sock, &size, sizeof(size)) == -1) { close(fd); return (-1); } // read and send file do { while ((size = read(fd, &buf, sizeof(buf))) == -1 && errno == EINTR) { } if (size > 0) { if (kavSocketWrite(sock, &buf, size) == -1) { close(fd); return (-1); } } } while (size > 0); if (size == -1) kavSetError(strerror(errno)); close(fd); // return 0 for success, -1 for error return (size == -1 ? -1 : 0); } static int recvFile(const char *fname, const int sock) { char buf[BUFSIZE]; int fd; int ret = 0; unsigned int size; // open file while ((fd = open(fname, O_RDWR | O_TRUNC)) == -1 && errno == EINTR) { } if (fd == -1) { kavSetError(strerror(errno)); return (-1); } // get file size if (kavSocketRead(sock, &size, sizeof(size)) == -1) { close(fd); return (-1); } size = ntohl(size); // receive and write to file do { ret = kavSocketRead(sock, &buf, size < sizeof(buf) ? size : sizeof(buf)); if (ret > 0) { while ((ret = write(fd, &buf, ret)) == -1 && errno == EINTR) { } // if ret is -1 (error), value of size is not // important anymore size -= ret; } } while (ret > 0 && size > 0); if (ret == -1) kavSetError(strerror(errno)); close(fd); // return 0 for success, -1 for error return (ret == -1 ? -1 : 0); } static struct kavHeaderList *headerAdd(struct kavHeaderList **h, const char * const data, const int slen) { // allocate memory for structure struct kavHeaderList *it; struct kavHeaderList *hh = calloc(1, sizeof(struct kavHeaderList)); if (hh == 0) { kavSetError("Cannot allocate memory"); return (0); } // set the data for the node if ((hh->data.data = malloc(slen + 1)) == 0) // +1 for NUL terminator { free(hh); kavSetError("Cannot allocate memory"); return (0); } strncpy(hh->data.data, data, slen); hh->data.data[slen] = 0; // NUL terminator hh->data.slen = slen; // append node into list if (*h == 0) // this is the first node *h = hh; else { // find last node for (it = *h; it->next != 0; it = it->next) { } // append new node it->next = hh; } return (hh); } static void headersDestroy(struct kavHeaderList **h) { struct kavHeaderList *it = *h; // iterate through list and free members while (it != 0) { struct kavHeaderList *tmp = it->next; if (it->data.data != 0) free(it->data.data); free(it); it = tmp; } *h = 0; }