void dealt(){ int n = 0; ans = 8; while(1){ push_back(deck[1], piles[n]); pop_front(deck); checkpile(piles[n]); make_status(); if(deck[0] == 0){ printf("Loss: %d\n", ans); return; } else if(deck[0] == 52){ printf("Win : %d\n", ans); return; } else if(exist(status) == 1){ printf("Draw: %d\n", ans); return; } n = (n+1)%7; ans++; while(piles[n][0] == 0) n = (n+1)%7; } }
// -------------------------------------------------------------------------- // AuthPLAIN: Performs a plain-text username and password authentication with // the server. // gogoc_status AuthPLAIN(pal_socket_t socket, net_tools_t *nt, tConf *conf, tBrokerList **broker_list) { char BufferIn[1024]; char BufferOut[REDIRECT_RECEIVE_BUFFER_SIZE]; char string[] = "AUTHENTICATE PLAIN\r\n"; int Length; sint32_t tsp_status; // Send authentication mode. if( nt->netsend(socket, string, sizeof(string)) == -1 ) { Display(LOG_LEVEL_1, ELError, "AuthPLAIN", STR_NET_FAIL_W_SOCKET); return make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); } memset(BufferIn, 0, sizeof(BufferIn)); Length = pal_snprintf(BufferIn, sizeof(BufferIn), "%c%s%c%s\r\n", '\0', conf->userid, '\0', conf->passwd); // Send username/password for authentication. if( nt->netsendrecv(socket, BufferIn, Length, BufferOut, sizeof(BufferOut)) == -1 ) { Display(LOG_LEVEL_1, ELError, "AuthPLAIN", STR_NET_FAIL_RW_SOCKET); return make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); } tsp_status = tspGetStatusCode(BufferOut); // Check if the reply status indicated a broker redirection. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(BufferOut, conf, broker_list) == TSP_REDIRECT_OK ) { // Return a REDIRECT event. return make_status(CTX_TSPAUTHENTICATION, EVNT_BROKER_REDIRECTION); } else { // Redirect error. return make_status(CTX_TSPAUTHENTICATION, ERR_BROKER_REDIRECTION); } } // Check if authentication was successful. switch( tsp_status ) { case TSP_PROTOCOL_SUCCESS: break; case TSP_PROTOCOL_AUTH_FAILED: Display(LOG_LEVEL_1, ELError, "AuthPLAIN", STR_TSP_AUTH_FAILED_USER, conf->userid); return make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); default: Display(LOG_LEVEL_1, ELError, "AuthPLAIN", STR_TSP_UNKNOWN_ERR_AUTH_FAILED, tspGetTspStatusStr(tsp_status)); return make_status(CTX_TSPAUTHENTICATION, ERR_TSP_GENERIC_ERROR); } // Successful plain text authentication. return make_status(CTX_TSPAUTHENTICATION, SUCCESS); }
// -------------------------------------------------------------------------- // AuthANONYMOUS: Performs an anonymous authentication with the server. // gogoc_status AuthANONYMOUS(pal_socket_t socket, net_tools_t *nt, tConf *conf, tBrokerList **broker_list) { char Buffer[REDIRECT_RECEIVE_BUFFER_SIZE]; char string[] = "AUTHENTICATE ANONYMOUS\r\n"; sint32_t tsp_status; // Send authentication mode. if( nt->netsendrecv(socket, string, sizeof(string), Buffer, sizeof(Buffer)) == -1 ) { Display(LOG_LEVEL_1, ELError, "AuthANONYMOUS", STR_NET_FAIL_RW_SOCKET); return make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); } tsp_status = tspGetStatusCode(Buffer); // Check if the reply status indicated a broker redirection. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(Buffer, conf, broker_list) == TSP_REDIRECT_OK ) { // Return a REDIRECT event. return make_status(CTX_TSPAUTHENTICATION, EVNT_BROKER_REDIRECTION); } else { // Redirect error. return make_status(CTX_TSPAUTHENTICATION, ERR_BROKER_REDIRECTION); } } // Check if authentication was successful. // No need to handle TSP_PROTOCOL_AUTH_FAILED here... if( tsp_status != TSP_PROTOCOL_SUCCESS ) { Display(LOG_LEVEL_1, ELError, "AuthANONYMOUS", STR_TSP_UNKNOWN_ERR_AUTH_FAILED, tspGetTspStatusStr(tsp_status)); return make_status(CTX_TSPAUTHENTICATION, ERR_TSP_GENERIC_ERROR); } // Successful anonymous authentication. return make_status(CTX_TSPAUTHENTICATION, SUCCESS); }
gogoc_status tspTestIPv6Support() { struct stat buf; if(stat("/proc/net/if_inet6",&buf) == -1) { Display(LOG_LEVEL_1,ELError,"tspTestIPv6Support",GOGO_STR_NO_IPV6_SUPPORT_FOUND); Display(LOG_LEVEL_1,ELError,"tspTestIPv6Support",GOGO_STR_TRY_MODPROBE_IPV6); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } Display(LOG_LEVEL_2,ELInfo,"tspTestIPv6Support",GOGO_STR_IPV6_SUPPORT_FOUND); return STATUS_SUCCESS_INIT; }
SEXP make_handle_response(reference *ref){ CURL *handle = ref->handle; SEXP res = PROTECT(allocVector(VECSXP, 6)); SET_VECTOR_ELT(res, 0, make_url(handle)); SET_VECTOR_ELT(res, 1, make_status(handle)); SET_VECTOR_ELT(res, 2, make_rawvec(ref->resheaders.buf, ref->resheaders.size)); SET_VECTOR_ELT(res, 3, make_filetime(handle)); SET_VECTOR_ELT(res, 4, make_timevec(handle)); SET_VECTOR_ELT(res, 5, R_NilValue); setAttrib(res, R_NamesSymbol, make_namesvec()); UNPROTECT(1); return res; }
static void setup_standalone (DawatiStatusPanel *status_panel) { ClutterActor *stage, *status; Window xwin; status = make_status (status_panel); clutter_actor_set_size (status, 1000, 600); stage = clutter_stage_new (); clutter_actor_set_size (stage, 1000, 600); clutter_container_add_actor (CLUTTER_CONTAINER (stage), status); clutter_actor_realize (stage); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); mpl_panel_clutter_setup_events_with_gtk_for_xid (xwin); clutter_actor_show (stage); }
int assemble_views() { /* button2 */ make_button2(); /*status*/ make_status(); /*scroll*/ make_scroll(); /*textview*/ make_textview(); /* tags */ make_tags(); gtk_container_add((GtkContainer *)hbox1, button2); gtk_box_set_child_packing(GTK_BOX(hbox1), button2, 0, 0, 1, GTK_PACK_START); gtk_container_add((GtkContainer *)hboxmain, textview1); gtk_container_add((GtkContainer *)scroll, textview2); gtk_container_add((GtkContainer *)hboxmain, scroll); gtk_container_add((GtkContainer *)vbox1, GTK_WIDGET(status)); gtk_box_set_child_packing(GTK_BOX(hboxmain), textview1, 0, 1, 2, GTK_PACK_START); gtk_box_set_child_packing(GTK_BOX(hboxmain), scroll, 1, 1, 2, GTK_PACK_END); gtk_box_set_child_packing(GTK_BOX(vbox1), GTK_WIDGET(status), 0, 1, 0, GTK_PACK_START); gtk_widget_show(scroll); viewsAssembled = TRUE; debug("Assemble views"); return 0; }
static void setup_panel (DawatiStatusPanel *status_panel) { MplPanelClient *panel; ClutterActor *stage, *status; panel = mpl_panel_clutter_new ("status", _("status"), NULL, "status-button", TRUE); status_panel->panel_client = panel; mpl_panel_clutter_setup_events_with_gtk ((MplPanelClutter *)panel); status = make_status (status_panel); mpl_panel_client_set_size_request (panel, 1024, 580); stage = mpl_panel_clutter_get_stage (MPL_PANEL_CLUTTER (panel)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), status); g_signal_connect (panel, "size-changed", G_CALLBACK (on_client_set_size), status); }
gogoc_status tspStartLocal(int socket, tConf *c, tTunnel *t, net_tools_t *nt) { TUNNEL_LOOP_CONFIG tun_loop_cfg; gogoc_status status = STATUS_SUCCESS_INIT; int ka_interval = 0; int tunfd = (-1); int pid; // Check if we got root privileges. if(geteuid() != 0) { // Error: we don't have root privileges. Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_FATAL_NOT_ROOT_FOR_TUN ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } // Check Ipv6 support. Display( LOG_LEVEL_2, ELInfo, "tspStartLocal", GOGO_STR_CHECKING_LINUX_IPV6_SUPPORT ); status = tspTestIPv6Support(); if( status_number(status) != SUCCESS ) { // Error: It seems the user does not have IPv6 support in kernel. return status; } // Check if we're already daemon. Calling multiple times the daemon() messes up pthreads. if( !c->nodaemon && getppid() != 1 ) { // Detach from controlling terminal and run in the background. Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_GOING_DAEMON ); if( daemon(1,0) == -1 ) { // Error: Failed to detach. Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_CANT_FORK ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } } // Check tunnel mode. if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 ) { // V4V6 tunnel mode is not supported on this platform. Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V4V6_ON_PLATFORM ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { // When using V6UDPV4 encapsulation, open the TUN device. tunfd = TunInit(c->if_tunnel_v6udpv4); if( tunfd == -1 ) { // Error: Failed to open TUN device. Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_MISC_FAIL_TUN_INIT ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } } while( 1 ) // Dummy loop. 'break' instruction at the end. { // Run the config script in another thread, without giving it our tunnel // descriptor. This is important because otherwise the tunnel will stay // open if we get killed. // pid = fork(); if( pid < 0 ) { // fork() error status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); break; } else if (pid == 0) { // Child processing: run template script. if( tunfd != -1 ) { close(tunfd); } status = tspSetupInterface(c, t); exit(status); } else { // Parent processing int s = 0; // Wait for child process to exit. Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_WAITING_FOR_SETUP_SCRIPT ); if( wait(&s) != pid ) { // Error occured: we have no other child Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_ERR_WAITING_SCRIPT ); status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); break; } // Check if process waited upon has exited. if( !WIFEXITED(s) ) { // Error: child has not exited properly. Maybe killed ? Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_GEN_SCRIPT_EXEC_FAILED ); status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); break; } // Check child exit code. status = WEXITSTATUS(s); if( status_number(status) != SUCCESS ) { break; } } // Retrieve keepalive inteval, if found in tunnel parameters. if( t->keepalive_interval != NULL ) { ka_interval = atoi(t->keepalive_interval); } // Start the tunnel loop, depending on tunnel mode // if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { status = TunMainLoop( tunfd, socket, c->keepalive, ka_interval, t->client_address_ipv6, t->keepalive_address); /* We got out of V6UDPV4 "TUN" tunnel loop */ tspClose(socket, nt); } else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 ) { memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) ); tun_loop_cfg.ka_interval = ka_interval; tun_loop_cfg.ka_src_addr = t->client_address_ipv6; tun_loop_cfg.ka_dst_addr = t->keepalive_address; tun_loop_cfg.sa_family = AF_INET6; tun_loop_cfg.tun_lifetime = 0; status = tspPerformTunnelLoop( &tun_loop_cfg ); } break; // END of DUMMY loop. } // Cleanup: Close tunnel descriptor, if it was opened. if( tunfd != -1 ) { // The tunnel file descriptor should be closed before attempting to tear // down the tunnel. Destruction of the tunnel interface may fail if // descriptor is not closed. close( tunfd ); } // Cleanup: Handle tunnel teardown. tspTearDownTunnel( c, t ); return status; }
/** Add a DSA key to the tspc key file * * @param dsa the DSA param pointer filled with our key info * @param host the hostname of the corresponding broker * @param filename the keyfile to use * * @return 0 if error * 1 if ok * */ int add_dsakey_to_keyfile(DSA *dsa, char *host, char *filename, tBoolean autoaccept) { FILE *fp = NULL; Buffer buf; char *str = NULL; int ret = 0; switch (is_dsakey_in_keyfile(dsa, host, filename)) { case 0: Display(LOG_LEVEL_3, ELInfo, TSP_AUTH_PASSDSS_STRING, GOGO_STR_ERR_IN_KEY_VERIF); Display(LOG_LEVEL_3, ELWarning, TSP_AUTH_PASSDSS_STRING, GOGO_STR_SERVER_KEY_REJECTED); break; case 1: /* not in, we add and continue */ #if defined(WIN32) && !defined(WINCE) // When running as a service we can't ask user // permission. Compromise and accept the key auto // if (!IsService && !autoaccept) { #else if (!autoaccept) { #endif if (!ask(GOGO_STR_UNKNOWN_HOST_ADD_KEY, host)) { Display(LOG_LEVEL_3, ELWarning, TSP_AUTH_PASSDSS_STRING, GOGO_STR_SERVER_KEY_REJECTED_USER); break; } } else Display(LOG_LEVEL_1, ELWarning, TSP_AUTH_PASSDSS_STRING, GOGO_STR_WARN_SERVER_KEY_AUTO_ADDED); Display(LOG_LEVEL_2, ELInfo, TSP_AUTH_PASSDSS_STRING, GOGO_STR_SERVER_KEY_ACCEPTED_ADDED); buffer_init(&buf); if (buf.buf == NULL) break; buffer_put_cstring(&buf, "ssh-dss"); buffer_put_bignum(&buf, dsa->p); buffer_put_bignum(&buf, dsa->q); buffer_put_bignum(&buf, dsa->g); buffer_put_bignum(&buf, dsa->pub_key); if ( (str = pal_malloc(2 * buffer_len(&buf))) == NULL) break; if ( (base64encode(str, buffer_ptr(&buf), (int) buffer_len(&buf))) < 1) break; fp = fopen(filename, "a"); if (fp) { fprintf(fp, "%s ssh-dss %s\n", host, str); fclose(fp); ret = 1; } buffer_free(&buf); pal_free(str); break; case 2: /* in and matching correctly, hurray */ Display(LOG_LEVEL_2, ELInfo, TSP_AUTH_PASSDSS_STRING, GOGO_STR_MATCHING_KEY_FOUND_USED); ret = 1; break; case 3: /* in and NOT matching correctly */ Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_WARN_STORED_LOCAL_KEY_NO_MATCH, filename, host); Display(LOG_LEVEL_3, ELWarning, TSP_AUTH_PASSDSS_STRING, GOGO_STR_SERVER_KEY_REJECTED); ret = 0; break; } return ret; } /** * Authenticate to the Migration Broker using PASSDSS-3DES-1 * * Buf_H will contain the data used to validate the server * signature. The data is a concatenation of the following parameters, * in that order: * azname,authname,DH_public_key,pklength,"ssh-dss",p,q,g,z,Y,ssecmask,sbuflen,dh_K * * @param socket * @param user * @param passwd * @param host * @param nt * * @return * * @todo DH public key validation (RFC2631, 2.1.5) * @todo Local storage for server public keys * */ gogoc_status AuthPASSDSS_3DES_1(pal_socket_t socket, net_tools_t *nt, tConf *conf, tBrokerList **broker_list) { DH *dh = NULL; /**< client DH key used to exchange key with server */ DSA *dsa = NULL; /**< Remote server DSA key public information */ DSA_SIG *sig = NULL; /**< DSA signature */ char authenticate[] = "AUTHENTICATE PASSDSS-3DES-1\r\n"; char *BufferIn = NULL; char *BufferOut = NULL; char *BufferPtr = NULL; Buffer BufH; /**< Buffer to hold data used for signature. */ Buffer BufSpace; /**< Space to hold data before/after base64 conversion */ Buffer *Buf_H = &BufH; Buffer *Buf_Space = &BufSpace; BIO *bio_rw = NULL; /**< Memory buffer bio */ BIO *b64= NULL; /**< Base64 bio */ BIO *cipher = NULL; /**< Symmetric crypto bio */ BIGNUM *server_pubkey = NULL; /**< received server public DH key */ BIGNUM *dh_K = NULL; /**< DH computed shared secret */ u_char hash[20]; /**< SHA1 hash */ u_char enc_key[24]; /**< encryption key (3des) */ u_char enc_iv[8]; /**< initialization vector (3des) */ u_char int_key[20]; /**< cs integrity key */ u_char tmphash[40]; /**< temporary hash storage */ u_char hmac[EVP_MAX_MD_SIZE]; /**< HMAC for integrity of sent data (step L) */ int pklength = 0; /**< length of SSH-style DSA server public key */ int ssecmask = 0; /**< SASL security layers offered */ int sbuflen = 0; /**< maximum server security layer block size */ char *s = NULL; u_char num[3]; /**< Array to manupulate 3 octet number (sbuflen) */ /* Temporary variables */ int buflen, readlen, keysize, siglength; gogoc_status status = STATUS_SUCCESS_INIT; sint32_t tsp_status; /* From draft-newman-sasl-passdss-01. "This group was taken from the * ISAKMP/Oakley specification, and was originally generated by * Richard Schroeppel at the University of Arizona. Properties of * this prime are described in [Orm96]" */ /* RFC2409, DH group 2 (second Oakley group) */ static char *dh_group2= "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" "FFFFFFFF" "FFFFFFFF"; static unsigned char dh_g[]={ 0x02, }; /* Initialize Diffie Hellman variables */ if ((dh = DH_new()) == NULL || (server_pubkey = BN_new()) == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Convert dh_group2 and dh_g to BIGNUM type */ BN_hex2bn(&dh->p, dh_group2); dh->g = BN_bin2bn(dh_g,sizeof(dh_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_INITIALIZATION_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; } if ((dh_K = BN_new()) == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Reserve storage for DSA key */ if ((dsa = DSA_new()) == NULL || (dsa->p = BN_new()) == NULL || (dsa->q = BN_new()) == NULL || (dsa->g = BN_new()) == NULL || (dsa->pub_key = BN_new()) == NULL || (dsa->priv_key = BN_new()) == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Allocate memory for DSA signature */ if ((sig = DSA_SIG_new()) == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Initialize data buffers */ BufferIn = calloc(1, TSP_AUTH_PASSDSS_BUFFERSIZE); BufferOut = calloc(1, TSP_AUTH_PASSDSS_BUFFERSIZE); if ((BufferIn == NULL) || (BufferOut == NULL)) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } buffer_init(Buf_Space); buffer_init(Buf_H); if (Buf_Space->buf == NULL || Buf_H->buf == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Create a read/write memory BIO. Memory is segment is * created and resized as needed. When BIO is destroyed, the * memory is freed. */ bio_rw = BIO_new(BIO_s_mem()); /* Create a base64 BIO filter */ b64 = BIO_new(BIO_f_base64()); if ((bio_rw == NULL) || (b64 == NULL)) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Compute the Diffie-Hellman public value "X" as follows. If X has a value of 0, repeat. x X = g mod n where g = dh_g = 2 n = dh_group2 x = DH secret key X = DH public key */ if (DH_generate_key(dh) == 0) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_DH_GEN_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; } /* Validate DH public key (RFC2631, 2.1.5) */ /* Send message with SASL mechanism identifier */ if ( nt->netsend(socket, authenticate, sizeof(authenticate)) == -1 ) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_NET_FAIL_W_SOCKET); status = make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); goto error; } /* First PASSDSS message from client to server: string azname ; the user name to login as, may be empty if same as authentication name string authname ; the authentication name mpint X ; Diffie-Hellman parameter X */ /* azname is empty. Just insert a string length zero */ buffer_put_int(Buf_Space, 0); /* authname */ buffer_put_cstring(Buf_Space, conf->userid); /* DH public key */ buffer_put_bignum(Buf_Space, dh->pub_key); /* At this point, save the buffer into Buf_H. Used later for * signature verification. */ buffer_append(Buf_H, buffer_ptr(Buf_Space), buffer_len(Buf_Space)); /* Push base64 filter */ BIO_push(b64, bio_rw); /* no newline */ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); /* Write Buffer content into bio_rw. Buffer will be base64 * encoded. */ BIO_write(b64, buffer_ptr(Buf_Space), (int) buffer_len(Buf_Space)); BIO_flush(b64); /* Get pointer to the result */ buflen = BIO_get_mem_data(bio_rw, &BufferPtr); // Send data to server, save response in BufferIn. if((readlen = nt->netsendrecv(socket, BufferPtr, buflen, BufferIn, TSP_AUTH_PASSDSS_BUFFERSIZE)) == -1) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_NET_FAIL_RW_SOCKET); status = make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); goto error; } /* remove base64 filter */ BIO_pop(bio_rw); buffer_clear(Buf_Space); buflen = 0; /* Decode response (base64) and extract server response * * The response format is as follows: uint32 pklength ; length of SSH-style DSA server public key (number of bytes up to y, inclusively) string "ssh-dss" ; constant string "ssh-dss" (lower case) mpint p ; DSA public key parameters mpint q mpint g mpint z (y in draft) mpint Y ; Diffie-Hellman parameter Y OCTET ssecmask ; SASL security layers offered 3 OCTET sbuflen ; maximum server security layer block size uint32 siglength ; length of SSH-style dss signature (number of bytes up to s inclusively) string "ssh-dss" ; constant string "ssh-dss" (lower case) mpint r ; DSA signature parameters mpint s */ buflen = base64decode(BufferOut, BufferIn); buffer_append(Buf_Space, BufferOut, buflen); /* Get pklength */ pklength = buffer_get_int(Buf_Space); /* Assuming that * p, g, and y are 512 bits, * q is 160 bits, * "ssh-dss" is 7 bytes * pklength should be at least 240 bytes. */ if (pklength < 240) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_RCVD_DATA_INVALID); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; } /* Make a copy of (pklength|"ssh-dss"|p|q|g|z) in Buf_H */ /* Add pklength */ buffer_put_int(Buf_H, pklength); /* Add "ssh-dss"|p|q|g|z */ buffer_append(Buf_H, buffer_ptr(Buf_Space), pklength); /* Get "ssh-dss" string */ s = buffer_get_string(Buf_Space, (unsigned int*)&buflen); pal_free(s); s = NULL; /* Get p */ buffer_get_bignum(Buf_Space, dsa->p); /* Get q */ buffer_get_bignum(Buf_Space, dsa->q); /* Get g */ buffer_get_bignum(Buf_Space, dsa->g); /* Get z (pub_key) */ buffer_get_bignum(Buf_Space, dsa->pub_key); /* Get DH public key */ buffer_get_bignum(Buf_Space, server_pubkey); /* Copy in Buf_H for signature verification later */ buffer_put_bignum(Buf_H, server_pubkey); /* Buffer now points at ssecmask (1 octet), followed by * sbuflen (3 octets). Make a copy of these 4 octets in Buf_H * now, then extract these values. */ buffer_append(Buf_H, buffer_ptr(Buf_Space), 4); /* Get ssecmask */ ssecmask = buffer_get_octet(Buf_Space); /* Get sbuflen * Big endian binary unsigned integer */ buffer_get(Buf_Space, (char *)num, 3); sbuflen = (((u_long)(u_char)(num)[0] << 16) | ((u_long)(u_char)(num)[1] << 8) | ((u_long)(u_char)(num)[2])); /* DSS signature */ /* Get siglength */ siglength = buffer_get_int(Buf_Space); /* r and s are 20 bytes each, encoded as mpint (2*24) * "ssh-dss" is 7 bytes + int32 siglength should be >= 59 * octets (mpint may have leading zero byte) */ if (siglength < 59) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_RCVD_DATA_INVALID); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; } /* Get "ssh-dss" string */ s = buffer_get_string(Buf_Space, (unsigned int*)&buflen); pal_free(s); s = NULL; /* Get DSA signature r and s*/ if ((sig->r= BN_new()) == NULL || (sig->s = BN_new()) == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } /* Get r */ buffer_get_bignum(Buf_Space, sig->r); /* Get s */ buffer_get_bignum(Buf_Space, sig->s); /* Validate server DH public key (RFC2631, 2.1.5) */ { if( !add_dsakey_to_keyfile(dsa, conf->server, TSPC_DSA_KEYFILE, conf->no_questions) ) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_KEY_VERIF_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; } } /* Verify that DSA public key belongs to server */ /* Compute DH shared secret */ if ((s = calloc(1, DH_size(dh))) == NULL) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_GEN_MALLOC_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); goto error; } if( (keysize = DH_compute_key((unsigned char*)s, server_pubkey, dh)) < 0 ) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_DH_SHARED_COMPUTE_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; } BN_bin2bn((const unsigned char*)s, keysize, dh_K); memset(s, 0, keysize); pal_free(s); s = NULL; Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_DH_SHARED_KEY, BN_bn2hex(dh_K)); /* Append dh_K in to complete the buffer. Use Buffer to hold * result to keep Bf_H intact, since to will be used (without * dh_K) to compute HMAC for packet integrity. */ buffer_clear(Buf_Space); buffer_append(Buf_Space, buffer_ptr(Buf_H), buffer_len(Buf_H)); buffer_put_bignum(Buf_Space, dh_K); /* Compute SHA1 hash of Buffer */ SHA1(buffer_ptr(Buf_Space), buffer_len(Buf_Space), hash); /* Debug information available at level 4 */ { BIGNUM *h; h = BN_bin2bn(hash, 20, NULL); Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_SIGNED_HASH, BN_bn2hex(h)); BN_free(h); } Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_DSA_SIGN_R, BN_bn2hex(sig->r)); Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_DSA_SIGN_S, BN_bn2hex(sig->s)); // Verify that the DSS signature is a signature of hash. switch( DSA_do_verify(hash, sizeof(hash), sig, dsa) ) { case 0: Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_BAD_SIG_FROM_SERVER); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; break; /* NOTREACHED */ case 1: /* correct signature */ break; default: /* -1 on error */ Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, GOGO_STR_SIG_VERIF_ERROR); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; break; /* NOTREACHED */ } /* Step I: Compute 3DES key and iv */ /* cs-encryption-iv = SHA1( K || "A" || H ) sc-encryption-iv = SHA1( K || "B" || H ) cs-encryption-key-1 = SHA1( K || "C" || H ) cs-encryption-key-2 = SHA1( K || cs-encryption-key-1 ) cs-encryption-key = cs-encryption-key-1 || cs-encryption-key-2 sc-encryption-key-1 = SHA1( K || "D" || H ) sc-encryption-key-2 = SHA1( K || sc-encryption-key-1 ) sc-encryption-key = sc-encryption-key-1 || sc-encryption-key-2 cs-integrity-key = SHA1( K || "E" || H ) sc-integrity-key = SHA1( K || "F" || H ) K is dh_k in mpint format (string) H is hash */ /* Since we won't support SASL security layers, we need to * compute the following only: * cs-encryption-iv * cs-encryption-key * cs-integrity-key */ buffer_clear(Buf_Space); buffer_put_bignum(Buf_Space, dh_K); buffer_put_octet(Buf_Space,'A'); buffer_append(Buf_Space, hash, 20); SHA1(buffer_ptr(Buf_Space), buffer_len(Buf_Space), tmphash); /* Use first 8 octets as iv */ memcpy(enc_iv, tmphash, 8); buffer_clear(Buf_Space); buffer_put_bignum(Buf_Space, dh_K); buffer_put_octet(Buf_Space,'E'); buffer_append(Buf_Space, hash, 20); SHA1(buffer_ptr(Buf_Space), buffer_len(Buf_Space), int_key); buffer_clear(Buf_Space); buffer_put_bignum(Buf_Space, dh_K); buffer_put_octet(Buf_Space,'C'); buffer_append(Buf_Space, hash, 20); SHA1(buffer_ptr(Buf_Space), buffer_len(Buf_Space), tmphash); buffer_clear(Buf_Space); buffer_put_bignum(Buf_Space, dh_K); buffer_append(Buf_Space, tmphash, 20); SHA1(buffer_ptr(Buf_Space), buffer_len(Buf_Space), tmphash+20); /* Use first 24 octets as key */ memcpy(enc_key, tmphash, 24); { BIGNUM *enc, *i, *iv; enc = BN_bin2bn(enc_key, 24, NULL); iv = BN_bin2bn(enc_iv, 8, NULL); i = BN_bin2bn(int_key, 20, NULL); Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_PASSDS_ENC_KEY, BN_bn2hex(enc)); Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_PASSDS_IV, BN_bn2hex(iv)); Display(LOG_LEVEL_3, ELDebug, TSP_AUTH_PASSDSS_STRING, GOGO_STR_PASSDS_INTEG_KEY, BN_bn2hex(i)); BN_free(enc); BN_free(i); BN_free(iv); } /* (J) Create a buffer beginning with a bit mask for the selected security layer (it MUST be one offered from server) followed by three octets representing the maximum cipher-text buffer size (at least 32) the client can accept in network byte order. This is followed by a string containing the passphrase. */ buffer_clear(Buf_Space); buffer_put_octet(Buf_Space, ssecmask); buffer_put_octet(Buf_Space, 0); buffer_put_octet(Buf_Space, 0); buffer_put_octet(Buf_Space, 0); /**< @bug must be at least 32 */ buffer_put_cstring(Buf_Space, conf->passwd); /* (K) Create a buffer containing items (1) through (7) immediately followed by the first four octets of (J). */ buffer_append(Buf_H, buffer_ptr(Buf_Space), 4); /* (L) Compute HMAC-SHA-1 with (K) as the data and the cs-integrity- key from step (I) as the key. This produces a 20 octet result. */ HMAC(EVP_sha1(), int_key, sizeof(int_key), buffer_ptr(Buf_H), buffer_len(Buf_H), hmac, (unsigned int*)&keysize); /* (M) Create a buffer containing (J) followed by (L) followed by an arbitrary number of zero octets as necessary to reach the block size of DES and conceal the passphrase length from an eavesdropper. */ buffer_append(Buf_Space, hmac, keysize); /* (N) Apply the triple-DES algorithm to (M) with the first 8 octets of cs-encryption-iv from step (I) as the initialization vector and the first 24 octets of cs-encryption-key as the key. */ /* Padding is automatically done. From OpenSSL EVP_EncryptInit(3): EVP_CIPHER_CTX_set_padding() enables or disables padding. By default encryption operations are padded using standard block padding and the padding is checked and removed when decrypting. */ /* Create BIO filter to encrypt using 3des + convert to base64. Result is written in memory BIO. */ /* Erase BIO and buffer memory */ BIO_reset(bio_rw); memset(BufferOut, 0, TSP_AUTH_PASSDSS_BUFFERSIZE); memset(BufferIn, 0, TSP_AUTH_PASSDSS_BUFFERSIZE); buflen = 0; /* Create cipher BIO */ cipher = BIO_new(BIO_f_cipher()); BIO_set_cipher(cipher, EVP_des_ede3_cbc(), enc_key, enc_iv, 1); /* Assemble filters as cipher->b64->bio_rw */ BIO_push(cipher, b64); BIO_push(b64, bio_rw); /* Write Buffer content into bio_rw */ BIO_write(cipher, buffer_ptr(Buf_Space), (int) buffer_len(Buf_Space)); BIO_flush(cipher); /* Get pointer to the result. */ buflen = BIO_get_mem_data(bio_rw, &BufferPtr); /* wipe encryption material */ memset(enc_key, 0, sizeof(enc_key)); memset(enc_iv, 0, sizeof(enc_iv)); /* Send data to server, save response in BufferIn */ if( (readlen = nt->netsendrecv(socket, BufferPtr, buflen, BufferIn, TSP_AUTH_PASSDSS_BUFFERSIZE)) == -1) { Display(LOG_LEVEL_1, ELError, TSP_AUTH_PASSDSS_STRING, STR_NET_FAIL_RW_SOCKET); status = make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); goto error; } tsp_status = tspGetStatusCode(BufferIn); // Check if the reply status indicated a broker redirection. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(BufferIn, conf, broker_list) == TSP_REDIRECT_OK ) { status = make_status(CTX_TSPAUTHENTICATION, EVNT_BROKER_REDIRECTION); } else { // Redirect error. status = make_status(CTX_TSPAUTHENTICATION, ERR_BROKER_REDIRECTION); } goto error; } // Check if authentication was successful. switch( tsp_status ) { case TSP_PROTOCOL_SUCCESS: break; case TSP_PROTOCOL_AUTH_FAILED: Display(LOG_LEVEL_1, ELError, "AuthPASSDSS_3DES_1", STR_TSP_AUTH_FAILED_USER, conf->userid); status = make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); goto error; default: Display(LOG_LEVEL_1, ELError, "AuthPASSDSS_3DES_1", STR_TSP_UNKNOWN_ERR_AUTH_FAILED, tspGetTspStatusStr(tsp_status)); status = make_status(CTX_TSPAUTHENTICATION, ERR_TSP_GENERIC_ERROR); goto error; } status = STATUS_SUCCESS_INIT; error: /* Free storage for DSA key */ if (dsa != NULL) DSA_free(dsa); /* Also frees BIGNUMs inside struct */ /* DSA signature */ if (sig != NULL) DSA_SIG_free(sig); /* Free Diffie Hellman variables */ if (dh != NULL) DH_free(dh); /* Also frees BIGNUMs inside struct */ if (server_pubkey != NULL) BN_free(server_pubkey); if (dh_K != NULL) BN_free(dh_K); /* Buffers */ if (Buf_Space->buf != NULL) buffer_free(Buf_Space); if (Buf_H->buf != NULL) buffer_free(Buf_H); /* malloc'ed space*/ if (BufferIn != NULL) pal_free(BufferIn); if (BufferOut != NULL) pal_free(BufferOut); /* BIOs */ if (cipher != NULL) BIO_vfree(cipher); if (b64 != NULL) BIO_vfree(b64); if (bio_rw != NULL) BIO_vfree(bio_rw); /* strings buffers */ if (s != NULL) pal_free(s); return status; }
// --------------------------------------------------------------------------- gw6c_status TunMainLoop(int tunfd, pal_socket_t Socket, tBoolean keepalive, int keepalive_interval, char *local_address_ipv6, char *keepalive_address) { fd_set rfds; int count, maxfd, ret; char bufin[2048]; char bufout[2048]; struct timeval timeout; void* p_ka_engine = NULL; ka_status_t ka_status; ka_ret_t ka_ret; gw6c_status status; int ongoing = 1; keepalive = (keepalive_interval != 0) ? TRUE : FALSE; if( keepalive == TRUE ) { // Initialize the keepalive engine. ka_ret = KA_init( &p_ka_engine, keepalive_interval * 1000, local_address_ipv6, keepalive_address, AF_INET6 ); if( ka_ret != KA_SUCCESS ) { return make_status(CTX_TUNNELLOOP, ERR_KEEPALIVE_ERROR); } // Start the keepalive loop(thread). ka_ret = KA_start( p_ka_engine ); if( ka_ret != KA_SUCCESS ) { KA_destroy( &p_ka_engine ); return make_status(CTX_TUNNELLOOP, ERR_KEEPALIVE_ERROR); } } // tun device wants bufin[0]...[3] to contain AF_INET6 ((u_int32_t *)bufin)[0] = htonl(AF_INET6); // Data send loop. while( ongoing == 1 ) { // initialize the status. status = STATUS_SUCCESS_INIT; if( tspCheckForStopOrWait( 0 ) != 0 ) { // We've been notified to stop. ongoing = 0; } if( keepalive == TRUE ) { // Check if we're stopping. if( ongoing == 0 ) { // Stop keepalive engine. KA_stop( p_ka_engine ); } // Query the keepalive status. ka_status = KA_qry_status( p_ka_engine ); switch( ka_status ) { case KA_STAT_ONGOING: case KA_STAT_FIN_SUCCESS: break; case KA_STAT_FIN_TIMEOUT: KA_stop( p_ka_engine ); status = make_status(CTX_TUNNELLOOP, ERR_KEEPALIVE_TIMEOUT); break; case KA_STAT_INVALID: case KA_STAT_FIN_ERROR: default: KA_stop( p_ka_engine ); status = make_status(CTX_TUNNELLOOP, ERR_KEEPALIVE_ERROR); break; } // Reinit select timeout variable; select modifies it. // Use 500ms because we need to re-check keepalive status. timeout.tv_sec = 0; timeout.tv_usec = 500000; // 500 milliseconds. } else { // Reinit select timeout variable; select modifies it. timeout.tv_sec = 7 * 24 * 60 * 60 ; // one week timeout.tv_usec = 0; } // Check if we're normal. if( status_number(status) != SUCCESS || ongoing != 1 ) { goto done; } FD_ZERO(&rfds); FD_SET(tunfd,&rfds); FD_SET(Socket,&rfds); maxfd = tunfd>Socket?tunfd:Socket; ret = select(maxfd+1,&rfds,0,0,&timeout); if (ret > 0) { if( FD_ISSET(tunfd, &rfds) ) { /* data sent through udp tunnel */ ioctl(tunfd, FIONREAD, &count); if (count > sizeof(bufout)) { Display(LOG_LEVEL_1, ELError, "TunMainLoop", STR_NET_FAIL_TUN_DEV_BUFSMALL); status = make_status(CTX_TUNNELLOOP, ERR_TUNNEL_IO); goto done; } if (read(tunfd, bufout, count) != count) { Display(LOG_LEVEL_1, ELError, "TunMainLoop", STR_NET_FAIL_R_TUN_DEV); status = make_status(CTX_TUNNELLOOP, ERR_TUNNEL_IO); goto done; } if (send(Socket, bufout+4, count-4, 0) != count-4) { Display(LOG_LEVEL_1, ELError, "TunMainLoop", STR_NET_FAIL_W_SOCKET); status = make_status(CTX_TUNNELLOOP, ERR_TUNNEL_IO); goto done; } } if(FD_ISSET(Socket,&rfds)) { // Data received through UDP tunnel. count=recvfrom(Socket,bufin+4,2048 - 4,0,NULL,NULL); if (write(tunfd, bufin, count + 4) != count + 4) { Display(LOG_LEVEL_1, ELError, "TunMainLoop", STR_NET_FAIL_W_TUN_DEV); status = make_status(CTX_TUNNELLOOP, ERR_TUNNEL_IO); goto done; } } } } /* Normal loop end */ status = STATUS_SUCCESS_INIT; done: if( keepalive == TRUE ) { KA_destroy( &p_ka_engine ); } return status; }
// -------------------------------------------------------------------------- // Function : tspAuthenticate // // Synopsys: Will authenticate a session with the broker. // // Description: // First, we'll try to find the most secure common authentication method. // Once the authentication method has been chosen, the authentication // process is initiated with the broker. // // Arguments: (only local-specific arguments are listed here) // cap: bitfield [IN], The authentication methods suported by the broker. // conf: tConf* [IN], The global configuration object. // // Return values: // A gogoc_status status. // // -------------------------------------------------------------------------- gogoc_status tspAuthenticate(pal_socket_t socket, tCapability cap, net_tools_t *nt, tConf *conf, tBrokerList **broker_list, int version_index) { gogoc_status status = make_status(CTX_TSPAUTHENTICATION, ERR_NO_COMMON_AUTHENTICATION); tCapability Mechanism; // Get mechanism, depending on requested authentication method. if( pal_strcasecmp( conf->auth_method, "any" ) == 0 ) Mechanism = AUTH_ANY; else Mechanism = tspSetCapability("AUTH", conf->auth_method); if( pal_strcasecmp( conf->auth_method, "anonymous" ) != 0 ) { // Try the most secure authentication methods first: #ifndef NO_OPENSSL if( Mechanism & cap & AUTH_PASSDSS_3DES_1 ) { Display(LOG_LEVEL_3, ELInfo, "tspAuthenticate", GOGO_STR_USING_AUTH_PASSDSS_3DES_1); status = AuthPASSDSS_3DES_1(socket, nt, conf, broker_list); goto EndAuthenticate; } #endif if( Mechanism & cap & AUTH_DIGEST_MD5 ) { Display(LOG_LEVEL_3, ELInfo, "tspAuthenticate", GOGO_STR_USING_AUTH_DIGEST_MD5); status = AuthDIGEST_MD5(socket, nt, conf, broker_list, version_index); goto EndAuthenticate; } if( Mechanism & cap & AUTH_PLAIN ) { Display(LOG_LEVEL_3, ELInfo, "tspAuthenticate", GOGO_STR_USING_AUTH_PLAIN); status = AuthPLAIN(socket, nt, conf, broker_list); goto EndAuthenticate; } } else { // Finally, try anonymous if possible. if( Mechanism & cap & AUTH_ANONYMOUS ) { Display(LOG_LEVEL_3, ELInfo, "tspAuthenticate", GOGO_STR_USING_AUTH_ANONYMOUS); status = AuthANONYMOUS(socket, nt, conf, broker_list); goto EndAuthenticate; } } EndAuthenticate: if( status_number(status) == ERR_NO_COMMON_AUTHENTICATION ) { const char* szStrings[] = { "Server Authentication Capabilities: ", "Your Configured Authentication: " }; size_t nWritten; char bufDisplay[256]; // Display server authentication capabilities. pal_snprintf( bufDisplay, sizeof(bufDisplay), "%s", szStrings[0] ); nWritten = pal_strlen( szStrings[0] ); tspFormatCapabilities( bufDisplay + nWritten, sizeof(bufDisplay) - nWritten, cap ); Display( LOG_LEVEL_1, ELWarning, "tspAuthenticate", bufDisplay ); // Display user authentication choice. pal_snprintf( bufDisplay, sizeof(bufDisplay), "%s", szStrings[1] ); nWritten = pal_strlen( szStrings[1] ); tspFormatCapabilities( bufDisplay + nWritten, sizeof(bufDisplay) - nWritten, Mechanism ); Display( LOG_LEVEL_1, ELWarning, "tspAuthenticate", bufDisplay ); // Failed to find a common authentication method. Display(LOG_LEVEL_1, ELError, "tspAuthenticate", STR_TSP_NO_COMMON_AUTHENTICATION); } return status; }
// -------------------------------------------------------------------------- // AuthDIGEST_MD5: Performs a Digest-MD5 authentication with the server. // gogoc_status AuthDIGEST_MD5(pal_socket_t socket, net_tools_t *nt, tConf *conf, tBrokerList **broker_list, int version_index) { char Buffer[4096], Response[33], cResponse[33], *ChallengeString; char string[] = "AUTHENTICATE DIGEST-MD5\r\n"; char BufferIn[REDIRECT_RECEIVE_BUFFER_SIZE]; time_t cnonce = pal_time(NULL); tChallenge c; sint32_t tsp_status; // Send authentication mode. memset(BufferIn, 0, sizeof(BufferIn)); if( nt->netsendrecv(socket, string, sizeof(string), BufferIn, sizeof(BufferIn)) == -1 ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_NET_FAIL_RW_SOCKET); return make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); } tsp_status = tspGetStatusCode(BufferIn); // Check if the reply status indicated a broker redirection. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(BufferIn, conf, broker_list) == TSP_REDIRECT_OK ) { // Return a REDIRECT event. return make_status(CTX_TSPAUTHENTICATION, EVNT_BROKER_REDIRECTION); } else { // Redirect error. return make_status(CTX_TSPAUTHENTICATION, ERR_BROKER_REDIRECTION); } } // Check for error in status. if( tsp_status == TSP_PROTOCOL_AUTH_FAILED ) { // Failed authentication. Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_TSP_AUTH_FAILED_USER, conf->userid); return make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); } // Allocate memory for challenge string. if( (ChallengeString = pal_malloc(pal_strlen(BufferIn) + 1)) == NULL ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } base64decode(ChallengeString, BufferIn); ExtractChallenge(&c, ChallengeString); pal_free(ChallengeString); { /*-----------------------------------------------------------*/ /* Extract from : RFC 2831 Digest SASL Mechanism Let H(s) be the 16 octet MD5 hash [RFC 1321] of the octet string s. Let KD(k, s) be H({k, ":", s}), i.e., the 16 octet hash of the string k, a colon and the string s. Let HEX(n) be the representation of the 16 octet MD5 hash n as a string of 32 hex digits (with alphabetic characters always in lower case, since MD5 is case sensitive). response-value = HEX( KD ( HEX(H(A1)), { nonce-value, ":" nc-value, ":", cnonce-value, ":", qop-value, ":", HEX(H(A2)) })) If authzid is not specified, then A1 is A1 = { H( { username-value, ":", realm-value, ":", passwd } ), ":", nonce-value, ":", cnonce-value } If the "qop" directive's value is "auth", then A2 is: A2 = { "AUTHENTICATE:", digest-uri-value } */ char *A1_1Fmt = "%s:%s:%s", #ifndef WIN32 *A1Fmt = ":%s:%lu", *ChallRespFmt = "%s:%s:00000001:%lu:%s:%s", *ResponseFmt = "charset=%s,username=\"%s\",realm=\"%s\",nonce=\"%s\",nc=00000001,cnonce=\"%lu\",digest-uri=\"tsp/%s\",response=%s,qop=auth", #else // 64 bit version. *A1Fmt = ":%s:%I64d", *ChallRespFmt = "%s:%s:00000001:%I64d:%s:%s", *ResponseFmt = "charset=%s,username=\"%s\",realm=\"%s\",nonce=\"%s\",nc=00000001,cnonce=\"%I64d\",digest-uri=\"tsp/%s\",response=%s,qop=auth", #endif *A2Fmt = "%s:tsp/%s", A1[33], A1_1[33], A2[33], cA2[33], *String; size_t len; /*-----------------------------------------------------------*/ /* Build HEX(H(A2)) & HEX(H(cA2)) */ len = pal_strlen(A2Fmt) + 12 /* AUTHENTICATE */ + pal_strlen(conf->server) + 1; if( (String = pal_malloc(len)) == NULL ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } pal_snprintf(String, len, A2Fmt, "AUTHENTICATE", conf->server); #if defined(_DEBUG) || defined(DEBUG) printf("A2 = %s\n", String); #endif strncpy(A2, md5(String, pal_strlen(String)), 33); pal_snprintf(String, len, A2Fmt, "", conf->server); #if defined(_DEBUG) || defined(DEBUG) printf("cA2 = %s\n", String); #endif strncpy(cA2, md5(String, pal_strlen(String)), 33); pal_free(String); /*-----------------------------------------------------------*/ /* Build HEX(H(A1)) */ /* A1_1 = { username-value, ":", realm-value, ":", passwd } */ /* A1 = { H( A1_1 ), ":", nonce-value, ":", cnonce-value } */ len = pal_strlen(A1_1Fmt) + pal_strlen(conf->userid) + pal_strlen(c.realm) + pal_strlen(conf->passwd) + 1; if( (String = pal_malloc(len)) == NULL ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } pal_snprintf(String, len, A1_1Fmt, conf->userid, c.realm, conf->passwd); #if defined(_DEBUG) || defined(DEBUG) printf("A1_1 = %s\n", String); #endif md5digest(String, pal_strlen(String), A1_1); pal_free(String); len = 16 /* A1_1 */ + 1 + pal_strlen(c.nonce) + 16 /* cnonce */ + 1; if( (String = pal_malloc(len)) == NULL ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } memcpy(String, A1_1, 16); pal_snprintf(String + 16, len - 16, A1Fmt, c.nonce, cnonce); #ifdef SUPPORT_MD5_BUG1455 A1_1[16] = '\0'; if ((pal_strlen(A1_1) < 16) && !((pal_strlen(TSPProtoVerStr[version_index]) > 5) || (strcmp(TSPProtoVerStr[version_index], CLIENT_VERSION_STRING_2_0_0) > 0))) strncpy(A1, md5(String, pal_strlen(String)), 33); else #endif /* SUPPORT_MD5_BUG1455 */ strncpy(A1, md5(String, 16 + pal_strlen(String + 16)), 33); pal_free(String); #if defined(_DEBUG) || defined(DEBUG) printf("A1 = [%s]\n", A1); #endif /*-----------------------------------------------------------*/ /* Build server's and client's challenge responses */ len = pal_strlen(ChallRespFmt) + 32 /* md5(A1) */ + pal_strlen(c.nonce) +16 /* cnonce */ + pal_strlen(c.qop) + 32 /* md5(A2) */ + 1; if((String = pal_malloc(len)) == NULL) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } pal_snprintf(String, len, ChallRespFmt, A1, c.nonce, cnonce, c.qop, A2); #if defined(_DEBUG) || defined(DEBUG) printf("Response = [%s]\n", String); #endif strncpy(Response, md5(String, pal_strlen(String)), 33); #if defined(_DEBUG) || defined(DEBUG) printf("MD5 Response = %s\n", Response); #endif pal_snprintf(String, len, ChallRespFmt, A1, c.nonce, cnonce, c.qop, cA2); #if defined(_DEBUG) || defined(DEBUG) printf("cResponse = [%s]\n", String); #endif strncpy(cResponse, md5(String, pal_strlen(String)), 33); #if defined(_DEBUG) || defined(DEBUG) printf("MD5 cResponse = %s\n", cResponse); #endif pal_free(String); /*-----------------------------------------------------------*/ /* Build Response */ { char userid[512]; // UserId is theorically limited to 253 chars. char * cc; size_t i; // Escape malicious " and \ from conf->userid. for(cc=conf->userid, i=0; *cc && i<512; cc++, i++) { // Prepend a backslash (\). if( *cc == '"' || *cc == '\\' ) userid[i++] = '\\'; // Copy character. userid[i] = *cc; } userid[i] = '\0'; len = pal_strlen(ResponseFmt) + pal_strlen(c.charset) + pal_strlen(userid) + pal_strlen(c.realm) + pal_strlen(c.nonce) + 16 /*cnonce*/ + pal_strlen(conf->server) + 32 /* md5 response */; if( (String = pal_malloc(len)) == NULL ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } pal_snprintf(String, len, ResponseFmt, c.charset, userid, c.realm, c.nonce, cnonce, conf->server, Response); memset(Buffer, 0, sizeof(Buffer)); base64encode(Buffer, String, (int)pal_strlen(String)); pal_free(String); } } // Send authentication data. memset(BufferIn, 0, sizeof(BufferIn)); if( nt->netprintf(socket, BufferIn, sizeof(BufferIn), "%s\r\n", Buffer) == -1 ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_NET_FAIL_W_SOCKET); return make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); } tsp_status = tspGetStatusCode(BufferIn); // Check if the reply status indicated a broker redirection. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(BufferIn, conf, broker_list) == TSP_REDIRECT_OK ) { // Return a REDIRECT event. return make_status(CTX_TSPAUTHENTICATION, EVNT_BROKER_REDIRECTION); } else { // Redirect error. return make_status(CTX_TSPAUTHENTICATION, ERR_BROKER_REDIRECTION); } } /*-----------------------------------------------------------*/ /* Verify server response */ if( tsp_status == TSP_PROTOCOL_AUTH_FAILED ) { // Failed authentication. Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_TSP_AUTH_FAILED_USER, conf->userid); return make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); } if( (ChallengeString = pal_malloc(pal_strlen(BufferIn) + 1)) == NULL ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_GEN_MALLOC_ERROR); return make_status(CTX_TSPAUTHENTICATION, ERR_MEMORY_STARVATION); } base64decode(ChallengeString, BufferIn); ExtractChallenge(&c, ChallengeString); pal_free(ChallengeString); if( memcmp(c.rspauth, cResponse, 32) ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_MISC_INVALID_MD5_RESPONSE); return make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); } // Receive reply. if( nt->netrecv(socket, Buffer, sizeof(Buffer) ) == -1 ) { Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_NET_FAIL_R_SOCKET); return make_status(CTX_TSPAUTHENTICATION, ERR_SOCKET_IO); } tsp_status = tspGetStatusCode(Buffer); // Check if the reply status indicated a broker redirection. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(Buffer, conf, broker_list) == TSP_REDIRECT_OK ) { // Return a REDIRECT event. return make_status(CTX_TSPAUTHENTICATION, EVNT_BROKER_REDIRECTION); } else { // Redirect error. return make_status(CTX_TSPAUTHENTICATION, ERR_BROKER_REDIRECTION); } } // Check if authentication was successful. switch( tsp_status ) { case TSP_PROTOCOL_SUCCESS: break; case TSP_PROTOCOL_AUTH_FAILED: Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_TSP_AUTH_FAILED_USER, conf->userid); return make_status(CTX_TSPAUTHENTICATION, ERR_AUTHENTICATION_FAILURE); default: Display(LOG_LEVEL_1, ELError, "AuthDIGEST_MD5", STR_TSP_UNKNOWN_ERR_AUTH_FAILED, tspGetTspStatusStr(tsp_status)); return make_status(CTX_TSPAUTHENTICATION, ERR_TSP_GENERIC_ERROR); } // Successful MD5 authentication. return make_status(CTX_TSPAUTHENTICATION, SUCCESS); }
gogoc_status tspStartLocal(int socket, tConf *c, tTunnel *t, net_tools_t *nt) { TUNNEL_LOOP_CONFIG tun_loop_cfg; int keepalive_interval = 0; gogoc_status status = STATUS_SUCCESS_INIT; /* Test for root privileges */ if(geteuid() != 0) { Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_FATAL_NOT_ROOT_FOR_TUN); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } /* start the tunneler service */ if (t->keepalive_interval != NULL) { keepalive_interval = atoi(t->keepalive_interval); } { Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_GOING_DAEMON); // Check if we're already daemon. Calling multiple times the daemon() messes up pthreads. if( !c->nodaemon && getppid() != 1 ) { if (daemon(1, 0) == -1) { Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_CANT_FORK); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } } if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V6UDPV4_ON_PLATFORM); return(make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED)); } if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 ) { Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V4V6_ON_PLATFORM); return(make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED)); } /* now, run the config script without giving it our tunnel file descriptor. // // This is important because otherwise the tunnnel will stay open even // if we get killed. */ { int pid = fork(); if (pid < 0) { // fork() error return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } else if (pid == 0) { // Child process status = tspSetupInterface(c, t); exit(status); } else { // Parent process int s = 0; Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_WAITING_FOR_SETUP_SCRIPT); if (wait(&s) == pid) { // Our child returned if ( !WIFEXITED(s) ) { Display(LOG_LEVEL_1, ELError, "tspStartLocal", STR_GEN_SCRIPT_EXEC_FAILED); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } // Check exit status. status = WEXITSTATUS(s); if( status_number(status) != SUCCESS ) { return status; } } else { // Error occured: we have no other child Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_ERR_WAITING_SCRIPT); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } } } if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 ) { memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) ); tun_loop_cfg.ka_interval = keepalive_interval; tun_loop_cfg.ka_src_addr = t->client_address_ipv6; tun_loop_cfg.ka_dst_addr = t->keepalive_address; tun_loop_cfg.sa_family = AF_INET6; tun_loop_cfg.tun_lifetime = 0; status = tspPerformTunnelLoop( &tun_loop_cfg ); } /* v4v6 not supported yet if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 ) { memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) ); tun_loop_cfg.ka_interval = keepalive_interval; tun_loop_cfg.ka_src_addr = t->client_address_ipv4; tun_loop_cfg.ka_dst_addr = t->keepalive_address; tun_loop_cfg.sa_family = AF_INET; tun_loop_cfg.tun_lifetime = atoi(t->lifetime); status = tspPerformTunnelLoop( &tun_loop_cfg ); } */ } // Handle tunnel teardown. tspTearDownTunnel( c, t ); return status; }
gogoc_status tspStartLocal( int socket, tConf *c, tTunnel *t, net_tools_t *nt ) { TUNNEL_LOOP_CONFIG tun_loop_cfg; gogoc_status status = STATUS_SUCCESS_INIT; int ka_interval = 0; int tunfd = -1; //int pid; // Check if we got root privileges. if( geteuid() != 0 ) { // Error: we don't have root privileges. Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_FATAL_NOT_ROOT_FOR_TUN ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } // Check if we're already daemon. Calling multiple times the daemon() messes up pthreads. if( !c->nodaemon && getppid() != 1 ) { // Detach from controlling terminal and run in the background. Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_GOING_DAEMON ); if( daemon(1, 0) == -1 ) { // Error: Failed to detach. Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_CANT_FORK ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } } // Check tunnel mode. if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 ) { // V4V6 encapsulation (DSTM) not supported on darwin. Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V4V6_ON_PLATFORM ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { // When using V6UDPV4 encapsulation, open the TUN device. tunfd = TunInit(c->if_tunnel_v6udpv4); if( tunfd == -1 ) { // Error: Failed to open TUN device. Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_MISC_FAIL_TUN_INIT ); return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); } // Get the real name of the opened tun device for the template script. free( c->if_tunnel_v6udpv4 ); c->if_tunnel_v6udpv4 = (char*) malloc( IFNAMSIZ ); TunName( tunfd, c->if_tunnel_v6udpv4, IFNAMSIZ ); } t->originalgateway = routepr(); while( 1 ) // Dummy loop. 'break' instruction at the end. { // Run the config script in another thread, without giving it our tunnel // descriptor. This is important because otherwise the tunnel will stay // open if we get killed. // // pid = fork(); // if( pid < 0 ) // { // fork() error // status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); // break; // } // else if( pid == 0 ) // { // Child processing: run template script. // if( tunfd != -1 ) // { // close(tunfd); // } status = tspSetupInterface(c, t); // exit( status ); // } // else // { // Parent processing // int s = 0; // Wait for child process to exit. // Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_WAITING_FOR_SETUP_SCRIPT ); // if( wait(&s) != pid ) // { // // Error occured: we have no other child // Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_ERR_WAITING_SCRIPT ); // status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); // break; // } // Check if process waited upon has exited. // if( !WIFEXITED(s) ) // { // // Error: child has not exited properly. Maybe killed ? // Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_GEN_SCRIPT_EXEC_FAILED ); // Display( LOG_LEVEL_1, ELError, "tspStartLocal", "status 0x%08X %s (%d).", s, strerror(s), errno); // status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED); // break; // } // Check child exit code. // status = WEXITSTATUS(s); if( status_number(status) != SUCCESS ) { break; } // } gStatusInfo.eStatus = GOGOC_CLISTAT__CONNECTED; gStatusInfo.nStatus = GOGOCM_UIS__NOERROR; send_status_info(); // Retrieve keepalive inteval, if found in tunnel parameters. if( t->keepalive_interval != NULL ) { ka_interval = atoi(t->keepalive_interval); } // Start the tunnel loop, depending on tunnel mode // if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { status = TunMainLoop( tunfd, socket, c->keepalive, ka_interval, t->client_address_ipv6, t->keepalive_address ); LOG( LOG_LEVEL_2, ELInfo, "end TunMainLoop. Starting tspClose."); // We got out of main V6UDPV4 loop. tspClose(socket, nt); LOG( LOG_LEVEL_2, ELInfo, "end tspClose."); } else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 ) { memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) ); tun_loop_cfg.ka_interval = ka_interval; tun_loop_cfg.ka_src_addr = t->client_address_ipv6; tun_loop_cfg.ka_dst_addr = t->keepalive_address; tun_loop_cfg.sa_family = AF_INET6; tun_loop_cfg.tun_lifetime = 0; status = tspPerformTunnelLoop( &tun_loop_cfg ); } break; // END of DUMMY loop. } // Cleanup: Close tunnel descriptor, if it was opened. if( tunfd != -1 ) { LOG( LOG_LEVEL_2, ELInfo, "Closing tunnel descriptor"); // The tunnel file descriptor should be closed before attempting to tear // down the tunnel. Destruction of the tunnel interface may fail if // descriptor is not closed. close( tunfd ); } // Cleanup: Handle tunnel teardown. LOG( LOG_LEVEL_2, ELInfo, "Handle tunnel teardown"); tspTearDownTunnel( c, t ); return status; }
// -------------------------------------------------------------------------- // tspGetCapabilities: // gogoc_status tspGetCapabilities(pal_socket_t socket, net_tools_t *nt, tCapability *capability, int version_index, tConf *conf, tBrokerList **broker_list) { char dataout[256]; char datain[REDIRECT_RECEIVE_BUFFER_SIZE]; sint32_t tsp_status; gogoc_status status = make_status(CTX_TSPCAPABILITIES, SUCCESS); memset( datain, 0, sizeof(datain) ); pal_snprintf(dataout, sizeof(dataout), "VERSION=%s\r\n", TSPProtoVerStr[version_index]); // Send TSP version to the server. Server should reply with the capabilities. if( nt->netsendrecv(socket, dataout, pal_strlen(dataout), datain, (sint32_t)sizeof(datain)) == -1 ) { // Error reading/writing to the socket. return make_status(CTX_TSPCAPABILITIES, ERR_SOCKET_IO); } // Check if we received the TSP capabilities. if( memcmp("CAPABILITY ", datain, 11) == 0 ) { // Extract the capabilities. *capability = tspExtractCapability(datain); } else { // Retrieve the TSP status from the reply. tsp_status = tspGetStatusCode(datain); // Check if it is a redirect TSP status. if( tspIsRedirectStatus(tsp_status) ) { if( tspHandleRedirect(datain, conf, broker_list) == TSP_REDIRECT_OK ) { // REDIRECT event. status = make_status(CTX_TSPCAPABILITIES, EVNT_BROKER_REDIRECTION); } else { // Redirect error. status = make_status(CTX_TSPCAPABILITIES, ERR_BROKER_REDIRECTION); } } else { switch( tsp_status ) { case TSP_PROTOCOL_SERVER_TOO_BUSY: // Ze server iz too busy. Display(LOG_LEVEL_1, ELWarning, "tspGetCapabilities", STR_TSP_SERVER_TOO_BUSY); status = make_status(CTX_TSPCAPABILITIES, ERR_TSP_SERVER_TOO_BUSY); break; case TSP_PROTOCOL_UNSUP_TSP_VER: // The status was an invalid TSP version. Display(LOG_LEVEL_1, ELWarning, "tspGetCapabilities", STR_TSP_INVALID_VERSION, TSPProtoVerStr[version_index]); status = make_status(CTX_TSPCAPABILITIES, ERR_INVAL_TSP_VERSION); break; default: // Unknown / unexpected TSP error occurred. Display(LOG_LEVEL_1, ELError, "tspGetCapabilities", STR_TSP_GEN_ERROR, tsp_status, tspGetTspStatusStr(tsp_status)); status = make_status(CTX_TSPCAPABILITIES, ERR_TSP_GENERIC_ERROR); break; } Display(LOG_LEVEL_1, ELError, "tspGetCapabilities", STR_TSP_GETCAPABILITIES_ERROR); } } // Successful operation. return status; }