예제 #1
0
static int do_referral(isieve_t *obj, char *refer_to)
{
    int ret;
    struct servent *serv;
    isieve_t *obj_new;
    char *mechlist;
    int port;
    char *errstr = NULL;
    const char *mtried;
    const char *scheme = "sieve://";
    char *host, *p;
    sasl_callback_t *callbacks;
    sasl_ssf_t ssf;

    /* check scheme */
    if (strncasecmp(refer_to, scheme, strlen(scheme)))
	return STAT_NO;

    /* get host */
    if ((host = strrchr(refer_to, '@'))) {
	char *authid, *userid;
	int n;

	*host++ = '\0';

	/* get authid - make a copy so it persists for the callbacks */
	authid = obj->refer_authinfo = xstrdup(refer_to + strlen(scheme));

	/* get userid */
	if ((userid = strrchr(authid, ';')))
	    *userid++ = '\0';

	/* count the callbacks */
	for (n = 0; obj->callbacks[n++].id != SASL_CB_LIST_END;);

	/* copy the callbacks, substituting some of our own */
	callbacks = obj->refer_callbacks = xmalloc(n*sizeof(sasl_callback_t));

	while (--n >= 0) {
	    callbacks[n].id = obj->callbacks[n].id;

	    switch (callbacks[n].id) {
	    case SASL_CB_USER:
		callbacks[n].proc = (int (*)(void))&refer_simple_cb;
		callbacks[n].context = userid ? userid : authid;
		break;
	    case SASL_CB_AUTHNAME:
		callbacks[n].proc = (int (*)(void))&refer_simple_cb;
		callbacks[n].context = authid;
		break;
	    default:
		callbacks[n].proc = obj->callbacks[n].proc;
		callbacks[n].context = obj->callbacks[n].context;
		break;
	    }
	}
    }
    else {
	host = refer_to + strlen(scheme);
	callbacks = obj->callbacks;
    }

    /* get port */
    p = host;
    if (*host == '[') {
	if ((p = strrchr(host + 1, ']')) != NULL) {
	    *p++ = '\0';
	    host++;			/* skip first bracket */
        } else
	    p = host;
    }
    if ((p = strchr(p, ':'))) {
	*p++ = '\0';
	port = atoi(p);
    } else {
	serv = getservbyname("sieve", "tcp");
	if (serv == NULL) {
	    port = 4190;
	} else {
	    port = ntohs(serv->s_port);
	}
    }

    ret = init_net(host, port, &obj_new);
    if(ret) return STAT_NO;

    /* Start up SASL */
    ret = init_sasl(obj_new, 128, callbacks);
    if(ret) return STAT_NO;

    /* Authenticate */
    mechlist = read_capability(obj_new);

    do {
	mtried = NULL;
	ret = auth_sasl(mechlist, obj_new, &mtried, &ssf, &errstr);
	if (errstr) {
	    free(errstr);
	    errstr = NULL;
	}
	if(ret) init_sasl(obj_new, 128, callbacks);

	if(mtried) {
	    char *newlist = (char*) xmalloc(strlen(mechlist)+1);
	    char *mtr = xstrdup(mtried);
	    char *tmp;

	    ucase(mtr);
	    tmp = strstr(mechlist,mtr);
	    if (tmp) {
		strcpy(newlist, mechlist);
		tmp++;
		tmp = strchr(tmp, ' ');
		if (tmp) {
		    strcat(newlist,tmp);
		}
	    }
	    
	    free(mtr);
	    free(mechlist);
	    mechlist = newlist;
	}
    } while(ret && mtried);

    /* xxx leak? */
    if(ret) return STAT_NO;

    if (ssf) {
        /* SASL security layer negotiated --
	   check if SASL mech list changed */
        if (detect_mitm(obj_new, mechlist)) {
	    free(mechlist);
	    return STAT_NO;
	}
    }
    free(mechlist);

    /* free old isieve_t */
    sieve_dispose(obj);

    /* Copy new isieve_t into memory used by old object */
    memcpy(obj,obj_new,sizeof(isieve_t));
    free(obj_new);

    /* Destroy the string that was allocated to save the destination server */
    free(refer_to);

    return STAT_OK;
}
예제 #2
0
int auth_sasl_ex(const char *method,
		 const char *initresponse,
		 const char *externalauth,
		 char *(*callback_func)(const char *, void *),
		 void *callback_arg,
		 char **authtype_ptr,		/* Returned - AUTHTYPE */
		 char **authdata_ptr)
{
	char	*uid;
	int n;

	if (strcmp(method, "EXTERNAL"))
		return auth_sasl(method, initresponse, callback_func,
				 callback_arg,
				 authtype_ptr,
				 authdata_ptr);

	if (!externalauth || !*externalauth)
		return AUTHSASL_ERROR;

	if (initresponse && !*initresponse)
		initresponse=NULL;

	if (initresponse && strcmp(initresponse, externalauth))
		return AUTHSASL_ERROR;

	if (!initresponse)
	{
		uid=callback_func("", callback_arg);

		if (*uid == '*')
		{
			free(uid);
			return (AUTHSASL_ABORTED);
		}

		n=authsasl_frombase64(uid);

		if (n < 0)
		{
			free(uid);
			return AUTHSASL_ABORTED;
		}
		uid[n]=0;

		if (uid[0])
		{
			free(uid);
			return AUTHSASL_ABORTED;
		}
		free(uid);
	}

	if ((*authtype_ptr=strdup("EXTERNAL")) == NULL)
		return AUTHSASL_ABORTED;

	if ((*authdata_ptr=strdup(externalauth)) == NULL)
	{
		free(authtype_ptr);
		return AUTHSASL_ABORTED;
	}

	return 0;
}