Exemple #1
0
static void imap_handle_continue(ImapSession *session)
{
	if (session->state < CLIENTSTATE_LOGOUT) {
		if (session->buff && p_string_len(session->buff) > 0) {
			int e = 0;
			if ((e = ci_write(session->ci, "%s", (char *)p_string_str(session->buff))) < 0) {
				int serr = errno;
				TRACE(TRACE_DEBUG,"ci_write returned error [%s]", strerror(serr));
				imap_handle_abort(session);
				return;
			}
			dbmail_imap_session_buff_clear(session);
		}
		if (p_string_len(session->ci->write_buffer) > session->ci->write_buffer_offset)
			ci_write(session->ci, NULL);
		if (session->command_state == TRUE)
			imap_session_reset(session);
	} else {
		dbmail_imap_session_buff_clear(session);
	}				

	// handle buffered pending input
	if (p_string_len(session->ci->read_buffer) > 0)
		imap_handle_input(session);
}
Exemple #2
0
int pop3_error(ClientSession_T * session, const char *formatstring, ...)
{
    va_list ap, cp;
    char *s;
    ClientBase_T *ci = session->ci;

    if (session->error_count >= MAX_ERRORS) {
        ci_write(ci, "-ERR too many errors\r\n");
        return -3;
    }
    va_start(ap, formatstring);
    va_copy(cp, ap);
    s = g_strdup_vprintf(formatstring, cp);
    va_end(cp);
    va_end(ap);
    ci_write(ci, s);
    g_free(s);

    if (ci->client_state & CLIENT_ERR) {
        return -3;
    }

    TRACE(TRACE_DEBUG, "an invalid command was issued");
    session->error_count++;
    return 1;
}
Exemple #3
0
void send_greeting(ClientSession_T *session)
{
	Field_T banner;
	GETCONFIGVALUE("banner", "LMTP", banner);
	if (! dm_db_ping()) {
		ci_write(session->ci, "500 database has gone fishing BYE\r\n");
		session->state = QUIT;
		return;
	}

	if (strlen(banner) > 0)
		ci_write(session->ci, "220 %s %s\r\n", session->hostname, banner);
	else
		ci_write(session->ci, "220 %s LMTP\r\n", session->hostname);
}
Exemple #4
0
static void send_greeting(ClientSession_T *session)
{
    Field_T banner;
    GETCONFIGVALUE("banner", "POP", banner);
    if (! dm_db_ping()) {
        ci_write(session->ci, "+ERR database has gone fishing\r\n");
        session->state = CLIENTSTATE_QUIT;
        return;
    }

    if (strlen(banner) > 0) {
        ci_write(session->ci, "+OK %s %s\r\n", banner, session->apop_stamp);
    } else {
        ci_write(session->ci, "+OK DBMAIL pop3 server ready to rock %s\r\n", session->apop_stamp);
    }
}
Exemple #5
0
static int _pop3_session_authenticated(ClientSession_T *session, int user_idnr)
{
    ClientBase_T *ci = session->ci;
    int result = 0;

    session->state = CLIENTSTATE_AUTHENTICATED;

    ci_authlog_init(ci, THIS_MODULE, (const char *)session->username, AUTHLOG_ACT);
    client_session_set_timeout(session, server_conf->timeout);

    /* user seems to be valid, let's build a session */
    TRACE(TRACE_DEBUG, "validation OK, building a session for user [%s]",
          session->username);

    /* if pop_before_smtp is active, log this ip */
    if (pop_before_smtp)
        db_log_ip(ci->src_ip);

    result = db_createsession(user_idnr, session);
    if (result == 1) {
        ci_write(ci, "+OK %s has %" PRIu64 " messages (%" PRIu64 " octets)\r\n",
                 session->username,
                 session->virtual_totalmessages,
                 session->virtual_totalsize);
        TRACE(TRACE_NOTICE, "user %s logged in [messages=%" PRIu64 ", octets=%" PRIu64 "]",
              session->username,
              session->virtual_totalmessages,
              session->virtual_totalsize);
    } else
        session->SessionResult = 4;	/* Database error. */

    return result;
}
Exemple #6
0
int ec_responce_with_istag(ci_request_t * req, int ec)
{
     char buf[256];
     ci_service_xdata_t *srv_xdata;
     int len;
     srv_xdata = service_data(req->current_service_mod);
     ci_headers_reset(req->response_header);
     snprintf(buf, 256, "ICAP/1.0 %d %s",
              ci_error_code(ec), ci_error_code_string(ec));
     ci_headers_add(req->response_header, buf);
     ci_headers_add(req->response_header, "Server: C-ICAP/" VERSION);
     if (req->keepalive)
          ci_headers_add(req->response_header, "Connection: keep-alive");
     else
          ci_headers_add(req->response_header, "Connection: close");

     ci_service_data_read_lock(srv_xdata);
     ci_headers_add(req->response_header, srv_xdata->ISTag);
     ci_service_data_read_unlock(srv_xdata);
     if (!ci_headers_is_empty(req->xheaders)) {
	  ci_headers_addheaders(req->response_header, req->xheaders);
     }
     ci_headers_pack(req->response_header);

     len = ci_write(req->connection->fd, 
		    req->response_header->buf, req->response_header->bufused, 
		    TIMEOUT);
     if (len < 0)
	 return -1;

     req->bytes_out += len;
     return len;
}
Exemple #7
0
/* 
 * only the main thread may write to the network event
 * worker threads must use an async queue
 */
static int64_t imap_session_printf(ImapSession * session, char * message, ...)
{
        va_list ap, cp;
        uint64_t l;
	int e = 0;

	p_string_truncate(session->buff, 0);

        assert(message);
        va_start(ap, message);
	va_copy(cp, ap);
        p_string_append_vprintf(session->buff, message, cp);
        va_end(cp);
        va_end(ap);

	if ((e = ci_write(session->ci, (char *)p_string_str(session->buff))) < 0) {
		TRACE(TRACE_DEBUG, "ci_write failed [%d]", e);
		imap_handle_abort(session);
		return e;
	}

        l = p_string_len(session->buff);
	p_string_truncate(session->buff, 0);

        return (int64_t)l;
}
Exemple #8
0
static void pop3_close(ClientSession_T *session)
{
    ClientBase_T *ci = session->ci;
    TRACE(TRACE_DEBUG,"[%p] sessionResult [%d]", session, session->SessionResult);

    session->state = CLIENTSTATE_QUIT;

    if (session->username != NULL && (session->was_apop || session->password != NULL)) {

        switch (session->SessionResult) {
        case 0:
            TRACE(TRACE_NOTICE, "user %s logging out [messages=%" PRIu64 ", octets=%" PRIu64 "]",
                  session->username,
                  session->virtual_totalmessages,
                  session->virtual_totalsize);

            /* if everything went well, write down everything and do a cleanup */
            if (db_update_pop(session) == DM_SUCCESS)
                ci_write(ci, "+OK see ya later\r\n");
            else
                ci_write(ci, "-ERR some deleted messages not removed\r\n");
            break;

        case 1:
            ci_write(ci, "-ERR I'm leaving, you're too slow\r\n");
            TRACE(TRACE_ERR, "client timed out, connection closed");
            break;

        case 2:
            TRACE(TRACE_ERR, "alert! possible flood attempt, closing connection");
            break;

        case 3:
            TRACE(TRACE_ERR, "authorization layer failure");
            break;
        case 4:
            TRACE(TRACE_ERR, "storage layer failure");
            break;
        }
    } else {
        ci_write(ci, "+OK see ya later\r\n");
    }
}
Exemple #9
0
void ec_responce(ci_request_t * req, int ec)
{
     char buf[256];
     int len;
     snprintf(buf, 256, "ICAP/1.0 %d %s\r\n\r\n",
              ci_error_code(ec), ci_error_code_string(ec));
     buf[255] = '\0';
     len = strlen(buf);
     ci_write(req->connection->fd, buf, len, TIMEOUT);
     req->bytes_out += len;
}
Exemple #10
0
int lmtp_error(ClientSession_T * session, const char *formatstring, ...)
{
	va_list ap, cp;
	char *s;

	if (session->error_count >= MAX_ERRORS) {
		ci_write(session->ci, "500 Too many errors, closing connection.\r\n");
		session->SessionResult = 2;	/* possible flood */
		return -3;
	}

	va_start(ap, formatstring);
	va_copy(cp, ap);
	s = g_strdup_vprintf(formatstring, cp);
	va_end(cp);
	ci_write(session->ci, s);
	g_free(s);

	session->error_count++;
	return -1;
}
Exemple #11
0
int ci_writen(int fd, char *buf, int len, int timeout)
{
     int ret = 0, remains;
     remains = len;
     while (remains) {
          if ((ret = ci_write(fd, buf, remains, timeout)) < 0)
               return ret;
          buf += ret;
          remains -= ret;
     }
     return len;
}
Exemple #12
0
int tims_error(ClientSession_t * session, const char *formatstring, ...)
{
	va_list ap, cp;
	char *s;

	if (session->error_count >= MAX_ERRORS) {
		ci_write(session->ci, "BYE \"Too many errors, closing connection.\"\r\n");
		session->SessionResult = 2;	/* possible flood */
		return -3;
	}

	va_start(ap, formatstring);
	va_copy(cp, ap);
	s = g_strdup_vprintf(formatstring, cp);
	va_end(cp);

	ci_write(session->ci, s);
	g_free(s);

	TRACE(TRACE_DEBUG, "an invalid command was issued");
	session->error_count++;
	return 1;
}
Exemple #13
0
static void pop3_handle_input(void *arg)
{
	char buffer[MAX_LINESIZE];	/* connection buffer */
	ClientSession_t *session = (ClientSession_t *)arg;

	if (session->ci->write_buffer->len) {
		ci_write(session->ci, NULL);
		return;
	}

	memset(buffer, 0, sizeof(buffer));
	if (ci_readln(session->ci, buffer) == 0)
		return;

	pop3(session, buffer);
}
Exemple #14
0
int recycle_request(ci_request_t * req, ci_connection_t * connection)
{
     int access;
     int len;

     ci_request_reset(req);
     ci_copy_connection(req->connection, connection);

     if ((access = access_check_client(req)) == CI_ACCESS_DENY) { /*Check for client access */
          len = strlen(FORBITTEN_STR);
          ci_write(connection->fd, FORBITTEN_STR, len, TIMEOUT);
          return 0;             /*Or something that means authentication error */
     }
     req->access_type = access;
     return 1;
}
Exemple #15
0
void tims_cb_write(void *arg)
{
	ClientSession_t *session = (ClientSession_t *)arg;
	TRACE(TRACE_DEBUG, "[%p] state: [%d]", session, session->state);

	switch(session->state) {
		case QUIT:
			client_session_bailout(&session);
			break;
		default:
			if (session->ci->write_buffer->len > session->ci->write_buffer_offset) {
				ci_write(session->ci,NULL);
				break;
			}
			session->handle_input(session);
			break;
	}
}
Exemple #16
0
void tims_cb_write(void *arg)
{
	ClientSession_T *session = (ClientSession_T *)arg;
	int state = session->state;

	TRACE(TRACE_DEBUG, "[%p] state: [%d]", session, state);

	switch(state) {
		case CLIENTSTATE_QUIT_QUEUED:
		case CLIENTSTATE_QUIT:
			break;
		default:
			if (p_string_len(session->ci->write_buffer) > session->ci->write_buffer_offset) {
				ci_write(session->ci,NULL);
				break;
			}
			session->handle_input(session);
			break;
	}
}
Exemple #17
0
static void pop3_handle_input(void *arg)
{
    char buffer[MAX_LINESIZE];	/* connection buffer */
    ClientSession_T *session = (ClientSession_T *)arg;

    if (p_string_len(session->ci->write_buffer)) {
        ci_write(session->ci, NULL);
        return;
    }

    memset(buffer, 0, sizeof(buffer));
    if (ci_readln(session->ci, buffer) == 0)
        return;

    ci_cork(session->ci);
    if (pop3(session, buffer) <= 0) {
        client_session_bailout(&session);
        return;
    }
    ci_uncork(session->ci);
}
Exemple #18
0
ci_request_t *newrequest(ci_connection_t * connection)
{
     ci_request_t *req;
     int access;
     int len;
     ci_connection_t *conn;

     conn = (ci_connection_t *) malloc(sizeof(ci_connection_t));
     ci_copy_connection(conn, connection);
     req = ci_request_alloc(conn);

     if ((access = access_check_client(req)) == CI_ACCESS_DENY) { /*Check for client access */
          len = strlen(FORBITTEN_STR);
          ci_write(connection->fd, FORBITTEN_STR, len, TIMEOUT);
	  ci_request_destroy(req);
          return NULL;          /*Or something that means authentication error */
     }


     req->access_type = access;
     return req;
}
Exemple #19
0
static void send_greeting(ClientSession_t *session)
{
	field_t banner;
	GETCONFIGVALUE("banner", "SIEVE", banner);
	if (! dm_db_ping()) {
		ci_write(session->ci, "BYE \"database has gone fishing\"\r\n");
		session->state = QUIT;
		return;
	}

	if (strlen(banner) > 0)
		ci_write(session->ci, "\"IMPLEMENTATION\" \"%s\"\r\n", banner);
	else
		ci_write(session->ci, "\"IMPLEMENTATION\" \"DBMail timsieved %s\"\r\n", VERSION);
	ci_write(session->ci, "\"SASL\" \"PLAIN\"\r\n");
	ci_write(session->ci, "\"SIEVE\" \"%s\"\r\n", sieve_extensions);
	ci_write(session->ci, "OK\r\n");
}
Exemple #20
0
int lmtp_tokenizer(ClientSession_T *session, char *buffer)
{
	char *command = NULL, *value;
	int command_type = 0;

	if (! session->command_type) {
		session->parser_state = FALSE;

		command = buffer;
		strip_crlf(command);
		g_strstrip(command);
		if (! strlen(command)) return FALSE; /* ignore empty commands */

		value = strstr(command, " ");	/* look for the separator */

		if (value) {
			*value++ = '\0';	/* set a \0 on the command end */

			if (strlen(value) == 0)
				value = NULL;	/* no value specified */
		}

		for (command_type = LMTP_LHLO; command_type < LMTP_END; command_type++)
			if (strcasecmp(command, commands[command_type]) == 0)
				break;

		/* Invalid command */
		if (command_type == LMTP_END)
			return lmtp_error(session, "500 Invalid command.\r\n");

		/* Commands that are allowed to have no arguments */
		if ((value == NULL) &&
		    !((command_type == LMTP_LHLO) || (command_type == LMTP_DATA) ||
		      (command_type == LMTP_RSET) || (command_type == LMTP_QUIT) ||
		      (command_type == LMTP_NOOP) || (command_type == LMTP_HELP) )) {
			return lmtp_error(session, "500 This command requires an argument.\r\n");
		}
		session->command_type = command_type;

		if (value) session->args = g_list_append(session->args, g_strdup(value));

	}

	if (session->command_type == LMTP_DATA) {
		if (command) {
			if (session->state != AUTH) {
				return lmtp_error(session, "550 Command out of sequence\r\n");
			}
			if (g_list_length(session->rcpt) < 1) {
				return lmtp_error(session, "503 No valid recipients\r\n");
			}
			if (g_list_length(session->from) < 1) {
				return lmtp_error(session, "554 No valid sender.\r\n");
			}
			ci_write(session->ci, "354 Start mail input; end with <CRLF>.<CRLF>\r\n");
			return FALSE;
		}

		if (strncmp(buffer,".\n",2)==0 || strncmp(buffer,".\r\n",3)==0)
			session->parser_state = TRUE;
		else if (strncmp(buffer,".",1)==0)
			g_string_append(session->rbuff, &buffer[1]);
		else
			g_string_append(session->rbuff, buffer);
	} else
		session->parser_state = TRUE;

	TRACE(TRACE_DEBUG, "[%p] cmd [%d], state [%d] [%s]", session, session->command_type, session->parser_state, buffer);

	return session->parser_state;
}
Exemple #21
0
int tims(ClientSession_t *session)
{
	/* returns values:
	 *  0 to quit
	 * -1 on failure
	 *  1 on success */
	
	char *arg;
	size_t scriptlen = 0;
	int ret;
	char *script = NULL, *scriptname = NULL;
	sort_result_t *sort_result = NULL;
	clientbase_t *ci = session->ci;

	TRACE(TRACE_DEBUG,"[%p] [%d][%s]", session, session->command_type, commands[session->command_type]);
	switch (session->command_type) {
	case TIMS_LOUT:
		ci_write(ci, "OK \"Bye.\"\r\n");
		session->state = QUIT;
		return 1;
		
	case TIMS_STLS:
		ci_write(ci, "NO\r\n");
		return 1;
		
	case TIMS_CAPA:
		send_greeting(session);
		return 1;
		
	case TIMS_AUTH:
		/* We currently only support plain authentication,
		 * which means that the command we accept will look
		 * like this: Authenticate "PLAIN" "base64-password"
		 * */
		session->args = g_list_first(session->args);
		if (! (session->args && session->args->data))
			return 1;

		arg = (char *)session->args->data;
		if (strcasecmp(arg, "PLAIN") == 0) {
			int i = 0;
			u64_t useridnr;
			if (! g_list_next(session->args))
				return tims_error(session, "NO \"Missing argument.\"\r\n");	
			session->args = g_list_next(session->args);
			arg = (char *)session->args->data;

			char **tmp64 = NULL;

			tmp64 = base64_decodev(arg);
			if (tmp64 == NULL)
				return tims_error(session, "NO \"SASL decode error.\"\r\n");
			for (i = 0; tmp64[i] != NULL; i++)
				;
			if (i < 3)
				tims_error(session, "NO \"Too few encoded SASL arguments.\"\r\n");

			/* The protocol specifies that the base64 encoding
			 * be made up of three parts: proxy, username, password
			 * Between them are NULLs, which are conveniently encoded
			 * by the base64 process... */
			if (auth_validate(ci, tmp64[1], tmp64[2], &useridnr) == 1) {
				ci_authlog_init(ci, THIS_MODULE, tmp64[1], AUTHLOG_ACT);

				ci_write(ci, "OK\r\n");
				session->state = AUTH;
				session->useridnr = useridnr;
				session->username = g_strdup(tmp64[1]);
				session->password = g_strdup(tmp64[2]);

				client_session_set_timeout(session, server_conf->timeout);

			} else {
				ci_authlog_init(ci, THIS_MODULE, tmp64[1], AUTHLOG_ERR);
				g_strfreev(tmp64);
				return tims_error(session, "NO \"Username or password incorrect.\"\r\n");
			}
			g_strfreev(tmp64);
		} else
			return tims_error(session, "NO \"Authentication scheme not supported.\"\r\n");

		return 1;

	case TIMS_PUTS:
		if (session->state != AUTH) {
			ci_write(ci, "NO \"Please authenticate first.\"\r\n");
			break;
		}
		
		session->args = g_list_first(session->args);
		if (! (session->args && session->args->data))
			return 1;

		scriptname = (char *)session->args->data;
		session->args = g_list_next(session->args);
		assert(session->args);

		script = (char *)session->args->data;

		scriptlen = strlen(script);
		TRACE(TRACE_INFO, "Client sending script of length [%ld]", scriptlen);
		if (scriptlen >= UINT_MAX)
			return tims_error(session, "NO \"Invalid script length.\"\r\n");

		if (dm_sievescript_quota_check(session->useridnr, scriptlen))
			return tims_error(session, "NO \"Script exceeds available space.\"\r\n");

		/* Store the script temporarily,
		 * validate it, then rename it. */
		if (dm_sievescript_add(session->useridnr, "@!temp-script!@", script)) {
			dm_sievescript_delete(session->useridnr, "@!temp-script!@");
			return tims_error(session, "NO \"Error inserting script.\"\r\n");
		}
		
		sort_result = sort_validate(session->useridnr, "@!temp-script!@");
		if (sort_result == NULL) {
			dm_sievescript_delete(session->useridnr, "@!temp-script!@");
			return tims_error(session, "NO \"Error inserting script.\"\r\n");
		} else if (sort_get_error(sort_result) > 0) {
			dm_sievescript_delete(session->useridnr, "@!temp-script!@");
			return tims_error(session, "NO \"Script error: %s.\"\r\n", sort_get_errormsg(sort_result));
		} 
		/* According to the draft RFC, a script with the same
		 * name as an existing script should [atomically] replace it. */
		if (dm_sievescript_rename(session->useridnr, "@!temp-script!@", scriptname))
			return tims_error(session, "NO \"Error inserting script.\"\r\n");

		ci_write(ci, "OK \"Script successfully received.\"\r\n");

		break;
		
	case TIMS_SETS:
		if (session->state != AUTH) {
			ci_write(ci, "NO \"Please authenticate first.\"\r\n");
			break;
		}
		

		scriptname = NULL;

		session->args = g_list_first(session->args);
		if ((session->args && session->args->data))
			scriptname = (char *)session->args->data;

		if (strlen(scriptname)) {
			if (! dm_sievescript_activate(session->useridnr, scriptname))
				ci_write(ci, "NO \"Error activating script.\"\r\n");
			else
				ci_write(ci, "OK \"Script activated.\"\r\n");
		} else {
			ret = dm_sievescript_get(session->useridnr, &scriptname);
			if (scriptname == NULL) {
				ci_write(ci, "OK \"No scripts are active at this time.\"\r\n");
			} else {
				if (! dm_sievescript_deactivate(session->useridnr, scriptname))
					ci_write(ci, "NO \"Error deactivating script.\"\r\n");
				else
					ci_write(ci, "OK \"All scripts deactivated.\"\r\n");
				g_free(scriptname);
			}
		}
		return 1;
		
	case TIMS_GETS:
		if (session->state != AUTH) {
			ci_write(ci, "NO \"Please authenticate first.\"\r\n");
			break;
		}
		
		session->args = g_list_first(session->args);
		if (! (session->args && session->args->data))
			return 1;

		scriptname = (char *)session->args->data;

		if (! strlen(scriptname))
			return tims_error(session, "NO \"Script name required.\"\r\n");

		ret = dm_sievescript_getbyname(session->useridnr, scriptname, &script);
		if (script == NULL) {
			return tims_error(session, "NO \"Script not found.\"\r\n");
		} else if (ret < 0) {
			g_free(script);
			return tims_error(session, "NO \"Internal error.\"\r\n");
		} else {
			ci_write(ci, "{%u+}\r\n", (unsigned int)strlen(script));
			ci_write(ci, "%s\r\n", script);
			ci_write(ci, "OK\r\n");
			g_free(script);
		}
		return 1;
		
	case TIMS_DELS:
		if (session->state != AUTH) {
			ci_write(ci, "NO \"Please authenticate first.\"\r\n");
			break;
		}
		
		session->args = g_list_first(session->args);
		if (! (session->args && session->args->data))
			return 1;

		scriptname = (char *)session->args->data;

		if (! strlen(scriptname))
			return tims_error(session, "NO \"Script name required.\"\r\n");

		if (! dm_sievescript_delete(session->useridnr, scriptname))
			return tims_error(session, "NO \"Error deleting script.\"\r\n");
		else
			ci_write(ci, "OK \"Script deleted.\"\r\n", scriptname);

		return 1;

	case TIMS_SPAC:
		if (session->state != AUTH) {
			ci_write(ci, "NO \"Please authenticate first.\"\r\n");
			break;
		}

		// Command is in format: HAVESPACE "scriptname" 12345
		// TODO: this is a fake
		if (dm_sievescript_quota_check(session->useridnr, 12345) == DM_SUCCESS)
			ci_write(ci, "OK (QUOTA)\r\n");
		else
			ci_write(ci, "NO (QUOTA) \"Quota exceeded\"\r\n");
		return 1;
		
	case TIMS_LIST:
		if (session->state != AUTH) {
			ci_write(ci, "NO \"Please authenticate first.\"\r\n");
			break;
		}
		
		GList *scriptlist = NULL;

		if (dm_sievescript_list (session->useridnr, &scriptlist) < 0) {
			ci_write(ci, "NO \"Internal error.\"\r\n");
		} else {
			if (g_list_length(scriptlist) == 0) {
				/* The command hasn't failed, but there aren't any scripts */
				ci_write(ci, "OK \"No scripts found.\"\r\n");
			} else {
				scriptlist = g_list_first(scriptlist);
				while (scriptlist) {
					sievescript_info_t *info = (sievescript_info_t *) scriptlist->data;
					ci_write(ci, "\"%s\"%s\r\n", info->name, (info-> active == 1 ?  " ACTIVE" : ""));
					if (! g_list_next(scriptlist)) break;
					scriptlist = g_list_next(scriptlist);
				}
				ci_write(ci, "OK\r\n");
			}
			g_list_destroy(scriptlist);
		}
		return 1;
		
	default:
		return tims_error(session, "NO \"What are you trying to say here?\"\r\n");
	}

	if (sort_result)
		sort_free_result(sort_result);
	
	return 1;
}
Exemple #22
0
void imap_handle_input(ImapSession *session)
{
	char buffer[MAX_LINESIZE];
	char *alloc_buf = NULL;
	uint64_t alloc_size = 0;
	int l, result;

	assert(session && session->ci && session->ci->write_buffer);

	// first flush the output buffer
	if (p_string_len(session->ci->write_buffer)) {
		TRACE(TRACE_DEBUG,"[%p] write buffer not empty", session);
		ci_write(session->ci, NULL);
	}

	// nothing left to handle
	if (p_string_len(session->ci->read_buffer) == 0) {
		TRACE(TRACE_DEBUG,"[%p] read buffer empty", session);
		return;
	}

	// command in progress
	if (session->command_state == FALSE && session->parser_state == TRUE) {
		TRACE(TRACE_DEBUG,"[%p] command in-progress", session);
		return;
	}

	// reset if we're done with the previous command
	if (session->command_state == TRUE)
		imap_session_reset(session);


	// Read in a line at a time if we don't have a string literal size defined
	// Otherwise read in rbuff_size amount of data
	while (TRUE) {
		char *input = NULL;
		FREE_ALLOC_BUF
		memset(buffer, 0, sizeof(buffer));

		if (session->ci->rbuff_size <= 0) {
			l = ci_readln(session->ci, buffer);
		} else {
			alloc_size = session->ci->rbuff_size+1;
			alloc_buf = mempool_pop(session->pool, alloc_size);
			l = ci_read(session->ci, alloc_buf, session->ci->rbuff_size);
		}

		if (l == 0) break; // done

		if (session->error_count >= MAX_FAULTY_RESPONSES) {
			imap_session_printf(session, "* BYE [TRY RFC]\r\n");
			imap_handle_abort(session);
			break;
		}

		// session is in a IDLE loop
		if (session->command_type == IMAP_COMM_IDLE  && session->command_state == IDLE) { 
			if (strlen(buffer) > 4 && strncasecmp(buffer,"DONE",4)==0)
				imap_session_printf(session, "%s OK IDLE terminated\r\n", session->tag);
			else
				imap_session_printf(session,"%s BAD Expecting DONE\r\n", session->tag);

			session->command_state = TRUE; // done
			imap_session_reset(session);

			continue;
		}

		if (alloc_buf != NULL)
			input = alloc_buf;
		else
			input = buffer;

		if (! imap4_tokenizer(session, input)) {
			FREE_ALLOC_BUF
			continue;
		}

		if ( session->parser_state < 0 ) {
			imap_session_printf(session, "%s BAD parse error\r\n", session->tag);
			imap_handle_retry(session);
			break;
		}

		if ( session->parser_state ) {
			result = imap4(session);
			TRACE(TRACE_DEBUG,"imap4 returned [%d]", result);
			if (result || (session->command_type == IMAP_COMM_IDLE && session->command_state == IDLE)) { 
				imap_handle_exit(session, result);
			}
			break;
		}

		if (session->state == CLIENTSTATE_ERROR) {
			TRACE(TRACE_NOTICE, "session->state: ERROR. abort");
			break;
		}
	}
Exemple #23
0
void tims_cb_time(void * arg)
{
	ClientSession_t *session = (ClientSession_t *)arg;
	session->state = QUIT;
	ci_write(session->ci, "BYE \"Connection timed out.\"\r\n");
}
Exemple #24
0
void pop3_cb_time(void * arg)
{
    ClientSession_T *session = (ClientSession_T *)arg;
    ci_write(session->ci, "-ERR I'm leaving, you're too slow\r\n");
    client_session_bailout(&session);
}
Exemple #25
0
static void lmtp_cb_time(void *arg)
{
	ClientSession_T *session = (ClientSession_T *)arg;
	session->state = QUIT;
	ci_write(session->ci, "221 Connection timeout BYE\r\n");
}
Exemple #26
0
int pop3(ClientSession_T *session, const char *buffer)
{
    /* returns a 0  on a quit
     *           -1  on a failure
     *            1  on a success
     */
    char *command, *value, *searchptr, *enctype, *s;
    Pop3Cmd cmdtype;
    int found = 0;
    //int indx = 0;
    int validate_result;
    bool login_disabled = FALSE;
    uint64_t result, top_lines, top_messageid, user_idnr;
    unsigned char *md5_apop_he;
    struct message *msg;
    ClientBase_T *ci = session->ci;

    s = (char *)buffer;

    strip_crlf(s);
    g_strstrip(s);

    TRACE(TRACE_DEBUG, "incoming buffer: [%s]", s);
    if (! strlen(s)) return 1;

    int state = session->state;
    /* check for command issued */
    /*
    while (strchr(ValidNetworkChars, s[indx++]))
    	;
    	*/

    command = s;

    value = strstr(command, " ");	/* look for the separator */

    if (value != NULL) {
        *value = '\0';	/* set a \0 on the command end */
        value++;	/* skip space */

        if (strlen(value) == 0)
            value = NULL;	/* no value specified */
        else {
            TRACE(TRACE_DEBUG, "state[%d], command issued :cmd [%s], value [%s]\n", state, command, value);
        }
    }

    /* find command that was issued */
    for (cmdtype = POP3_QUIT; cmdtype < POP3_FAIL; cmdtype++)
        if (strcasecmp(command, commands[cmdtype]) == 0) {
            session->was_apop = 1;
            break;
        }

    TRACE(TRACE_DEBUG, "command looked up as commandtype %d",
          cmdtype);

    /* commands that are allowed to have no arguments */
    if (value == NULL) {
        switch (cmdtype) {
        case POP3_QUIT:
        case POP3_LIST:
        case POP3_STAT:
        case POP3_RSET:
        case POP3_NOOP:
        case POP3_LAST:
        case POP3_UIDL:
        case POP3_AUTH:
        case POP3_CAPA:
        case POP3_STLS:
            break;
        default:
            return pop3_error(session, "-ERR your command does not compute\r\n");
            break;
        }
    }

    if (state == CLIENTSTATE_INITIAL_CONNECT) {
        if (server_conf->ssl) {
            Field_T val;
            GETCONFIGVALUE("login_disabled", "POP", val);
            if (SMATCH(val, "yes"))
                login_disabled = TRUE;
        }
    }

    switch (cmdtype) {

    case POP3_QUIT:
        /* We return 0 here, and then pop3_handle_connection cleans up
         * the connection, commits all changes, and sends the final
         * "OK" message indicating that QUIT has completed. */
        session->state = CLIENTSTATE_LOGOUT;

        session->SessionResult = 0;
        pop3_close(session);
        return 0;

    case POP3_STLS:
        if (state != CLIENTSTATE_INITIAL_CONNECT)
            return pop3_error(session, "-ERR wrong command mode\r\n");
        if (! server_conf->ssl)
            return pop3_error(session, "-ERR server error\r\n");

        if (session->ci->sock->ssl_state)
            return pop3_error(session, "-ERR TLS already active\r\n");
        ci_write(session->ci, "+OK Begin TLS now\r\n");
        if (ci_starttls(session->ci) < 0) return -1;
        return 1;

    case POP3_USER:
        if (state != CLIENTSTATE_INITIAL_CONNECT)
            return pop3_error(session, "-ERR wrong command mode\r\n");

        if (login_disabled && ! session->ci->sock->ssl_state)
            return pop3_error(session, "-ERR try STLS\r\n");

        if (session->username != NULL) {
            /* reset username */
            g_free(session->username);
            session->username = NULL;
        }

        if (session->username == NULL) {
            /* create memspace for username */
            session->username = g_new0(char,strlen(value) + 1);
            strncpy(session->username, value, strlen(value) + 1);
        }

        ci_write(ci, "+OK Password required for %s\r\n", session->username);
        return 1;

    case POP3_PASS:
        if (state != CLIENTSTATE_INITIAL_CONNECT)
            return pop3_error(session, "-ERR wrong command mode\r\n");

        if (login_disabled && ! session->ci->sock->ssl_state)
            return pop3_error(session, "-ERR try STLS\r\n");

        if (session->password != NULL) {
            g_free(session->password);
            session->password = NULL;
        }

        if (session->password == NULL) {
            /* create memspace for password */
            session->password = g_new0(char,strlen(value) + 1);
            strncpy(session->password, value, strlen(value) + 1);
        }
Exemple #27
0
int lmtp(ClientSession_T * session)
{
	DbmailMessage *msg;
	ClientBase_T *ci = session->ci;
	int helpcmd;
	const char *class, *subject, *detail;
	size_t tmplen = 0, tmppos = 0;
	char *tmpaddr = NULL, *tmpbody = NULL, *arg;

	switch (session->command_type) {

	case LMTP_QUIT:
		ci_write(ci, "221 %s BYE\r\n", session->hostname);
		session->state = QUIT;
		return 1;

	case LMTP_NOOP:
		ci_write(ci, "250 OK\r\n");
		return 1;

	case LMTP_RSET:
		ci_write(ci, "250 OK\r\n");
		lmtp_rset(session,TRUE);
		return 1;

	case LMTP_LHLO:
		/* Reply wth our hostname and a list of features.
		 * The RFC requires a couple of SMTP extensions
		 * with a MUST statement, so just hardcode them.
		 * */
		ci_write(ci, "250-%s\r\n250-PIPELINING\r\n"
			"250-ENHANCEDSTATUSCODES\r\n250 SIZE\r\n", 
			session->hostname);
				/* This is a SHOULD implement:
				 * "250-8BITMIME\r\n"
				 * Might as well do these, too:
				 * "250-CHUNKING\r\n"
				 * "250-BINARYMIME\r\n"
				 * */
		client_session_reset(session);
		session->state = AUTH;
		client_session_set_timeout(session, server_conf->timeout);

		return 1;

	case LMTP_HELP:
	
		session->args = g_list_first(session->args);
		if (session->args && session->args->data)
			arg = (char *)session->args->data;
		else
			arg = NULL;

		if (arg == NULL)
			helpcmd = LMTP_END;
		else
			for (helpcmd = LMTP_LHLO; helpcmd < LMTP_END; helpcmd++)
				if (strcasecmp (arg, commands[helpcmd]) == 0)
					break;

		TRACE(TRACE_DEBUG, "LMTP_HELP requested for commandtype %d", helpcmd);

		if ((helpcmd == LMTP_LHLO) || (helpcmd == LMTP_DATA) || 
			(helpcmd == LMTP_RSET) || (helpcmd == LMTP_QUIT) || 
			(helpcmd == LMTP_NOOP) || (helpcmd == LMTP_HELP)) {
			ci_write(ci, "%s", LMTP_HELP_TEXT[helpcmd]);
		} else
			ci_write(ci, "%s", LMTP_HELP_TEXT[LMTP_END]);
		return 1;

	case LMTP_VRFY:
		/* RFC 2821 says this SHOULD be implemented...
		 * and the goal is to say if the given address
		 * is a valid delivery address at this server. */
		ci_write(ci, "502 Command not implemented\r\n");
		return 1;

	case LMTP_EXPN:
		/* RFC 2821 says this SHOULD be implemented...
		 * and the goal is to return the membership
		 * of the specified mailing list. */
		ci_write(ci, "502 Command not implemented\r\n");
		return 1;

	case LMTP_MAIL:
		/* We need to LHLO first because the client
		 * needs to know what extensions we support.
		 * */
		if (session->state != AUTH) {
			ci_write(ci, "550 Command out of sequence.\r\n");
			return 1;
		} 
		if (g_list_length(session->from) > 0) {
			ci_write(ci, "500 Sender already received. Use RSET to clear.\r\n");
			return 1;
		}
		/* First look for an email address.
		 * Don't bother verifying or whatever,
		 * just find something between angle brackets!
		 * */

		session->args = g_list_first(session->args);
		if (! (session->args && session->args->data))
			return 1;
		arg = (char *)session->args->data;

		if (find_bounded(arg, '<', '>', &tmpaddr, &tmplen, &tmppos) < 0) {
			ci_write(ci, "500 No address found. Missing <> boundries.\r\n");
			return 1;
		}

		/* Second look for a BODY keyword.
		 * See if it has an argument, and if we
		 * support that feature. Don't give an OK
		 * if we can't handle it yet, like 8BIT!
		 * */

		/* Find the '=' following the address
		 * then advance one character past it
		 * (but only if there's more string!)
		 * */
		if ((tmpbody = strstr(arg + tmppos, "=")) != NULL)
			if (strlen(tmpbody))
				tmpbody++;

		/* This is all a bit nested now... */
		if (tmpbody) {
			if (MATCH(tmpbody, "8BITMIME")) {   // RFC1652
				ci_write(ci, "500 Please use 7BIT MIME only.\r\n");
				return 1;
			}
			if (MATCH(tmpbody, "BINARYMIME")) { // RFC3030
				ci_write(ci, "500 Please use 7BIT MIME only.\r\n");
				return 1;
			}
		}

		session->from = g_list_prepend(session->from, g_strdup(tmpaddr));
		ci_write(ci, "250 Sender <%s> OK\r\n", (char *)(session->from->data));

		g_free(tmpaddr);

		return 1;

	case LMTP_RCPT:
		if (session->state != AUTH) {
			ci_write(ci, "550 Command out of sequence.\r\n");
			return 1;
		} 

		session->args = g_list_first(session->args);
		if (! (session->args && session->args->data))
			return 1;
		arg = (char *)session->args->data;

		if (find_bounded(arg, '<', '>', &tmpaddr, &tmplen, &tmppos) < 0 || tmplen < 1) {
			ci_write(ci, "500 No address found. Missing <> boundries or address is null.\r\n");
			return 1;
		}

		Delivery_T *dsnuser = g_new0(Delivery_T,1);

		dsnuser_init(dsnuser);

		/* find_bounded() allocated tmpaddr for us, and that's ok
		 * since dsnuser_free() will free it for us later on. */
		dsnuser->address = tmpaddr;

		if (dsnuser_resolve(dsnuser) != 0) {
			TRACE(TRACE_ERR, "dsnuser_resolve_list failed");
			ci_write(ci, "430 Temporary failure in recipient lookup\r\n");
			dsnuser_free(dsnuser);
			g_free(dsnuser);
			return 1;
		}

		/* Class 2 means the address was deliverable in some way. */
		switch (dsnuser->dsn.class) {
			case DSN_CLASS_OK:
				ci_write(ci, "250 Recipient <%s> OK\r\n", dsnuser->address);
				session->rcpt = g_list_prepend(session->rcpt, dsnuser);
				break;
			default:
				ci_write(ci, "550 Recipient <%s> FAIL\r\n", dsnuser->address);
				dsnuser_free(dsnuser);
				g_free(dsnuser);
				break;
		}
		return 1;

	/* Here's where it gets really exciting! */
	case LMTP_DATA:
		msg = dbmail_message_new();
		dbmail_message_init_with_string(msg, session->rbuff);
		dbmail_message_set_header(msg, "Return-Path", (char *)session->from->data);
		g_string_truncate(session->rbuff,0);
		g_string_maybe_shrink(session->rbuff);

		if (insert_messages(msg, session->rcpt) == -1) {
			ci_write(ci, "430 Message not received\r\n");
			dbmail_message_free(msg);
			return 1;
		}
		/* The DATA command itself it not given a reply except
		 * that of the status of each of the remaining recipients. */

		/* The replies MUST be in the order received */
		session->rcpt = g_list_reverse(session->rcpt);
		while (session->rcpt) {
			Delivery_T * dsnuser = (Delivery_T *)session->rcpt->data;
			dsn_tostring(dsnuser->dsn, &class, &subject, &detail);

			/* Give a simple OK, otherwise a detailed message. */
			switch (dsnuser->dsn.class) {
				case DSN_CLASS_OK:
					ci_write(ci, "%d%d%d Recipient <%s> OK\r\n",
							dsnuser->dsn.class, dsnuser->dsn.subject, dsnuser->dsn.detail,
							dsnuser->address);
					break;
				default:
					ci_write(ci, "%d%d%d Recipient <%s> %s %s %s\r\n",
							dsnuser->dsn.class, dsnuser->dsn.subject, dsnuser->dsn.detail,
							dsnuser->address, class, subject, detail);
			}

			if (! g_list_next(session->rcpt)) break;
			session->rcpt = g_list_next(session->rcpt);
		}
		dbmail_message_free(msg);
		/* Reset the session after a successful delivery;
		 * MTA's like Exim prefer to immediately begin the
		 * next delivery without an RSET or a reconnect. */
		lmtp_rset(session,TRUE);
		return 1;

	default:
		return lmtp_error(session, "500 What are you trying to say here?\r\n");

	}
	return 1;
}
Exemple #28
0
void pop3_cb_time(void * arg)
{
	ClientSession_t *session = (ClientSession_t *)arg;
	session->state = CLIENTSTATE_QUIT;
	ci_write(session->ci, "-ERR I'm leaving, you're too slow\r\n");
}