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)
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 = >m_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; }