src/server/safs/auth.c

Sun, 15 Sep 2024 09:47:36 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 15 Sep 2024 09:47:36 +0200
changeset 558
0e79e17c70e2
parent 467
4d038bc6f86e
permissions
-rw-r--r--

improve sessionhandler trace logging

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
 *
 * THE BSD LICENSE
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the  nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <strings.h>

#include "../public/auth.h"
#include "../daemon/config.h"
#include "../daemon/session.h"

#include "auth.h"


/* ------------------------------ _uudecode ------------------------------- */

static const unsigned char pr2six[256] = {
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
    52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
    10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
    28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64
};

char *_uudecode(pool_handle_t *pool, char *bufcoded) {
    register char *bufin = bufcoded;
    register unsigned char *bufout;
    register int nprbytes;
    unsigned char *bufplain;
    int nbytesdecoded;

    /* Find the length */
    while(pr2six[(int)*(bufin++)] <= 63);
    nprbytes = bufin - bufcoded - 1;
    nbytesdecoded = ((nprbytes+3)/4) * 3;

    bufout = pool_malloc(pool, nbytesdecoded + 1);
    bufplain = bufout;

    bufin = bufcoded;

    while (nprbytes > 0) {
        *(bufout++) = (unsigned char)
            (pr2six[(int)(*bufin)] << 2 | pr2six[(int)bufin[1]] >> 4);
        *(bufout++) = (unsigned char)
            (pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2);
        *(bufout++) = (unsigned char)
            (pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]);
        bufin += 4;
        nprbytes -= 4;
    }

    if(nprbytes & 03) {
        if(pr2six[(int)bufin[-2]] > 63)
            nbytesdecoded -= 2;
        else
            nbytesdecoded -= 1;
    }
    bufplain[nbytesdecoded] = '\0';

    return (char *)bufplain;
}

int basicauth_getuser(Session *sn, Request *rq, char **user, char **pw) {
    char *auth = NULL;
    *user = NULL;
    *pw = NULL;
    char *u;
    char *p;
    
    if(request_header("authorization", &auth, sn, rq) == REQ_ABORTED) {
        return REQ_ABORTED;
    }
    
    if(!auth) {
        return REQ_NOACTION;
    }
    
    /* Skip leading whitespace */
    while(*auth && (*auth == ' '))
        ++auth;
    if(!(*auth)) {
        protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL);
        return REQ_ABORTED;
    }

    /* Verify correct type */
    if((strlen(auth) < 6) || strncasecmp(auth, "basic ", 6)) {
        return REQ_NOACTION;
    }

    /* Skip whitespace */
    auth += 6;
    while(*auth && (*auth == ' ')) {
        ++auth;
    }

    if(!*auth) {
        return REQ_NOACTION;
    }
    
    /* Uuencoded user:password now */
    if(!(u = _uudecode(sn->pool, auth))) {
        return REQ_NOACTION;
    }

    if(!(p = strchr(u, ':'))) {
        pool_free(sn->pool, u);
        return REQ_NOACTION;
    }
    *p++ = '\0';
    
    *user = u;
    *pw = p;
    
    return REQ_PROCEED;
}

/* ------------------------------ auth_basic ------------------------------ */

int auth_basic(pblock *param, Session *sn, Request *rq)
{
    char *pwfile, *grpfile, *type, *auth, *user, *pw;
    char *pwfn, *grpfn;
    pblock *npb;
    pb_param *pp;
    int ret;

    /* Although this is authorization (which is not cacheable) the
     * check is not actually done until we call require-auth.  So
     * this part is cacheable; require-auth can be cacheable if the
     * user has limited the auth to only affect a certain set of
     * paths.
     */
    rq->directive_is_cacheable = 1;

    type = pblock_findval("auth-type", param);
    pwfile = pblock_findval("userdb", param);
    grpfile = pblock_findval("groupdb", param);
    pwfn = pblock_findval("userfn", param);
    grpfn = pblock_findval("groupfn", param);

    if((!type) || (!pwfile) || (!pwfn) || (grpfile && !grpfn)) {
        log_ereport(LOG_MISCONFIG, "basic-auth: missing parameter");
        protocol_status(sn, rq, PROTOCOL_SERVER_ERROR, NULL);
        return REQ_ABORTED;
    }

    ret = basicauth_getuser(sn, rq, &user, &pw);
    if(ret != REQ_PROCEED) {
        return ret;
    }

    npb = pblock_create(4);
    pblock_nvinsert("user", user, npb);
    pblock_nvinsert("pw", pw, npb);
    pblock_nvinsert("userdb", pwfile, npb);
    if(grpfile)
        pblock_nvinsert("groupdb", grpfile, npb);
    pblock_nvinsert("fn", pwfn, npb);

    if ((ret = func_exec(npb, sn, rq)) != REQ_PROCEED)
    {
        goto bye;
    }

    pblock_nvinsert("auth-type", "basic", rq->vars);
    pblock_nvinsert("auth-user", user, rq->vars);
    pblock_nvinsert("auth-db", pwfile, rq->vars);
#if defined(XP_WIN32) || defined(MCC_ADMSERV)
    /* MLM - the admin server needs this password information,
     *       so I'm putting it back   */
    pblock_nvinsert("auth-password", pw, rq->vars);
#endif /* XP_WIN32 */

    if(grpfile) {
        pblock_nvinsert("groupdb", grpfile, npb);
        pp = pblock_find("fn", npb);
        free(pp->value);
        pp->value = strdup(grpfn);

        if( (ret = func_exec(npb, sn, rq)) != REQ_PROCEED )
            goto bye;
    }
    ret = REQ_PROCEED;
  bye:
    pblock_free(npb);
    return ret;
}

int auth_db(pblock *param, Session *sn, Request *rq) {
    char *db;
    char *user;
    char *pw; 

    db = pblock_findval("db", param);

    if(!db) {
        // TODO: log error
        log_ereport(LOG_MISCONFIG, "basic-auth: missing db parameter");
        protocol_status(sn, rq, PROTOCOL_SERVER_ERROR, NULL);
        return REQ_ABORTED;
    }

    int ret = basicauth_getuser(sn, rq, &user, &pw);
    if(ret != REQ_PROCEED) {
        return ret;
    }

    // get auth db
    ServerConfiguration *config = session_get_config(sn);
    AuthDB *authdb = cxMapGet(config->authdbs, cx_hash_key_str(db));
    
    User *auth_user = authdb->get_user(authdb, sn, rq, user);
    if(auth_user && !auth_user->verify_password(auth_user, pw)) {
        fprintf(stderr, "authdb user not authenticated: %s\n", user);
        free(user);
        auth_user->free(auth_user);
        return REQ_NOACTION;
    }
    

    pblock_nvinsert("auth-type", "basic", rq->vars);
    pblock_nvinsert("auth-user", user, rq->vars);
    pblock_nvinsert("auth-db", db, rq->vars);
    
    if(auth_user) {
        auth_user->free(auth_user);
    }
    
    return REQ_PROCEED;
}

mercurial