Ejemplo n.º 1
0
void	iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg)
{	/* note extraarg is not currently used */
	int4			length, flags, timeout, msec_timeout, status, status2, len, errlen, devlen, tls_errno, save_errno;
	io_desc			*iod;
	d_socket_struct 	*dsocketptr;
	socket_struct		*socketptr;
	char			optionstr[MAX_TLSOPTION], idstr[MAX_TLSID_LEN], passwordstr[GTM_PASSPHRASE_MAX_ASCII + 1];
	const char		*errp;
	tls_option		option;
	gtm_tls_socket_t	*tlssocket;
	ABS_TIME		cur_time, end_time;
#	ifdef USE_POLL
	struct pollfd		fds;
#	else
	fd_set			fds, *readfds, *writefds;
	struct timeval		timeout_spec, *timeout_ptr;
#	endif

	iod = io_curr_device.out;
	assert(gtmsocket == iod->type);
	dsocketptr = (d_socket_struct *)iod->dev_sp;
	if (0 >= dsocketptr->n_socket)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV);
		return;
	}
	if (dsocketptr->n_socket <= dsocketptr->current_socket)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
		return;
	}
	if (dsocketptr->mupintr)
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
	socketptr = dsocketptr->socket[dsocketptr->current_socket];
	ENSURE_DATA_SOCKET(socketptr);
	if (socket_tcpip != socketptr->protocol)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, RTS_ERROR_MVAL(optionmval),
			LEN_AND_LIT("but socket is not TCP"));
		return;
	}
	if (socket_connected != socketptr->state)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("/TLS"),
			LEN_AND_LIT("but socket not connected"));
		return;
	}
	if (NULL != tlsid)
	{
		length = tlsid->str.len;
		if (MAX_TLSID_LEN < (length + 1))	/* for null */
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("TLSID"), LEN_AND_LIT("too long"));
			return;
		}
		STRNCPY_STR(idstr, tlsid->str.addr, length);
		idstr[length] = '\0';
	} else
		idstr[0] = '\0';
	if (NULL != password)
	{
		length = password->str.len;
		if (GTM_PASSPHRASE_MAX_ASCII < length)
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("passphrase"),
				LEN_AND_LIT("too long"));
			return;
		}
		STRNCPY_STR(passwordstr, password->str.addr, length);
		passwordstr[length] = '\0';
	} else
		passwordstr[0] = '\0';
	length = MIN(MAX_TLSOPTION, optionmval->str.len);
	lower_to_upper((uchar_ptr_t)optionstr, (uchar_ptr_t)optionmval->str.addr, length);
	if (0 == memcmp(optionstr, "CLIENT", length))
		option = tlsopt_client;
	else if (0 == memcmp(optionstr, "SERVER", length))
		option = tlsopt_server;
	else if (0 == memcmp(optionstr, "RENEGOTIATE", length))
		option = tlsopt_renegotiate;
	else
		option = tlsopt_invalid;
	memcpy(iod->dollar.device, "0", SIZEOF("0"));
	if (NO_M_TIMEOUT != timeoutarg)
	{
		msec_timeout = timeout2msec(timeoutarg);
		sys_get_curr_time(&cur_time);
		add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
	} else
		msec_timeout = -1;
	if ((tlsopt_client == option) || (tlsopt_server == option))
	{	/* most of the setup is common */
		if (socketptr->tlsenabled)
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
				LEN_AND_LIT("but TLS already enabled"));
			return;
		}
		assertpro((0 >= socketptr->buffered_length) && (0 >= socketptr->obuffer_length));
		if (NULL == tls_ctx)
		{	/* first use of TLS */
			if (-1 == gtm_tls_loadlibrary())
			{
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSDLLNOOPEN, 0, ERR_TEXT, 2, LEN_AND_STR(dl_err));
				return;
			}
			if (NULL == (tls_ctx = (gtm_tls_init(GTM_TLS_API_VERSION, GTMTLS_OP_INTERACTIVE_MODE))))
			{
				errp = gtm_tls_get_error();
				len = SIZEOF(ONE_COMMA) - 1;
				memcpy(iod->dollar.device, ONE_COMMA, len);
				errlen = STRLEN(errp);
				devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
				memcpy(&iod->dollar.device[len], errp, devlen + 1);
				if (devlen < errlen)
					iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
				if (socketptr->ioerror)
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSINIT, 0, ERR_TEXT, 2, errlen, errp);
				if (NO_M_TIMEOUT != timeoutarg)
					dollar_truth = FALSE;
				return;
			}
		}
		socketptr->tlsenabled = TRUE;
		flags = GTMTLS_OP_SOCKET_DEV | ((tlsopt_client == option) ? GTMTLS_OP_CLIENT_MODE : 0);
		socketptr->tlssocket = gtm_tls_socket(tls_ctx, NULL, socketptr->sd, idstr, flags);
		if (NULL == socketptr->tlssocket)
		{
			socketptr->tlsenabled = FALSE;
			errp = gtm_tls_get_error();
			len = SIZEOF(ONE_COMMA) - 1;
			memcpy(iod->dollar.device, ONE_COMMA, len);
			errlen = STRLEN(errp);
			devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
			memcpy(&iod->dollar.device[len], errp, devlen + 1);
			if (devlen < errlen)
				iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
			if (socketptr->ioerror)
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp);
			if (NO_M_TIMEOUT != timeoutarg)
				dollar_truth = FALSE;
			return;
		}
		status = 0;
#		ifndef	USE_POLL
		if (NO_M_TIMEOUT == timeoutarg)
			timeout_ptr = NULL;
		else
		{
			timeout_spec.tv_sec = msec_timeout / 1000;
			timeout_spec.tv_usec = (msec_timeout % 1000) * 1000;	/* remainder in millsecs to microsecs */
			timeout_ptr = &timeout_spec;
		}
#		endif
		do
		{
			status2 = 0;
			if (0 != status)
			{
#				ifdef USE_POLL
				fds.fd = socketptr->sd;
				fds.events = (GTMTLS_WANT_READ == status) ? POLLIN : POLLOUT;
#				else
				readfds = writefds = NULL;
				assertpro(FD_SETSIZE > socketptr->sd);
				FD_ZERO(&fds);
				FD_SET(socketptr->sd, &fds);
				writefds = (GTMTLS_WANT_WRITE == status) ? &fds : NULL;
				readfds = (GTMTLS_WANT_READ == status) ? &fds : NULL;
#				endif
				POLL_ONLY(if (-1 == (status2 = poll(&fds, 1, msec_timeout))))
				SELECT_ONLY(if (-1 == (status2 = select(socketptr->sd + 1, readfds, writefds, NULL, timeout_ptr))))
				{
					save_errno = errno;
					if (EAGAIN == save_errno)
					{
						rel_quant();	/* allow resources to become available */
						status2 = 0;	/* treat as timeout */
					} else if (EINTR == save_errno)
						status2 = 0;
				}
			} else
				status2 = 1;	/* do accept/connect first time */
			if (0 < status2)
			{
				if (tlsopt_server == option)
					status = gtm_tls_accept((gtm_tls_socket_t *)socketptr->tlssocket);
				else
					status = gtm_tls_connect((gtm_tls_socket_t *)socketptr->tlssocket);
			}
			if ((0 > status2) || ((status != 0) && ((GTMTLS_WANT_READ != status) && (GTMTLS_WANT_WRITE != status))))
			{
				if (0 != status)
				{
					tls_errno = gtm_tls_errno();
					if (0 > tls_errno)
						errp = gtm_tls_get_error();
					else
						errp = STRERROR(tls_errno);
				} else
					errp = STRERROR(save_errno);
				socketptr->tlsenabled = FALSE;
				len = SIZEOF(ONE_COMMA) - 1;
				memcpy(iod->dollar.device, ONE_COMMA, len);
				errlen = STRLEN(errp);
				devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
				memcpy(&iod->dollar.device[len], errp, devlen + 1);
				if (devlen < errlen)
					iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
				if (socketptr->ioerror)
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSHANDSHAKE, 0,
						ERR_TEXT, 2, errlen, errp);
				return;
			}
			if ((0 != status) && (0 <= status2))	/* not accepted/connected and not error */
			{	/* check for timeout if not error or want read or write */
				if ((0 != timeoutarg) && (NO_M_TIMEOUT != timeoutarg))
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					if (0 >= cur_time.at_sec)
					{	/* no more time */
						gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
						socketptr->tlsenabled = FALSE;
						dollar_truth = FALSE;
						return;
					} else
					{	/* adjust msec_timeout for poll/select */
#					ifdef	USE_POLL
						msec_timeout = (cur_time.at_sec * 1000) + (cur_time.at_usec / 1000);
#					else
						timeout_spec.tv_sec = cur_time.at_sec;
						timeout_spec.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
#					endif
					}
				} else if (0 == timeoutarg)
				{	/* only one chance */
					gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
					socketptr->tlsenabled = FALSE;
					dollar_truth = FALSE;
					return;
				}
				continue;
			}
		} while ((GTMTLS_WANT_READ == status) || (GTMTLS_WANT_WRITE == status));
		/* turn on output buffering */
		if (0 == socketptr->obuffer_size)
			socketptr->obuffer_size = socketptr->buffer_size;
		socketptr->obuffer_length = socketptr->obuffer_offset = 0;
		socketptr->obuffer_wait_time = DEFAULT_WRITE_WAIT;
		socketptr->obuffer_flush_time = DEFAULT_WRITE_WAIT * 2;	/* until add device parameter */
		socketptr->obuffer = malloc(socketptr->obuffer_size);
	} else if (tlsopt_renegotiate == option)
Ejemplo n.º 2
0
int gtm_main (int argc, char **argv, char **envp)
#ifdef __osf__
# pragma pointer_size (restore)
#endif
{
	char			*ptr, *eq, **p;
	int             	eof, parse_ret;
	int			gtmcrypt_errno;
#	ifdef GTM_SOCKET_SSL_SUPPORT
	int			status;
	char			tlsid_env_name[MAX_TLSID_LEN * 2];
#	endif
	DCL_THREADGBL_ACCESS;

	GTM_THREADGBL_INIT;
	gtmenvp = envp;
	gtm_dist_ok_to_use = TRUE;
	common_startup_init(GTM_IMAGE);
	GTMTRIG_DBG_ONLY(ch_at_trigger_init = &mdb_condition_handler);
	err_init(stop_image_conditional_core);
	UNICODE_ONLY(gtm_strToTitle_ptr = &gtm_strToTitle);
	GTM_ICU_INIT_IF_NEEDED;	/* Note: should be invoked after err_init (since it may error out) and before CLI parsing */
	cli_lex_setup(argc, argv);
	/* put the arguments into buffer, then clean up the token buffer
	 * cli_gettoken() copies all arguments except the first one argv[0]
	 * into the buffer (cli_lex_in_ptr->in_str).
	 * i.e. command line: "/usr/library/V990/mumps -run somefile"
	 * the buffer cli_lex_in_ptr->in_str == "-run somefile"
	 */
	if (1 < argc)
		cli_gettoken(&eof);
	/* cli_gettoken() extracts the first token into cli_token_buf (in tok_extract())
	 * which should be done in parse_cmd(), So, reset the token buffer here to make
	 * parse_cmd() starts from the first token
	*/
	cli_token_buf[0] = '\0';
	/* insert the "MUMPS " in the parsing buffer the buffer is now:
	 * cli_lex_in_ptr->in_str == "MUMPS -run somefile"
	 * we didnot change argv[0]
	*/
	ptr = cli_lex_in_ptr->in_str;
	memmove(strlen("MUMPS ") + ptr, ptr, strlen(ptr) + 1);	/* BYPASSOK */
	MEMCPY_LIT(ptr, "MUMPS ");
	/* reset the argument buffer pointer, it's changed in cli_gettoken() call above
	 * do NOT reset to 0(NULL) to avoid fetching cmd line args into buffer again
	 * cli_lex_in_ptr->tp is the pointer to indicate current position in the buffer
	 * cli_lex_in_ptr->in_str
	 */
	cli_lex_in_ptr->tp = cli_lex_in_ptr->in_str;
	parse_ret = parse_cmd();
	if (parse_ret && (EOF != parse_ret))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) parse_ret, 2, LEN_AND_STR(cli_err_str));
	if (cli_present("DIRECT_MODE"))
		invocation_mode = MUMPS_DIRECT;
	else if (cli_present("RUN"))
		invocation_mode = MUMPS_RUN;
	gtm_chk_dist(argv[0]);
	/* this should be after cli_lex_setup() due to S390 A/E conversion in cli_lex_setup   */
	init_gtm();
#	ifdef GTM_TLS
	if (MUMPS_COMPILE != invocation_mode)
	{
		if ((NULL != (ptr = (char *)getenv(GTM_PASSWD_ENV))) && (0 == strlen(ptr)))
		{
			INIT_PROC_ENCRYPTION(NULL, gtmcrypt_errno);
			if (0 != gtmcrypt_errno)
			{
				CLEAR_CRYPTERR_MASK(gtmcrypt_errno);
				assert(!IS_REPEAT_MSG_MASK(gtmcrypt_errno));
				assert((ERR_CRYPTDLNOOPEN == gtmcrypt_errno) || (ERR_CRYPTINIT == gtmcrypt_errno));
				if (ERR_CRYPTDLNOOPEN == gtmcrypt_errno)
					gtmcrypt_errno = ERR_CRYPTDLNOOPEN2;
				else if (ERR_CRYPTINIT == gtmcrypt_errno)
					gtmcrypt_errno = ERR_CRYPTINIT2;
				gtmcrypt_errno = SET_CRYPTERR_MASK(gtmcrypt_errno);
				GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, SIZEOF(GTMCRYPT_ERRLIT) - 1, GTMCRYPT_ERRLIT); /* BYPASSOK */
			}
		}
#		ifdef GTM_SOCKET_SSL_SUPPORT
		/* The below logic is for prefetching the password for TLS identifiers that may have been set in the environment.
		 * But, since SSL support for Socket devices is not yet implemented, this logic need not be enabled as of this
		 * writing. When SSL support for socket devices is implemented, the surrounding #ifdef can be removed.
		 */
		if (NULL != getenv("gtmcrypt_config"))
		{	/* Environment is configured for SSL/TLS (and/or encryption). Check if any environment variable of the form
			 * `gtmtls_passwd_*' is set to NULL string. If so, nudge the SSL/TLS library to read password(s) from the
			 * user.
			 */
			for (p = envp; *p; p++)
			{
				ptr = *p;
				if (0 == MEMCMP_LIT(ptr, GTMTLS_PASSWD_ENV_PREFIX))
				{	/* At least one environment variable of $gtmtls_passwd_* is found. */
					eq = strchr(ptr, '=');
					if (0 != strlen(eq + 1))
						break; /* Set to non-empty string. No need to initialize the library now. */
					/* Set to empty string. */
					if (NULL == tls_ctx)
					{
						if (SS_NORMAL != (status = gtm_tls_loadlibrary()))
						{
							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSDLLNOOPEN, 0,
									ERR_TEXT, 2, LEN_AND_STR(dl_err));
						}
						if (NULL == (tls_ctx = gtm_tls_init(GTM_TLS_API_VERSION,
											GTMTLS_OP_INTERACTIVE_MODE)))
						{
							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSINIT, 0,
									ERR_TEXT, 2, LEN_AND_STR(gtm_tls_get_error()));
						}
					}
					assert(NULL != tls_ctx);
					assert((MAX_TLSID_LEN * 2) > (int)(eq - ptr));
					memcpy(tlsid_env_name, ptr, (int)(eq - ptr));
					tlsid_env_name[(int)(eq - ptr)] = '\0';
					gtm_tls_prefetch_passwd(tls_ctx, tlsid_env_name);
				}
			}
		}
#		endif
	}
#	endif
	dm_start();
	return 0;
}