Ejemplo n.º 1
0
/* (err, data) = cyrussasl.client_step(conn, data)
 *
 * Arguments:
 *   conn: the return result from a previous call to client_new
 *   data: any data that the client might have sent from the previous step.
 *         Note that data may still be an empty string or nil. (Like the 
 *         argument of the same name to server_start.)
 *
 * Return values:
 *   err: the (integer) SASL error code reflecting the state of the attempt 
 *        (e.g. SASL_OK, SASL_CONTINUE, SASL_BADMECH, ...)
 *   data: data that the server wants to send to the client in order 
 *         to continue the authN attempt. Returned as a Lua string object.
 */
static int cyrussasl_sasl_client_step(lua_State *l)
{
  int numargs = lua_gettop(l);
  int err;
  struct _sasl_ctx *ctx = NULL;
  const char *data = NULL;
  size_t len;
  unsigned outlen;

  if (numargs != 2) {
    lua_pushstring(l, 
		   "usage: (err, data) = cyrussasl.client_step(conn, data)");
    lua_error(l);
    return 0;
  }

  ctx = get_context(l, 1);
  data = tolstring(l, 2, &len);

  err = sasl_client_step( ctx->conn,
			  data,
			  len,
			  NULL, /* prompt_need */
			  &data,
			  &outlen );

  /* Form the reply and push onto the stack */
  lua_pushinteger(l, err);          /* SASL_CONTINUE, SASL_OK, et al  */
  if (data) {
    lua_pushlstring(l, data, outlen); /* server's reply to the client   */
  } else {
    lua_pushnil(l);
  }
  return 2;                         /* returning 2 items on Lua stack */
}
Ejemplo n.º 2
0
bson_bool_t
_mongoc_sasl_step (mongoc_sasl_t      *sasl,
                   const bson_uint8_t *inbuf,
                   bson_uint32_t       inbuflen,
                   bson_uint8_t       *outbuf,
                   bson_uint32_t       outbufmax,
                   bson_uint32_t      *outbuflen,
                   bson_error_t       *error)
{
   const char *raw = NULL;
   unsigned rawlen = 0;
   int status;

   BSON_ASSERT (sasl);
   BSON_ASSERT (inbuf);
   BSON_ASSERT (outbuf);
   BSON_ASSERT (outbuflen);
   BSON_ASSERT (*outbuflen);

   sasl->step++;

   if (sasl->step == 1) {
      return _mongoc_sasl_start (sasl, outbuf, outbufmax, outbuflen,
                                 error);
   } else if (sasl->step >= 10) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      SASL_NOTDONE,
                      "SASL Failure: maximum steps detected");
      return FALSE;
   }

   if (!inbuflen) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      MONGOC_ERROR_CLIENT_AUTHENTICATE,
                      "SASL Failure: no payload provided from server.");
      return FALSE;
   }

   status = sasl_decode64 ((char *)inbuf, inbuflen, (char *)outbuf, outbufmax,
                           outbuflen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return FALSE;
   }

   status = sasl_client_step (sasl->conn, (char *)outbuf, *outbuflen,
                              &sasl->interact, &raw, &rawlen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return FALSE;
   }

   status = sasl_encode64 (raw, rawlen, (char *)outbuf, outbufmax, outbuflen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return FALSE;
   }

   return TRUE;
}
Ejemplo n.º 3
0
static JabberSaslState
jabber_cyrus_handle_challenge(JabberStream *js, xmlnode *packet,
                              xmlnode **reply, char **error)
{
	char *enc_in = xmlnode_get_data(packet);
	unsigned char *dec_in;
	char *enc_out;
	const char *c_out;
	unsigned int clen;
	gsize declen;

	dec_in = purple_base64_decode(enc_in, &declen);

	js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen,
					  NULL, &c_out, &clen);
	g_free(enc_in);
	g_free(dec_in);
	if (js->sasl_state != SASL_CONTINUE && js->sasl_state != SASL_OK) {
		gchar *tmp = g_strdup_printf(_("SASL error: %s"),
				sasl_errdetail(js->sasl));
		purple_debug_error("jabber", "Error is %d : %s\n",
				js->sasl_state, sasl_errdetail(js->sasl));
		*error = tmp;
		return JABBER_SASL_STATE_FAIL;
	} else {
		xmlnode *response = xmlnode_new("response");
		xmlnode_set_namespace(response, NS_XMPP_SASL);
		if (clen > 0) {
			/* Cyrus SASL 2.1.22 appears to contain code to add the charset
			 * to the response for DIGEST-MD5 but there is no possibility
			 * it will be executed.
			 *
			 * My reading of the digestmd5 plugin indicates the username and
			 * realm are always encoded in UTF-8 (they seem to be the values
			 * we pass in), so we need to ensure charset=utf-8 is set.
			 */
			if (!purple_strequal(js->current_mech, "DIGEST-MD5") ||
					strstr(c_out, ",charset="))
				/* If we're not using DIGEST-MD5 or Cyrus SASL is fixed */
				enc_out = purple_base64_encode((unsigned char*)c_out, clen);
			else {
				char *tmp = g_strdup_printf("%s,charset=utf-8", c_out);
				enc_out = purple_base64_encode((unsigned char*)tmp, clen + 14);
				g_free(tmp);
			}

			xmlnode_insert_data(response, enc_out, -1);
			g_free(enc_out);
		}

		*reply = response;
		return JABBER_SASL_STATE_CONTINUE;
	}
}
Ejemplo n.º 4
0
int virNetSASLSessionClientStep(virNetSASLSessionPtr sasl,
                                const char *serverin,
                                size_t serverinlen,
                                sasl_interact_t **prompt_need,
                                const char **clientout,
                                size_t *clientoutlen)
{
    unsigned inlen = serverinlen;
    unsigned outlen = 0;
    int err;
    int ret = -1;

    VIR_DEBUG("sasl=%p serverin=%p serverinlen=%zu prompt_need=%p clientout=%p clientoutlen=%p",
              sasl, serverin, serverinlen, prompt_need, clientout, clientoutlen);

    virObjectLock(sasl);
    err = sasl_client_step(sasl->conn,
                           serverin,
                           inlen,
                           prompt_need,
                           clientout,
                           &outlen);
    *clientoutlen = outlen;

    switch (err) {
    case SASL_OK:
        if (virNetSASLSessionUpdateBufSize(sasl) < 0)
            goto cleanup;
        ret = VIR_NET_SASL_COMPLETE;
        break;
    case SASL_CONTINUE:
        ret = VIR_NET_SASL_CONTINUE;
        break;
    case SASL_INTERACT:
        ret = VIR_NET_SASL_INTERACT;
        break;
    default:
        virReportError(VIR_ERR_AUTH_FAILED,
                       _("Failed to step SASL negotiation: %d (%s)"),
                       err, sasl_errdetail(sasl->conn));
        break;
    }

cleanup:
    virObjectUnlock(sasl);
    return ret;
}
Ejemplo n.º 5
0
static JabberSaslState
jabber_cyrus_handle_success(JabberStream *js, xmlnode *packet,
                            char **error)
{
	const void *x;

	/* The SASL docs say that if the client hasn't returned OK yet, we
	 * should try one more round against it
	 */
	if (js->sasl_state != SASL_OK) {
		char *enc_in = xmlnode_get_data(packet);
		unsigned char *dec_in = NULL;
		const char *c_out;
		unsigned int clen;
		gsize declen = 0;

		if(enc_in != NULL)
			dec_in = purple_base64_decode(enc_in, &declen);

		js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen, NULL, &c_out, &clen);

		g_free(enc_in);
		g_free(dec_in);

		if (js->sasl_state != SASL_OK) {
			/* This happens when the server sends back jibberish
			 * in the "additional data with success" case.
			 * Seen with Wildfire 3.0.1.
			 */
			*error = g_strdup(_("Invalid response from server"));
			return JABBER_SASL_STATE_FAIL;
		}
	}

	/* If we've negotiated a security layer, we need to enable it */
	if (js->sasl) {
		sasl_getprop(js->sasl, SASL_SSF, &x);
		if (*(int *)x > 0) {
			sasl_getprop(js->sasl, SASL_MAXOUTBUF, &x);
			js->sasl_maxbuf = *(int *)x;
		}
	}

	return JABBER_SASL_STATE_OK;
}
Ejemplo n.º 6
0
int php_mongo_saslcontinue(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, sasl_conn_t *conn, char *step_payload, int step_payload_len, int32_t conversation_id, char **error_message) {
	sasl_interact_t *client_interact=NULL;

	/*
	 * Snippet from sasl.h:
	 *  4. client calls sasl_client_step()
	 *  4b. If SASL error, goto 7 or 3
	 *  4c. If SASL_OK, continue or goto 6 if last server response was success
	 */

	do {
		char base_payload[4096], payload[4096];
		unsigned int base_payload_len, payload_len;
		const char *out;
		unsigned int outlen;
		unsigned char done = 0;
		int result;

		step_payload_len--; /* Remove the \0 from the string */
		result = sasl_decode64(step_payload, step_payload_len, base_payload, sizeof(base_payload), &base_payload_len);
		if (is_sasl_failure(conn, result, error_message)) {
			return 0;
		}

		result = sasl_client_step(conn, (const char *)base_payload, base_payload_len, &client_interact, &out, &outlen);
		if (is_sasl_failure(conn, result, error_message)) {
			return 0;
		}

		result = sasl_encode64(out, outlen, payload, sizeof(base_payload), &payload_len);
		if (is_sasl_failure(conn, result, error_message)) {
			return 0;
		}

		if (!mongo_connection_authenticate_saslcontinue(manager, con, options, server_def, conversation_id, payload, payload_len + 1, &step_payload, &step_payload_len, &done, error_message)) {
			return 0;
		}

		if (done) {
			break;
		}
	} while (1);

	return 1;
}
Ejemplo n.º 7
0
	POP3_SASL_STATE_E Pop3SaslWrapper::SaslStep(string& auth_str)
	{
		int sasl_result;
		const char* out = NULL;
		unsigned int outlen = 0;
		if(init == false)
		{				
			string mechlist = sasl_data.mech;
			const char *mechusing;

			do
			{
				sasl_result = sasl_client_start(conn, mechlist.c_str(), &client_interact, &out, &outlen, &mechusing);
			}while(sasl_result == SASL_INTERACT);
				
			if(sasl_result != SASL_CONTINUE)
			{
				//Log Error
				POP3_SASL_DEBUG("SASL-Error 4 - \n");
				return POP3_SASL_ERROR;
			}

			init = true;
			auth_str.assign(out, outlen);				
			return POP3_SASL_OK;
		}

		do
		{
			sasl_result = sasl_client_step(conn, auth_str.c_str(), auth_str.length(), &client_interact, &out, &outlen);
			POP3_DEBUG_INFO1("sasl_result : %d\n", sasl_result);

		}while(sasl_result == SASL_INTERACT);

		if(sasl_result != SASL_OK && sasl_result != SASL_CONTINUE)
		{
			//Log Error
			POP3_SASL_DEBUG("SASL-Error 5 -- \n");
			return POP3_SASL_ERROR;
		}
		
		auth_str.assign(out, outlen);
		return POP3_SASL_OK;

	}
Ejemplo n.º 8
0
int php_mongo_saslcontinue(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, sasl_conn_t *conn, char *step_payload, int step_payload_len, int32_t conversation_id, char **error_message) {
	int result;
	sasl_interact_t *client_interact=NULL;

	do {
		char base_payload[4096], payload[4096];
		unsigned int base_payload_len, payload_len;
		unsigned char done;
		const char *out;
		unsigned int outlen;

		result = sasl_decode64(step_payload, step_payload_len, base_payload, sizeof(base_payload), &base_payload_len);
		if (is_sasl_failure(conn, result, error_message)) {
			return result;
		}

		result = sasl_client_step(conn, (const char *)base_payload, base_payload_len, &client_interact, &out, &outlen);
		if (is_sasl_failure(conn, result, error_message)) {
			return result;
		}

		/* TODO : Deal with interaction */

		if (result == SASL_OK) {
			/* We are all done */
			break;
		}

		result = sasl_encode64(out, outlen, payload, sizeof(base_payload), &payload_len);
		if (is_sasl_failure(conn, result, error_message)) {
			return result;
		}

		if (!mongo_connection_authenticate_saslcontinue(manager, con, options, server_def, conversation_id, payload, payload_len + 1, &step_payload, &step_payload_len, &done, (char **)&error_message)) {
			*error_message = strdup("saslStart failed miserably");
			return result;
		}
	} while (result == SASL_INTERACT || result == SASL_CONTINUE);

	return result;
}
Ejemplo n.º 9
0
/* Evaluates the challenge data and generates a response. */
uint8_t* TSaslClient::evaluateChallengeOrResponse(
    const uint8_t* challenge, const uint32_t len, uint32_t *resLen) {
    sasl_interact_t* client_interact=NULL;
    uint8_t* out=NULL;
    uint32_t outlen=0;
    uint32_t result;
    char* mechUsing;

    if (!clientStarted) {
        result=sasl_client_start(conn,
                                 mechList.c_str(),
                                 &client_interact, /* filled in if an interaction is needed */
                                 (const char**)&out,      /* filled in on success */
                                 &outlen,   /* filled in on success */
                                 (const char**)&mechUsing);
        clientStarted = true;
        chosenMech = mechUsing;
    } else {
        if (len  > 0) {
            result=sasl_client_step(conn,  /* our context */
                                    (const char*)challenge,    /* the data from the server */
                                    len, /* its length */
                                    &client_interact,  /* this should be unallocated and NULL */
                                    (const char**)&out,     /* filled in on success */
                                    &outlen); /* filled in on success */
        } else {
            result = SASL_CONTINUE;
        }
    }

    if (result == SASL_OK) {
        authComplete = true;
    } else if (result != SASL_CONTINUE) {
        throw SaslClientImplException(sasl_errdetail(conn));
    }
    *resLen = outlen;
    return (uint8_t*)out;
}
Ejemplo n.º 10
0
static int pni_wrap_client_step(pni_sasl_t *sasl, const pn_bytes_t *in)
{
    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
    sasl_interact_t *client_interact=NULL;
    const char *out;
    unsigned outlen;

    int result;
    do {

        result = sasl_client_step(cyrus_conn,
                                  in->start, in->size,
                                  &client_interact,
                                  &out, &outlen);
        if (result==SASL_INTERACT) {
            pni_cyrus_interact(sasl, client_interact);
        }
    } while (result==SASL_INTERACT);

    sasl->bytes_out.start = out;
    sasl->bytes_out.size = outlen;
    return result;
}
Ejemplo n.º 11
0
static int
nsldapi_sasl_do_bind( LDAP *ld, const char *dn,
        const char *mechs, unsigned flags,
        LDAP_SASL_INTERACT_PROC *callback, void *defaults,
        LDAPControl **sctrl, LDAPControl **cctrl, LDAPControl ***rctrl )
{
        sasl_interact_t *prompts = NULL;
        sasl_conn_t     *ctx = NULL;
        sasl_ssf_t      *ssf = NULL;
        const char      *mech = NULL;
        int             saslrc, rc;
        struct berval   ccred;
        unsigned        credlen;
        int stepnum = 1;
        char *sasl_username = NULL;

        if (rctrl) {
            /* init to NULL so we can call ldap_controls_free below */
            *rctrl = NULL;
        }

        if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) {
                LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
                return( LDAP_NOT_SUPPORTED );
        }

        /* shouldn't happen */
        if (callback == NULL) {
                return( LDAP_LOCAL_ERROR );
        }

        if ( (rc = nsldapi_sasl_open(ld, NULL, &ctx, 0)) != LDAP_SUCCESS ) {
            return( rc );
        }

        ccred.bv_val = NULL;
        ccred.bv_len = 0;

        LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n",
                  (mechs ? mechs : ""), 0, 0 );

        do {
                saslrc = sasl_client_start( ctx,
                        mechs,
                        &prompts,
                        (const char **)&ccred.bv_val,
                        &credlen,
                        &mech );

                LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of client start for SASL/%s authentication\n",
                          stepnum, (mech ? mech : ""), 0 );
                stepnum++;

                if( saslrc == SASL_INTERACT &&
                    (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) {
                        break;
                }
        } while ( saslrc == SASL_INTERACT );

        ccred.bv_len = credlen;

        if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
                return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
        }

        stepnum = 1;

        do {
                struct berval *scred;
                int clientstepnum = 1;

                scred = NULL;

                if (rctrl) {
                    /* if we're looping again, we need to free any controls set
                       during the previous loop */
                    /* NOTE that this assumes we only care about the controls
                       returned by the last call to nsldapi_sasl_bind_s - if
                       we care about _all_ controls, we will have to figure out
                       some way to append them each loop go round */
                    ldap_controls_free(*rctrl);
                    *rctrl = NULL;
                }

                LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of bind for SASL/%s authentication\n",
                          stepnum, (mech ? mech : ""), 0 );
                stepnum++;

                /* notify server of a sasl bind step */
                rc = nsldapi_sasl_bind_s(ld, dn, mech, &ccred,
                                      sctrl, cctrl, &scred, rctrl); 

                if ( ccred.bv_val != NULL ) {
                        ccred.bv_val = NULL;
                }

                if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
                        ber_bvfree( scred );
                        return( rc );
                }

                if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
                        /* we're done, no need to step */
                        if( scred ) {
                            if ( scred->bv_len == 0 ) { /* MS AD sends back empty screds */
                                LDAPDebug(LDAP_DEBUG_ANY,
                                          "SASL BIND complete - ignoring empty credential response\n",
                                          0, 0, 0);
                                ber_bvfree( scred );
                            } else {
                                /* but server provided us with data! */
                                LDAPDebug(LDAP_DEBUG_TRACE,
                                          "SASL BIND complete but invalid because server responded with credentials - length [%u]\n",
                                          scred->bv_len, 0, 0);
                                ber_bvfree( scred );
                                LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR,
                                                  NULL, "Error during SASL handshake - invalid server credential response" );
                                return( LDAP_LOCAL_ERROR );
                            }
                        }
                        break;
                }

                /* perform the next step of the sasl bind */
                do {
                        LDAPDebug(LDAP_DEBUG_TRACE, "Doing client step %d of bind step %d for SASL/%s authentication\n",
                                  clientstepnum, stepnum, (mech ? mech : "") );
                        clientstepnum++;
                        saslrc = sasl_client_step( ctx,
                                (scred == NULL) ? NULL : scred->bv_val,
                                (scred == NULL) ? 0 : scred->bv_len,
                                &prompts,
                                (const char **)&ccred.bv_val,
                                &credlen );

                        if( saslrc == SASL_INTERACT &&
                            (callback)(ld, flags, defaults, prompts)
                                                        != LDAP_SUCCESS ) {
                                break;
                        }
                } while ( saslrc == SASL_INTERACT );

                ccred.bv_len = credlen;
                ber_bvfree( scred );

                if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
                        return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
                }
        } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );

        if ( rc != LDAP_SUCCESS ) {
                return( rc );
        }

        if ( saslrc != SASL_OK ) {
                return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
        }

        saslrc = sasl_getprop( ctx, SASL_USERNAME, (const void **) &sasl_username );
        if ( (saslrc == SASL_OK) && sasl_username ) {
                LDAPDebug(LDAP_DEBUG_TRACE, "SASL identity: %s\n", sasl_username, 0, 0);
        }

        saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
        if( saslrc == SASL_OK ) {
                if( ssf && *ssf ) {
                        LDAPDebug(LDAP_DEBUG_TRACE,
                                "SASL install encryption, for SSF: %lu\n",
                                (unsigned long) *ssf, 0, 0 );
                        nsldapi_sasl_install( ld, NULL );
                }
        }

        return( rc );
}
Ejemplo n.º 12
0
static int xsasl_cyrus_client_next(XSASL_CLIENT *xp, const char *server_reply,
				           VSTRING *client_reply)
{
    const char *myname = "xsasl_cyrus_client_next";
    XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
    unsigned enc_length;
    unsigned enc_length_out;
    CLIENTOUT_TYPE clientout;
    unsigned clientoutlen;
    unsigned serverinlen;
    int     sasl_status;

    /*
     * Process a server challenge.
     */
    serverinlen = strlen(server_reply);
    VSTRING_RESET(client->decoded);		/* Fix 200512 */
    VSTRING_SPACE(client->decoded, serverinlen);
    if ((sasl_status = SASL_DECODE64(server_reply, serverinlen,
				     STR(client->decoded),
				     vstring_avail(client->decoded),
				     &enc_length)) != SASL_OK) {
	vstring_strcpy(client_reply, xsasl_cyrus_strerror(sasl_status));
	return (XSASL_AUTH_FORM);
    }
    if (msg_verbose)
	msg_info("%s: decoded challenge: %.*s",
		 myname, (int) enc_length, STR(client->decoded));
    sasl_status = sasl_client_step(client->sasl_conn, STR(client->decoded),
				   enc_length, NO_SASL_INTERACTION,
				   &clientout, &clientoutlen);
    if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) {
	vstring_strcpy(client_reply, xsasl_cyrus_strerror(sasl_status));
	return (XSASL_AUTH_FAIL);
    }

    /*
     * Send a client response.
     */
    if (clientoutlen > 0) {
	if (msg_verbose)
	    msg_info("%s: uncoded client response %.*s",
		     myname, (int) clientoutlen, clientout);
	enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
	VSTRING_RESET(client_reply);		/* Fix 200512 */
	VSTRING_SPACE(client_reply, enc_length);
	if ((sasl_status = sasl_encode64(clientout, clientoutlen,
					 STR(client_reply),
					 vstring_avail(client_reply),
					 &enc_length_out)) != SASL_OK)
	    msg_panic("%s: sasl_encode64 botch: %s",
		      myname, xsasl_cyrus_strerror(sasl_status));
#if SASL_VERSION_MAJOR < 2
	/* SASL version 1 doesn't free memory that it allocates. */
	free(clientout);
#endif
    } else {
	/* XXX Can't happen. */
	vstring_strcpy(client_reply, "");
    }
    return (XSASL_AUTH_OK);
}
Ejemplo n.º 13
0
/**
 * Handle received frame from broker.
 */
static int rd_kafka_sasl_handle_recv (rd_kafka_transport_t *rktrans,
				      rd_kafka_buf_t *rkbuf,
				      char *errstr, int errstr_size) {
	int r;

	rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "SASL",
		   "Received SASL frame from broker (%"PRIdsz" bytes)",
		   rkbuf ? rkbuf->rkbuf_len : 0);

	if (rktrans->rktrans_sasl.complete && (!rkbuf || rkbuf->rkbuf_len == 0))
		goto auth_successful;

	do {
		sasl_interact_t *interact = NULL;
		const char *out;
		unsigned int outlen;

		r = sasl_client_step(rktrans->rktrans_sasl.conn,
				     rkbuf && rkbuf->rkbuf_len > 0 ?
				     rkbuf->rkbuf_rbuf : NULL,
				     rkbuf ? rkbuf->rkbuf_len : 0,
				     &interact,
				     &out, &outlen);

		if (rkbuf) {
			rd_kafka_buf_destroy(rkbuf);
			rkbuf = NULL;
		}

		if (r >= 0) {
			/* Note: outlen may be 0 here for an empty response */
			if (rd_kafka_sasl_send(rktrans, out, outlen,
					       errstr, errstr_size) == -1)
				return -1;
		}

		if (r == SASL_INTERACT)
			rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "SASL",
				   "SASL_INTERACT: %lu %s, %s, %s, %p",
				   interact->id,
				   interact->challenge,
				   interact->prompt,
				   interact->defresult,
				   interact->result);

	} while (r == SASL_INTERACT);

	if (r == SASL_CONTINUE)
		return 0;  /* Wait for more data from broker */
	else if (r != SASL_OK) {
		rd_snprintf(errstr, errstr_size,
			    "SASL handshake failed (step): %s",
			    sasl_errdetail(rktrans->rktrans_sasl.conn));
		return -1;
	}

	/* Authentication successful */
auth_successful:
	if (rktrans->rktrans_rkb->rkb_rk->rk_conf.debug &
	    RD_KAFKA_DBG_SECURITY) {
		const char *user, *mech, *authsrc;

		if (sasl_getprop(rktrans->rktrans_sasl.conn, SASL_USERNAME,
				 (const void **)&user) != SASL_OK)
			user = "******";
		
		if (sasl_getprop(rktrans->rktrans_sasl.conn, SASL_MECHNAME,
				 (const void **)&mech) != SASL_OK)
			mech = "(unknown)";

		if (sasl_getprop(rktrans->rktrans_sasl.conn, SASL_AUTHSOURCE,
				 (const void **)&authsrc) != SASL_OK)
			authsrc = "(unknown)";
			
		rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "SASL",
			   "Authenticated as %s using %s (%s)",
			   user, mech, authsrc);
	}

	rd_kafka_broker_connect_up(rktrans->rktrans_rkb);

	return 0;
}
Ejemplo n.º 14
0
	int clientTryAgain()
	{
		if(step == 0) {
			const char *clientout, *m;
			unsigned int clientoutlen;

			need = 0;
			QString list = methodsToString(mechlist);
			int r;
			while(1) {
				if(need)
					params.extractHave(need);
				if(in_sendFirst)
					r = sasl_client_start(con, list.toLatin1().data(), &need, &clientout, &clientoutlen, &m);
				else
					r = sasl_client_start(con, list.toLatin1().data(), &need, NULL, NULL, &m);
				if(r != SASL_INTERACT)
					break;

				params.applyInteract(need);
				if(params.missingAny())
					return NeedParams;
			}
			if(r != SASL_OK && r != SASL_CONTINUE) {
				err = saslErrorCond(r);
				return Error;
			}

			out_mech = m;
			if(in_sendFirst && clientout) {
				out_clientInit = makeByteArray(clientout, clientoutlen);
				out_useClientInit = true;
			}
			else
				out_useClientInit = false;

			++step;

			if(r == SASL_OK) {
				getssfparams();
				return Success;
			}
			return Continue;
		}
		else {
			const char *clientout;
			unsigned int clientoutlen;
			int r;
			while(1) {
				if(need)
					params.extractHave(need);
				//QByteArray cs(in_buf.data(), in_buf.size());
				//printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", cs.data(), in_buf.size());
				r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen);
				//printf("returned: %d\n", r);
				if(r != SASL_INTERACT)
					break;

				params.applyInteract(need);
				if(params.missingAny())
					return NeedParams;
			}
			if(r != SASL_OK && r != SASL_CONTINUE) {
				err = saslErrorCond(r);
				return Error;
			}
			out_buf = makeByteArray(clientout, clientoutlen);
			if(r == SASL_OK) {
				getssfparams();
				return Success;
			}
			return Continue;
		}
	}
Ejemplo n.º 15
0
bool
_mongoc_cyrus_step (mongoc_cyrus_t *sasl,
                    const uint8_t *inbuf,
                    uint32_t inbuflen,
                    uint8_t *outbuf,
                    uint32_t outbufmax,
                    uint32_t *outbuflen,
                    bson_error_t *error)
{
   const char *raw = NULL;
   unsigned rawlen = 0;
   int status;

   BSON_ASSERT (sasl);
   BSON_ASSERT (inbuf);
   BSON_ASSERT (outbuf);
   BSON_ASSERT (outbuflen);

   TRACE ("Running %d, inbuflen: %" PRIu32, sasl->step, inbuflen);
   sasl->step++;

   if (sasl->step == 1) {
      return _mongoc_cyrus_start (sasl, outbuf, outbufmax, outbuflen, error);
   } else if (sasl->step >= 10) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      SASL_NOTDONE,
                      "SASL Failure: maximum steps detected");
      return false;
   }

   TRACE ("Running %d, inbuflen: %" PRIu32, sasl->step, inbuflen);
   if (!inbuflen) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      MONGOC_ERROR_CLIENT_AUTHENTICATE,
                      "SASL Failure: no payload provided from server: %s",
                      sasl_errdetail (sasl->conn));
      return false;
   }

   status = sasl_decode64 (
      (char *) inbuf, inbuflen, (char *) outbuf, outbufmax, outbuflen);
   if (_mongoc_cyrus_is_failure (status, error)) {
      return false;
   }

   TRACE ("%s", "Running client_step");
   status = sasl_client_step (
      sasl->conn, (char *) outbuf, *outbuflen, &sasl->interact, &raw, &rawlen);
   TRACE ("%s sent a client step",
          status == SASL_OK ? "Successfully" : "UNSUCCESSFULLY");
   if (_mongoc_cyrus_is_failure (status, error)) {
      return false;
   }

   status = sasl_encode64 (raw, rawlen, (char *) outbuf, outbufmax, outbuflen);
   if (_mongoc_cyrus_is_failure (status, error)) {
      return false;
   }

   return true;
}
Ejemplo n.º 16
0
static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist)
{
        sasl_conn_t* saslconn;
        sasl_interact_t* interaction = NULL;
        const char* mech;
        const char* data = NULL;
        unsigned int len;
        char buf[HUGE_STRING];
        int rc, saslrc;

        if (mutt_sasl_client_new (conn, &saslconn) < 0)
                return SMTP_AUTH_FAIL;

        do {
                rc = sasl_client_start (saslconn, mechlist, &interaction, &data, &len, &mech);
                if (rc == SASL_INTERACT)
                        mutt_sasl_interact (interaction);
        }
        while (rc == SASL_INTERACT);

        if (rc != SASL_OK && rc != SASL_CONTINUE) {
                dprint (2, (debugfile, "smtp_auth_sasl: %s unavailable\n", mech));
                sasl_dispose (&saslconn);
                return SMTP_AUTH_UNAVAIL;
        }

        if (!option(OPTNOCURSES))
                mutt_message (_("Authenticating (%s)..."), mech);

        snprintf (buf, sizeof (buf), "AUTH %s", mech);
        if (len) {
                safe_strcat (buf, sizeof (buf), " ");
                if (sasl_encode64 (data, len, buf + mutt_strlen (buf),
                sizeof (buf) - mutt_strlen (buf), &len) != SASL_OK) {
                        dprint (1, (debugfile, "smtp_auth_sasl: error base64-encoding client response.\n"));
                        goto fail;
                }
        }
        safe_strcat (buf, sizeof (buf), "\r\n");

        do {
                if (mutt_socket_write (conn, buf) < 0)
                        goto fail;
                if ((rc = mutt_socket_readln (buf, sizeof (buf), conn)) < 0)
                        goto fail;
                if (smtp_code (buf, rc, &rc) < 0)
                        goto fail;

                if (rc != smtp_ready)
                        break;

                if (sasl_decode64 (buf+4, strlen (buf+4), buf, sizeof (buf), &len) != SASL_OK) {
                        dprint (1, (debugfile, "smtp_auth_sasl: error base64-decoding server response.\n"));
                        goto fail;
                }

                do {
                        saslrc = sasl_client_step (saslconn, buf, len, &interaction, &data, &len);
                        if (saslrc == SASL_INTERACT)
                                mutt_sasl_interact (interaction);
                }
                while (saslrc == SASL_INTERACT);

                if (len) {
                        if (sasl_encode64 (data, len, buf, sizeof (buf), &len) != SASL_OK) {
                                dprint (1, (debugfile, "smtp_auth_sasl: error base64-encoding client response.\n"));
                                goto fail;
                        }
                }
                strfcpy (buf + len, "\r\n", sizeof (buf) - len);
        } while (rc == smtp_ready && saslrc != SASL_FAIL);

        if (smtp_success (rc)) {
                mutt_sasl_setup_conn (conn, saslconn);
                return SMTP_AUTH_SUCCESS;
        }

        fail:
        sasl_dispose (&saslconn);
        return SMTP_AUTH_FAIL;
}
Ejemplo n.º 17
0
int mailesmtp_auth_sasl(mailsmtp * session, const char * auth_type,
    const char * server_fqdn,
    const char * local_ip_port,
    const char * remote_ip_port,
    const char * login, const char * auth_name,
    const char * password, const char * realm)
{
#ifdef USE_SASL
  int r;
  char command[SMTP_STRING_SIZE];
  sasl_callback_t sasl_callback[5];
  const char * sasl_out;
  unsigned sasl_out_len;
  const char * mechusing;
  sasl_secret_t * secret;
  int res;
  size_t len;
  char * encoded;
  unsigned int encoded_len;
  unsigned int max_encoded;

  sasl_callback[0].id = SASL_CB_GETREALM;
  sasl_callback[0].proc =  (int (*)(void)) sasl_getrealm;
  sasl_callback[0].context = session;
  sasl_callback[1].id = SASL_CB_USER;
  sasl_callback[1].proc =  (int (*)(void)) sasl_getsimple;
  sasl_callback[1].context = session;
  sasl_callback[2].id = SASL_CB_AUTHNAME;
  sasl_callback[2].proc =  (int (*)(void)) sasl_getsimple;
  sasl_callback[2].context = session;
  sasl_callback[3].id = SASL_CB_PASS;
  sasl_callback[3].proc =  (int (*)(void)) sasl_getsecret;
  sasl_callback[3].context = session;
  sasl_callback[4].id = SASL_CB_LIST_END;
  sasl_callback[4].proc =  NULL;
  sasl_callback[4].context = NULL;

  len = strlen(password);
  secret = malloc(sizeof(* secret) + len);
  if (secret == NULL) {
    res = MAILSMTP_ERROR_MEMORY;
    goto err;
  }
  secret->len = len;
  memcpy(secret->data, password, len + 1);

  session->smtp_sasl.sasl_server_fqdn = server_fqdn;
  session->smtp_sasl.sasl_login = login;
  session->smtp_sasl.sasl_auth_name = auth_name;
  session->smtp_sasl.sasl_password = password;
  session->smtp_sasl.sasl_realm = realm;
  session->smtp_sasl.sasl_secret = secret;

  /* init SASL */
  if (session->smtp_sasl.sasl_conn != NULL) {
    sasl_dispose((sasl_conn_t **) &session->smtp_sasl.sasl_conn);
    session->smtp_sasl.sasl_conn = NULL;
  }
  else {
    mailsasl_ref();
  }

  r = sasl_client_new("smtp", server_fqdn,
      local_ip_port, remote_ip_port, sasl_callback, 0,
      (sasl_conn_t **) &session->smtp_sasl.sasl_conn);
  if (r != SASL_OK) {
    res = MAILSMTP_ERROR_AUTH_LOGIN;
    goto free_secret;
  }

  r = sasl_client_start(session->smtp_sasl.sasl_conn,
      auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing);
  if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
    res = MAILSMTP_ERROR_AUTH_LOGIN;
    goto free_sasl_conn;
  }

  if (sasl_out_len != 0) {
    max_encoded = ((sasl_out_len + 2) / 3) * 4;
    encoded = malloc(max_encoded + 1);
    if (encoded == NULL) {
      res = MAILSMTP_ERROR_MEMORY;
      goto free_sasl_conn;
    }

    r = sasl_encode64(sasl_out, sasl_out_len,
        encoded, max_encoded + 1, &encoded_len);
    if (r != SASL_OK) {
      free(encoded);
      res = MAILSMTP_ERROR_MEMORY;
      goto free_sasl_conn;
    }

    snprintf(command, SMTP_STRING_SIZE, "AUTH %s %s\r\n", auth_type, encoded);

    free(encoded);
  }
  else {
    snprintf(command, SMTP_STRING_SIZE, "AUTH %s\r\n", auth_type);
  }

  r = send_command_private(session, command, 0);
  if (r == -1) {
    res = MAILSMTP_ERROR_STREAM;
    goto free_sasl_conn;
  }

  while (1) {
    r = read_response(session);
    switch (r) {
    case 220:
    case 235:
      res = MAILSMTP_NO_ERROR;
      goto free_sasl_conn;

    case 535:
      res = MAILSMTP_ERROR_AUTH_LOGIN;
      goto free_sasl_conn;

    case 553:
    case 554:
      res = MAILSMTP_ERROR_AUTH_AUTHENTICATION_FAILED;
      goto free_sasl_conn;

    case 334:
      {
        size_t response_len;
        char * decoded;
        unsigned int decoded_len;
        unsigned int max_decoded;
        char * p;

        p = strchr(session->response, '\r');
        if (p != NULL) {
          * p = '\0';
        }
        p = strchr(session->response, '\n');
        if (p != NULL) {
          * p = '\0';
        }

        response_len = strlen(session->response);
        max_decoded = response_len * 3 / 4;
        decoded = malloc(max_decoded + 1);
        if (decoded == NULL) {
          res = MAILSMTP_ERROR_MEMORY;
          goto free_sasl_conn;
        }

        r = sasl_decode64(session->response, response_len,
            decoded, max_decoded + 1, &decoded_len);

        if (r != SASL_OK) {
          free(decoded);
          res = MAILSMTP_ERROR_MEMORY;
          goto free_sasl_conn;
        }

        r = sasl_client_step(session->smtp_sasl.sasl_conn,
            decoded, decoded_len, NULL, &sasl_out, &sasl_out_len);

        free(decoded);

        if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
          res = MAILSMTP_ERROR_AUTH_LOGIN;
          goto free_sasl_conn;
        }

        max_encoded = ((sasl_out_len + 2) / 3) * 4;
        encoded = malloc(max_encoded + 1);
        if (encoded == NULL) {
          res = MAILSMTP_ERROR_MEMORY;
          goto free_sasl_conn;
        }

        r = sasl_encode64(sasl_out, sasl_out_len,
            encoded, max_encoded + 1, &encoded_len);
        if (r != SASL_OK) {
          free(encoded);
          res = MAILSMTP_ERROR_MEMORY;
          goto free_sasl_conn;
        }

        snprintf(command, SMTP_STRING_SIZE, "%s\r\n", encoded);
        r = send_command(session, command);

        free(encoded);

        if (r == -1) {
          res = MAILSMTP_ERROR_STREAM;
          goto free_sasl_conn;
        }
      }
      break;

    default:
      res = auth_map_errors(r);
      goto free_sasl_conn;
    }
  }

  res = MAILSMTP_NO_ERROR;

 free_sasl_conn:
  sasl_dispose((sasl_conn_t **) &session->smtp_sasl.sasl_conn);
  session->smtp_sasl.sasl_conn = NULL;
  mailsasl_unref();
 free_secret:
  free(session->smtp_sasl.sasl_secret);
  session->smtp_sasl.sasl_secret = NULL;
 err:
  return res;
#else
  return MAILSMTP_ERROR_NOT_IMPLEMENTED;
#endif
}
Ejemplo n.º 18
0
EXPORT_SYM const char *
hdfs_namenode_authenticate_full(struct hdfs_namenode *n, const char *username,
	const char *real_user)
{
	const char *error = NULL;
	struct hdfs_object *header;
	struct hdfs_heap_buf hbuf = { 0 };
	char *inh = NULL, preamble[12];
	size_t preamble_len;

	_lock(&n->nn_lock);
	ASSERT(!n->nn_authed);
	ASSERT(n->nn_sock != -1);

	memset(preamble, 0, sizeof(preamble));
	if (n->nn_proto == HDFS_NN_v1) {
		sprintf(preamble, "hrpc\x04%c",
		    (n->nn_kerb == HDFS_NO_KERB)? 0x50 : 0x51);
		preamble_len = 6;

		header = hdfs_authheader_new_ext(n->nn_proto, username,
		    real_user, HDFS_NO_KERB);
	} else if (n->nn_proto == HDFS_NN_v2) {
		/* HDFSv2 has used both version 7 (2.0.0-2.0.2) and 8 (2.0.3+). */
		sprintf(preamble, "hrpc%c%c", 8 /* XXX Configurable? */,
		    (n->nn_kerb == HDFS_NO_KERB)? 0x50 : 0x51);
		/* There is a zero at the end: */
		preamble_len = 7;

		header = hdfs_authheader_new_ext(n->nn_proto, username,
		    real_user, n->nn_kerb);
	} else if (n->nn_proto == HDFS_NN_v2_2) {
		memcpy(preamble, "hrpc\x09", 5);
		preamble[5] = 0;
		preamble[6] = (n->nn_kerb == HDFS_NO_KERB)? 0 : -33;
		preamble_len = 7;

		header = hdfs_authheader_new_ext(n->nn_proto, username,
		    real_user, n->nn_kerb);
		_authheader_set_clientid(header, n->nn_client_id);
	} else {
		ASSERT(false);
	}

	// Serialize the connection header object (I am speaking ClientProtocol
	// and this is my username)
	hdfs_object_serialize(&hbuf, header);
	hdfs_object_free(header);

	if (n->nn_kerb == HDFS_NO_KERB) {
		// Prefix the header object with the protocol preamble
		hbuf.buf = realloc(hbuf.buf, hbuf.size + preamble_len);
		ASSERT(hbuf.buf);
		memmove(hbuf.buf + preamble_len, hbuf.buf, hbuf.used);
		memcpy(hbuf.buf, preamble, preamble_len);
		hbuf.used += preamble_len;
		hbuf.size += preamble_len;
	} else {
		/*
		 * XXX This is probably totally wrong for HDFSv2+. They start
		 * using protobufs at this point to wrap the SASL packets.
		 *
		 * To be fair, it's probably broken for HDFSv1 too :). I need
		 * to find a kerberized HDFS to test against.
		 */
		int r;
		sasl_interact_t *interactions = NULL;
		const char *out, *mechusing;
		unsigned outlen;
		struct iovec iov[3];
		uint32_t inlen;
		const uint32_t SWITCH_TO_SIMPLE_AUTH = (uint32_t)-1;

		uint8_t in[4], zero[4] = { 0 };

		do {
			r = sasl_client_start(n->nn_sasl_ctx, "GSSAPI",
			    &interactions, &out, &outlen, &mechusing);

			if (r == SASL_INTERACT)
				_sasl_interacts(interactions);
		} while (r == SASL_INTERACT);

		if (r != SASL_CONTINUE) {
			error = sasl_errstring(r, NULL, NULL);
			goto out;
		}

		// Send prefix, first auth token
		_be32enc(in, outlen);
		iov[0].iov_base = preamble;
		iov[0].iov_len = preamble_len;
		iov[1].iov_base = in;
		iov[1].iov_len = 4;
		iov[2].iov_base = __DECONST(void *, out);
		iov[2].iov_len = outlen;

		error = _writev_all(n->nn_sock, iov, 3);
		if (error)
			goto out;

		do {
			// read success / error status
			error = _read_all(n->nn_sock, in, 4);
			if (error)
				goto out;

			if (memcmp(in, zero, 4)) {
				// error. exception will be next on the wire,
				// but let's skip it.
				error = "Got error from server, bailing";
				goto out;
			}

			// read token len
			error = _read_all(n->nn_sock, in, 4);
			if (error)
				goto out;
			inlen = _be32dec(in);

			if (inlen == SWITCH_TO_SIMPLE_AUTH) {
				if (n->nn_kerb == HDFS_REQUIRE_KERB) {
					error = "Server tried to drop kerberos but "
					    "client requires it";
					goto out;
				}
				goto send_header;
			}

			// read token
			if (inh)
				free(inh);
			inh = NULL;
			if (inlen > 0) {
				inh = malloc(inlen);
				ASSERT(inh);
				error = _read_all(n->nn_sock, inh, inlen);
				if (error)
					goto out;
			}

			out = NULL;
			outlen = 0;
			r = sasl_client_step(n->nn_sasl_ctx, inh,
			    inlen, &interactions, &out, &outlen);

			if (r == SASL_INTERACT)
				_sasl_interacts(interactions);

			if (r == SASL_CONTINUE ||
			    (r == SASL_OK && out != NULL)) {
				_be32enc(in, outlen);
				iov[0].iov_base = in;
				iov[0].iov_len = 4;
				iov[1].iov_base = __DECONST(void *, out);
				iov[1].iov_len = outlen;

				error = _writev_all(n->nn_sock, iov, 2);
				if (error)
					goto out;
			}
		} while (r == SASL_INTERACT || r == SASL_CONTINUE);

		if (r != SASL_OK) {
			error = sasl_errstring(r, NULL, NULL);
			goto out;
		}

		// sasl connection established
		n->nn_sasl_ssf = _getssf(n->nn_sasl_ctx);
send_header:
		if (n->nn_sasl_ssf > 0)
			_sasl_encode_inplace(n->nn_sasl_ctx, &hbuf);
	}

	// send auth header
	error = _write_all(n->nn_sock, hbuf.buf, hbuf.used);
	n->nn_authed = true;

out:
	if (inh)
		free(inh);
	_unlock(&n->nn_lock);
	free(hbuf.buf);

	return error;
}
Ejemplo n.º 19
0
/* imap_auth_sasl: Default authenticator if available. */
imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method)
{
  sasl_conn_t* saslconn;
  sasl_interact_t* interaction = NULL;
  int rc, irc;
  char buf[HUGE_STRING];
  const char* mech;
  const char *pc = NULL;
  unsigned int len, olen;
  unsigned char client_start;

  if (mutt_sasl_client_new (idata->conn, &saslconn) < 0)
  {
    dprint (1, (debugfile,
      "imap_auth_sasl: Error allocating SASL connection.\n"));
    return IMAP_AUTH_FAILURE;
  }

  rc = SASL_FAIL;

  /* If the user hasn't specified a method, use any available */
  if (!method)
  {
    method = idata->capstr;

    /* hack for SASL ANONYMOUS support:
     * 1. Fetch username. If it's "" or "anonymous" then
     * 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability
     * 3. if sasl_client_start fails, fall through... */

    if (mutt_account_getuser (&idata->conn->account))
      return IMAP_AUTH_FAILURE;

    if (mutt_bit_isset (idata->capabilities, AUTH_ANON) &&
	(!idata->conn->account.user[0] ||
	 !ascii_strncmp (idata->conn->account.user, "anonymous", 9)))
      rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, 
                              &mech);
  } else if (!ascii_strcasecmp ("login", method) &&
	!strstr (NONULL (idata->capstr), "AUTH=LOGIN"))
    /* do not use SASL login for regular IMAP login (#3556) */
    return IMAP_AUTH_UNAVAIL;
  
  if (rc != SASL_OK && rc != SASL_CONTINUE)
    do
    {
      rc = sasl_client_start (saslconn, method, &interaction,
        &pc, &olen, &mech);
      if (rc == SASL_INTERACT)
	mutt_sasl_interact (interaction);
    }
    while (rc == SASL_INTERACT);

  client_start = (olen > 0);

  if (rc != SASL_OK && rc != SASL_CONTINUE)
  {
    if (method)
      dprint (2, (debugfile, "imap_auth_sasl: %s unavailable\n", method));
    else
      dprint (1, (debugfile, "imap_auth_sasl: Failure starting authentication exchange. No shared mechanisms?\n"));
    /* SASL doesn't support LOGIN, so fall back */

    return IMAP_AUTH_UNAVAIL;
  }

  mutt_message (_("Authenticating (%s)..."), mech);

  snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech);
  if (mutt_bit_isset (idata->capabilities, SASL_IR) && client_start)
  {
    len = mutt_strlen (buf);
    buf[len++] = ' ';
    if (sasl_encode64 (pc, olen, buf + len, sizeof (buf) - len, &olen) != SASL_OK)
    {
      dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n"));
      goto bail;
    }
    client_start = olen = 0;
  }
  imap_cmd_start (idata, buf);
  irc = IMAP_CMD_CONTINUE;

  /* looping protocol */
  while (rc == SASL_CONTINUE || olen > 0)
  {
    do
      irc = imap_cmd_step (idata);
    while (irc == IMAP_CMD_CONTINUE);

    if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO)
      goto bail;

    if (irc == IMAP_CMD_RESPOND)
    {
      /* Exchange incorrectly returns +\r\n instead of + \r\n */
      if (idata->buf[1] == '\0')
      {
	buf[0] = '\0';
	len = 0;
      }
      else if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf,
			      LONG_STRING-1, &len) != SASL_OK)
      {
	dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n"));
	goto bail;
      }
    }

    /* client-start is only available with the SASL-IR extension, but
     * SASL 2.1 seems to want to use it regardless, at least for DIGEST
     * fast reauth. Override if the server sent an initial continuation */
    if (!client_start || buf[0])
    {
      do
      {
	rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen);
	if (rc == SASL_INTERACT)
	  mutt_sasl_interact (interaction);
      }
      while (rc == SASL_INTERACT);
    }
    else
      client_start = 0;

    /* send out response, or line break if none needed */
    if (olen)
    {
      if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK)
      {
	dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n"));
	goto bail;
      }
    }
    
    if (irc == IMAP_CMD_RESPOND)
    {
      strfcpy (buf + olen, "\r\n", sizeof (buf) - olen);
      mutt_socket_write (idata->conn, buf);
    }

    /* If SASL has errored out, send an abort string to the server */
    if (rc < 0)
    {
      mutt_socket_write (idata->conn, "*\r\n");
      dprint (1, (debugfile, "imap_auth_sasl: sasl_client_step error %d\n",rc));
    }
	  
    olen = 0;
  }

  while (irc != IMAP_CMD_OK)
    if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
      break;

  if (rc != SASL_OK)
    goto bail;

  if (imap_code (idata->buf))
  {
    mutt_sasl_setup_conn (idata->conn, saslconn);
    return IMAP_AUTH_SUCCESS;
  }

 bail:
  sasl_dispose (&saslconn);

  if (method)
  {
    dprint (2, (debugfile, "imap_auth_sasl: %s failed\n", method));
    return IMAP_AUTH_UNAVAIL;
  }

  mutt_error _("SASL authentication failed.");
  mutt_sleep(2);

  return IMAP_AUTH_FAILURE;
}
Ejemplo n.º 20
0
static int login(struct backend *s, const char *userid,
                 sasl_callback_t *cb, const char **status,
                 int noauth __attribute__((unused)))
{
    int r = 0;
    socklen_t addrsize;
    struct sockaddr_storage saddr_l, saddr_r;
    char remoteip[60], localip[60];
    static struct buf buf = BUF_INITIALIZER;
    sasl_security_properties_t secprops =
        { 0, 0xFF, PROT_BUFSIZE, 0, NULL, NULL }; /* default secprops */
    const char *mech_conf, *pass, *clientout = NULL;
    struct auth_scheme_t *scheme = NULL;
    unsigned need_tls = 0, tls_done = 0, auth_done = 0, clientoutlen;
    hdrcache_t hdrs = NULL;

    if (status) *status = NULL;

    /* set the IP addresses */
    addrsize = sizeof(struct sockaddr_storage);
    if (getpeername(s->sock, (struct sockaddr *) &saddr_r, &addrsize) ||
        iptostring((struct sockaddr *) &saddr_r, addrsize, remoteip, 60)) {
        if (status) *status = "Failed to get remote IP address";
        return SASL_FAIL;
    }

    addrsize = sizeof(struct sockaddr_storage);
    if (getsockname(s->sock, (struct sockaddr *) &saddr_l, &addrsize) ||
        iptostring((struct sockaddr *) &saddr_l, addrsize, localip, 60)) {
        if (status) *status = "Failed to get local IP address";
        return SASL_FAIL;
    }

    /* Create callbacks, if necessary */
    if (!cb) {
        buf_setmap(&buf, s->hostname, strcspn(s->hostname, "."));
        buf_appendcstr(&buf, "_password");
        pass = config_getoverflowstring(buf_cstring(&buf), NULL);
        if (!pass) pass = config_getstring(IMAPOPT_PROXY_PASSWORD);
        cb = mysasl_callbacks(NULL, /* userid */
                              config_getstring(IMAPOPT_PROXY_AUTHNAME),
                              config_getstring(IMAPOPT_PROXY_REALM),
                              pass);
        s->sasl_cb = cb;
    }

    /* Create SASL context */
    r = sasl_client_new(s->prot->sasl_service, s->hostname,
                        localip, remoteip, cb, SASL_USAGE_FLAGS, &s->saslconn);
    if (r != SASL_OK) goto done;

    r = sasl_setprop(s->saslconn, SASL_SEC_PROPS, &secprops);
    if (r != SASL_OK) goto done;

    /* Get SASL mechanism list.  We can force a particular
       mechanism using a <shorthost>_mechs option */
    buf_setmap(&buf, s->hostname, strcspn(s->hostname, "."));
    buf_appendcstr(&buf, "_mechs");
    if (!(mech_conf = config_getoverflowstring(buf_cstring(&buf), NULL))) {
        mech_conf = config_getstring(IMAPOPT_FORCE_SASL_CLIENT_MECH);
    }

    do {
        unsigned code;
        const char **hdr, *errstr, *serverin;
        char base64[BASE64_BUF_SIZE+1];
        unsigned int serverinlen;
        struct body_t resp_body;
#ifdef SASL_HTTP_REQUEST
        sasl_http_request_t httpreq = { "OPTIONS",      /* Method */
                                        "*",            /* URI */
                                        (u_char *) "",  /* Empty body */
                                        0,              /* Zero-length body */
                                        0 };            /* Persistent cxn? */
#endif

        /* Base64 encode any client response, if necessary */
        if (clientout && scheme && (scheme->flags & AUTH_BASE64)) {
            r = sasl_encode64(clientout, clientoutlen,
                              base64, BASE64_BUF_SIZE, &clientoutlen);
            if (r != SASL_OK) break;

            clientout = base64;
        }

        /* Send Authorization and/or Upgrade request to server */
        prot_puts(s->out, "OPTIONS * HTTP/1.1\r\n");
        prot_printf(s->out, "Host: %s\r\n", s->hostname);
        prot_printf(s->out, "User-Agent: %s\r\n", buf_cstring(&serverinfo));
        if (scheme) {
            prot_printf(s->out, "Authorization: %s %s\r\n",
                        scheme->name, clientout ? clientout : "");
            prot_printf(s->out, "Authorize-As: %s\r\n",
                        userid ? userid : "anonymous");
        }
        else {
            prot_printf(s->out, "Upgrade: %s\r\n", TLS_VERSION);
            if (need_tls) {
                prot_puts(s->out, "Connection: Upgrade\r\n");
                need_tls = 0;
            }
            prot_puts(s->out, "Authorization: \r\n");
        }
        prot_puts(s->out, "\r\n");
        prot_flush(s->out);

        serverin = clientout = NULL;
        serverinlen = clientoutlen = 0;

        /* Read response(s) from backend until final response or error */
        do {
            resp_body.flags = BODY_DISCARD;
            r = http_read_response(s, METH_OPTIONS, &code, NULL,
                                   &hdrs, &resp_body, &errstr);
            if (r) {
                if (status) *status = errstr;
                break;
            }

            if (code == 101) {  /* Switching Protocols */
                if (tls_done) {
                    r = HTTP_BAD_GATEWAY;
                    if (status) *status = "TLS already active";
                    break;
                }
                else if (backend_starttls(s, NULL, NULL, NULL)) {
                    r = HTTP_SERVER_ERROR;
                    if (status) *status = "Unable to start TLS";
                    break;
                }
                else tls_done = 1;
            }
        } while (code < 200);

        switch (code) {
        default: /* Failure */
            if (!r) {
                r = HTTP_BAD_GATEWAY;
                if (status) {
                    buf_reset(&buf);
                    buf_printf(&buf,
                               "Unexpected status code from backend: %u", code);
                    *status = buf_cstring(&buf);
                }
            }
            break;

        case 426: /* Upgrade Required */
            if (tls_done) {
                r = HTTP_BAD_GATEWAY;
                if (status) *status = "TLS already active";
            }
            else need_tls = 1;
            break;

        case 200: /* OK */
            if (scheme->recv_success &&
                (serverin = scheme->recv_success(hdrs))) {
                /* Process success data */
                serverinlen = strlen(serverin);
                goto challenge;
            }
            break;

        case 401: /* Unauthorized */
            if (auth_done) {
                r = SASL_BADAUTH;
                break;
            }

            if (!serverin) {
                int i = 0;

                hdr = spool_getheader(hdrs, "WWW-Authenticate");

                if (!scheme) {
                    unsigned avail_auth_schemes = 0;
                    const char *mech = NULL;
                    size_t len;

                    /* Compare authentication schemes offered in
                     * WWW-Authenticate header(s) to what we support */
                    buf_reset(&buf);
                    for (i = 0; hdr && hdr[i]; i++) {
                        len = strcspn(hdr[i], " ");

                        for (scheme = auth_schemes; scheme->name; scheme++) {
                            if (!strncmp(scheme->name, hdr[i], len) &&
                                !((scheme->flags & AUTH_NEED_PERSIST) &&
                                  (resp_body.flags & BODY_CLOSE))) {
                                /* Tag the scheme as available */
                                avail_auth_schemes |= (1 << scheme->idx);

                                /* Add SASL-based schemes to SASL mech list */
                                if (scheme->saslmech) {
                                    if (buf_len(&buf)) buf_putc(&buf, ' ');
                                    buf_appendcstr(&buf, scheme->saslmech);
                                }
                                break;
                            }
                        }
                    }

                    /* If we have a mech_conf, use it */
                    if (mech_conf && buf_len(&buf)) {
                        char *conf = xstrdup(mech_conf);
                        char *newmechlist =
                            intersect_mechlists(conf,
                                                (char *) buf_cstring(&buf));

                        if (newmechlist) {
                            buf_setcstr(&buf, newmechlist);
                            free(newmechlist);
                        }
                        else {
                            syslog(LOG_DEBUG, "%s did not offer %s",
                                   s->hostname, mech_conf);
                            buf_reset(&buf);
                        }
                        free(conf);
                    }

#ifdef SASL_HTTP_REQUEST
                    /* Set HTTP request as specified above (REQUIRED) */
                    httpreq.non_persist = (resp_body.flags & BODY_CLOSE);
                    sasl_setprop(s->saslconn, SASL_HTTP_REQUEST, &httpreq);
#endif

                    /* Try to start SASL exchange using available mechs */
                    r = sasl_client_start(s->saslconn, buf_cstring(&buf),
                                          NULL,         /* no prompts */
                                          NULL, NULL,   /* no initial resp */
                                          &mech);

                    if (mech) {
                        /* Find auth scheme associated with chosen SASL mech */
                        for (scheme = auth_schemes; scheme->name; scheme++) {
                            if (scheme->saslmech &&
                                !strcmp(scheme->saslmech, mech)) break;
                        }
                    }
                    else {
                        /* No matching SASL mechs - try Basic */
                        scheme = &auth_schemes[AUTH_BASIC];
                        if (!(avail_auth_schemes & (1 << scheme->idx))) {
                            need_tls = !tls_done;
                            break;  /* case 401 */
                        }
                    }

                    /* Find the associated WWW-Authenticate header */
                    for (i = 0; hdr && hdr[i]; i++) {
                        len = strcspn(hdr[i], " ");
                        if (!strncmp(scheme->name, hdr[i], len)) break;
                    }
                }

                /* Get server challenge, if any */
                if (hdr) {
                    const char *p = strchr(hdr[i], ' ');
                    serverin = p ? ++p : "";
                    serverinlen = strlen(serverin);
                }
            }

        challenge:
            if (serverin) {
                /* Perform the next step in the auth exchange */

                if (scheme->idx == AUTH_BASIC) {
                    /* Don't care about "realm" in server challenge */
                    const char *authid =
                        callback_getdata(s->saslconn, cb, SASL_CB_AUTHNAME);
                    pass = callback_getdata(s->saslconn, cb, SASL_CB_PASS);

                    buf_reset(&buf);
                    buf_printf(&buf, "%s:%s", authid, pass);
                    clientout = buf_cstring(&buf);
                    clientoutlen = buf_len(&buf);
                    auth_done = 1;
                }
                else {
                    /* Base64 decode any server challenge, if necessary */
                    if (serverin && (scheme->flags & AUTH_BASE64)) {
                        r = sasl_decode64(serverin, serverinlen,
                                          base64, BASE64_BUF_SIZE, &serverinlen);
                        if (r != SASL_OK) break;  /* case 401 */

                        serverin = base64;
                    }

                    /* SASL mech (Digest, Negotiate, NTLM) */
                    r = sasl_client_step(s->saslconn, serverin, serverinlen,
                                         NULL,          /* no prompts */
                                         &clientout, &clientoutlen);
                    if (r == SASL_OK) auth_done = 1;
                }
            }
            break;  /* case 401 */
        }

    } while (need_tls || clientout);

  done:
    if (hdrs) spool_free_hdrcache(hdrs);

    if (r && status && !*status) *status = sasl_errstring(r, NULL, NULL);

    return r;
}
Ejemplo n.º 21
0
int mailpop3_auth(mailpop3 * f, const char * auth_type,
    const char * server_fqdn,
    const char * local_ip_port,
    const char * remote_ip_port,
    const char * login, const char * auth_name,
    const char * password, const char * realm)
{
#ifdef USE_SASL
  int r;
  char command[POP3_STRING_SIZE];
  sasl_callback_t sasl_callback[5];
  const char * sasl_out;
  unsigned sasl_out_len;
  const char * mechusing;
  sasl_secret_t * secret;
  int res;
  size_t len;
  char * encoded;
  unsigned int encoded_len;
  unsigned int max_encoded;
  
  sasl_callback[0].id = SASL_CB_GETREALM;
  sasl_callback[0].proc =  sasl_getrealm;
  sasl_callback[0].context = f;
  sasl_callback[1].id = SASL_CB_USER;
  sasl_callback[1].proc =  sasl_getsimple;
  sasl_callback[1].context = f;
  sasl_callback[2].id = SASL_CB_AUTHNAME;
  sasl_callback[2].proc =  sasl_getsimple;
  sasl_callback[2].context = f; 
  sasl_callback[3].id = SASL_CB_PASS;
  sasl_callback[3].proc =  sasl_getsecret;
  sasl_callback[3].context = f;
  sasl_callback[4].id = SASL_CB_LIST_END;
  sasl_callback[4].proc =  NULL;
  sasl_callback[4].context = NULL;
  
  len = strlen(password);
  secret = malloc(sizeof(* secret) + len);
  if (secret == NULL) {
    res = MAILPOP3_ERROR_MEMORY;
    goto err;
  }
  secret->len = len;
  memcpy(secret->data, password, len + 1);
  
  f->pop3_sasl.sasl_server_fqdn = server_fqdn;
  f->pop3_sasl.sasl_login = login;
  f->pop3_sasl.sasl_auth_name = auth_name;
  f->pop3_sasl.sasl_password = password;
  f->pop3_sasl.sasl_realm = realm;
  f->pop3_sasl.sasl_secret = secret;
  
  /* init SASL */
  if (f->pop3_sasl.sasl_conn != NULL) {
    sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn);
    f->pop3_sasl.sasl_conn = NULL;
  }
  else {
    mailsasl_ref();
  }
  
  r = sasl_client_new("pop", server_fqdn,
      local_ip_port, remote_ip_port, sasl_callback, 0,
      (sasl_conn_t **) &f->pop3_sasl.sasl_conn);
  if (r != SASL_OK) {
    res = MAILPOP3_ERROR_BAD_USER;
    goto free_secret;
  }
  
  r = sasl_client_start(f->pop3_sasl.sasl_conn,
      auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing);
  if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
    res = MAILPOP3_ERROR_BAD_USER;
    goto free_sasl_conn;
  }
  
  snprintf(command, POP3_STRING_SIZE, "AUTH %s\r\n", auth_type);
  
  r = send_command(f, command);
  if (r == -1) {
    res = MAILPOP3_ERROR_STREAM;
    goto free_sasl_conn;
  }
  
  while (1) {
    char * response;
    
    response = read_line(f);
    
    r = parse_auth(f, response);
    switch (r) {
    case RESPONSE_OK:
      f->pop3_state = POP3_STATE_TRANSACTION;
      res = MAILPOP3_NO_ERROR;
      goto free_sasl_conn;
      
    case RESPONSE_ERR:
      res = MAILPOP3_ERROR_BAD_USER;
      goto free_sasl_conn;
    
    case RESPONSE_AUTH_CONT:
      {
        size_t response_len;
        char * decoded;
        unsigned int decoded_len;
        unsigned int max_decoded;
        int got_response;
        
        got_response = 1;
        if (* f->pop3_response == '\0')
          got_response = 0;
        
        if (got_response) {
          char * p;
          
          p = strchr(f->pop3_response, '\r');
          if (p != NULL) {
            * p = '\0';
          }
          p = strchr(f->pop3_response, '\n');
          if (p != NULL) {
            * p = '\0';
          }
          response_len = strlen(f->pop3_response);
          max_decoded = response_len * 3 / 4;
          decoded = malloc(max_decoded + 1);
          if (decoded == NULL) {
            res = MAILPOP3_ERROR_MEMORY;
            goto free_sasl_conn;
          }
          
          r = sasl_decode64(f->pop3_response, response_len,
              decoded, max_decoded + 1, &decoded_len);
          
          if (r != SASL_OK) {
            free(decoded);
            res = MAILPOP3_ERROR_MEMORY;
            goto free_sasl_conn;
          }
          
          r = sasl_client_step(f->pop3_sasl.sasl_conn,
              decoded, decoded_len, NULL, &sasl_out, &sasl_out_len);
          
          free(decoded);
          
          if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
            res = MAILPOP3_ERROR_BAD_USER;
            goto free_sasl_conn;
          }
        }
        
        max_encoded = ((sasl_out_len + 2) / 3) * 4;
        encoded = malloc(max_encoded + 1);
        if (encoded == NULL) {
          res = MAILPOP3_ERROR_MEMORY;
          goto free_sasl_conn;
        }
        
        r = sasl_encode64(sasl_out, sasl_out_len,
            encoded, max_encoded + 1, &encoded_len);
        if (r != SASL_OK) {
          free(encoded);
          res = MAILPOP3_ERROR_MEMORY;
          goto free_sasl_conn;
        }
        
        snprintf(command, POP3_STRING_SIZE, "%s\r\n", encoded);
        r = send_command(f, command);
        
        free(encoded);
        
        if (r == -1) {
          res = MAILPOP3_ERROR_STREAM;
          goto free_sasl_conn;
        }
      }
      break;
    }
  }

  f->pop3_state = POP3_STATE_TRANSACTION;
  res = MAILPOP3_NO_ERROR;
  
 free_sasl_conn:
  sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn);
  f->pop3_sasl.sasl_conn = NULL;
  mailsasl_unref();
 free_secret:
  free(f->pop3_sasl.sasl_secret);
  f->pop3_sasl.sasl_secret = NULL;
 err:
  return res;
#else
  return MAILPOP3_ERROR_BAD_USER;
#endif
}
Ejemplo n.º 22
0
int auth_sasl(char *mechlist, isieve_t *obj, const char **mechusing,
	      sasl_ssf_t *ssf, char **errstr)
{
  sasl_interact_t *client_interact=NULL;
  int saslresult=SASL_INTERACT;
  const char *out;
  unsigned int outlen;
  char *in;
  unsigned int inlen;
  char inbase64[2048];
  unsigned int inbase64len;

  imt_stat status = STAT_CONT;

  if(!mechlist || !obj || !mechusing) return -1;

  /* call sasl client start */
  while (saslresult==SASL_INTERACT)
  {
    saslresult=sasl_client_start(obj->conn, mechlist,
				 &client_interact,
				 &out, &outlen,
				 mechusing);
    if (saslresult==SASL_INTERACT)
      fillin_interactions(client_interact); /* fill in prompts */      
  }

  if ((saslresult!=SASL_OK) && (saslresult!=SASL_CONTINUE)) return saslresult;

  if (out!=NULL)
  {
    prot_printf(obj->pout,"AUTHENTICATE \"%s\" ",*mechusing);

    sasl_encode64(out, outlen,
		  inbase64, sizeof(inbase64), &inbase64len);

    prot_printf(obj->pout, "{%d+}\r\n",inbase64len);
    prot_write(obj->pout,inbase64,inbase64len);
    prot_printf(obj->pout,"\r\n");
  } else {
    prot_printf(obj->pout,"AUTHENTICATE \"%s\"\r\n",*mechusing);
  }
  prot_flush(obj->pout);

  inlen = 0;

  /* get reply */
  status=getauthline(obj,&in,&inlen, errstr);

  while (status==STAT_CONT)
  {
    saslresult=SASL_INTERACT;
    while (saslresult==SASL_INTERACT)
    {
      saslresult=sasl_client_step(obj->conn,
				  in,
				  inlen,
				  &client_interact,
				  &out,&outlen);

      if (saslresult==SASL_INTERACT)
	fillin_interactions(client_interact); /* fill in prompts */
    }

    /* check if sasl suceeded */
    if (saslresult<SASL_OK)
    {
	/* send cancel notice */
	prot_printf(obj->pout, "*\r\n");
	prot_flush(obj->pout);

	/* eat the auth line that confirms that we canceled */
	if(getauthline(obj,&in,&inlen,errstr) != STAT_NO) {
	    *errstr = xstrdup("protocol error");
	} else {
	    *errstr = xstrdup(sasl_errstring(saslresult,NULL,NULL));
	}
	
	return saslresult;
    }

    /* send to server */

    sasl_encode64(out, outlen,
		  inbase64, sizeof(inbase64), &inbase64len);

    prot_printf(obj->pout, "{%d+}\r\n",inbase64len);
    prot_flush(obj->pout);
    prot_write(obj->pout,inbase64,inbase64len);
    prot_flush(obj->pout);
    prot_printf(obj->pout,"\r\n");
    prot_flush(obj->pout);

    /* get reply */
    status=getauthline(obj,&in,&inlen, errstr);
  }

  if(status == STAT_OK) {
      /* do we have a last send? */
      if(in) {
	  saslresult=sasl_client_step(obj->conn,
				      in,
				      inlen,
				      &client_interact,
				      &out, &outlen);
	  
	  if(saslresult != SASL_OK)
	      return -1;
      }

      if (ssf) {
	  const void *ssfp;

	  saslresult = sasl_getprop(obj->conn, SASL_SSF, &ssfp);
	  if(saslresult != SASL_OK) return -1;

	  *ssf = *((sasl_ssf_t *) ssfp);
      }

      /* turn on layer if need be */
      prot_setsasl(obj->pin,  obj->conn);
      prot_setsasl(obj->pout, obj->conn);

      /* There wasn't a last send, or we are already OK */
      return 0;
  } else {
      /* Error */
      return -1;
  }
}