Home | History | Annotate | Line # | Download | only in src
      1 /* $NetBSD: mech.c,v 1.8 2025/12/16 12:03:39 nia Exp $ */
      2 
      3 /* Copyright (c) 2010 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Mateusz Kocielski.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. Neither the name of The NetBSD Foundation nor the names of its
     18  *    contributors may be used to endorse or promote products derived
     19  *    from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.	IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 #include <sys/cdefs.h>
     34 __RCSID("$NetBSD: mech.c,v 1.8 2025/12/16 12:03:39 nia Exp $");
     35 
     36 #include <sys/queue.h>
     37 
     38 #include <saslc.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 
     43 #include "dict.h"
     44 #include "error.h"
     45 #include "mech.h"
     46 #include "msg.h"
     47 #include "saslc_private.h"
     48 
     49 /* mechanisms */
     50 __weakref_visible const saslc__mech_t weak_saslc__mech_anonymous
     51     __weak_reference(saslc__mech_anonymous);
     52 __weakref_visible const saslc__mech_t weak_saslc__mech_crammd5
     53     __weak_reference(saslc__mech_crammd5);
     54 __weakref_visible const saslc__mech_t weak_saslc__mech_digestmd5
     55     __weak_reference(saslc__mech_digestmd5);
     56 __weakref_visible const saslc__mech_t weak_saslc__mech_external
     57     __weak_reference(saslc__mech_external);
     58 __weakref_visible const saslc__mech_t weak_saslc__mech_gssapi
     59     __weak_reference(saslc__mech_gssapi);
     60 __weakref_visible const saslc__mech_t weak_saslc__mech_login
     61     __weak_reference(saslc__mech_login);
     62 __weakref_visible const saslc__mech_t weak_saslc__mech_plain
     63     __weak_reference(saslc__mech_plain);
     64 
     65 static const saslc__mech_t *saslc__mechanisms[] = {
     66 	&weak_saslc__mech_anonymous,
     67 	&weak_saslc__mech_crammd5,
     68 	&weak_saslc__mech_digestmd5,
     69 	&weak_saslc__mech_external,
     70 	&weak_saslc__mech_gssapi,
     71 	&weak_saslc__mech_login,
     72 	&weak_saslc__mech_plain,
     73 };
     74 
     75 /*
     76  * This table is used by the inline functions in mech.h, which are
     77  * used in mech_digestmd5.c and mech_gssapi.c.
     78  *
     79  * NB: This is indexed by saslc__mech_sess_qop_t values and must be
     80  * NULL terminated for use in saslc__list_flags().
     81  */
     82 const named_flag_t saslc__mech_qop_tbl[] = {
     83 	{ "auth",	F_QOP_NONE },
     84 	{ "auth-int",	F_QOP_INT },
     85 	{ "auth-conf",	F_QOP_CONF },
     86 	{ NULL,		0 }
     87 };
     88 
     89 /**
     90  * @brief creates a list of supported mechanisms and their resources.
     91  * @param ctx context
     92  * @return pointer to head of the list, NULL if allocation failed
     93  */
     94 saslc__mech_list_t *
     95 saslc__mech_list_create(saslc_t *ctx)
     96 {
     97 	saslc__mech_list_t *head = NULL;
     98 	saslc__mech_list_node_t *node = NULL;
     99 	size_t i;
    100 
    101 	if ((head = calloc(1, sizeof(*head))) == NULL) {
    102 		saslc__error_set_errno(ERR(ctx), ERROR_NOMEM);
    103 		return NULL;
    104 	}
    105 	for (i = 0; i < __arraycount(saslc__mechanisms); i++) {
    106 		if (saslc__mechanisms[i] == NULL)
    107 			continue;
    108 		if ((node = calloc(1, sizeof(*node))) == NULL)
    109 			goto error;
    110 
    111 		if ((node->prop = saslc__dict_create()) == NULL) {
    112 			free(node);
    113 			goto error;
    114 		}
    115 
    116 		node->mech = saslc__mechanisms[i];
    117 		LIST_INSERT_HEAD(head, node, nodes);
    118 	}
    119 	return head;
    120 
    121  error:
    122 	saslc__error_set_errno(ERR(ctx), ERROR_NOMEM);
    123 	saslc__mech_list_destroy(head);
    124 	return NULL;
    125 }
    126 
    127 /**
    128  * @brief gets mechanism from the list using name
    129  * @param list mechanisms list
    130  * @param mech_name mechanism name
    131  * @return pointer to the mechanism, NULL if mechanism was not found
    132  */
    133 saslc__mech_list_node_t *
    134 saslc__mech_list_get(saslc__mech_list_t *list, const char *mech_name)
    135 {
    136 	saslc__mech_list_node_t *node;
    137 
    138 	LIST_FOREACH(node, list, nodes) {
    139 		if (strcasecmp(node->mech->name, mech_name) == 0)
    140 			return node;
    141 	}
    142 	return NULL;
    143 }
    144 
    145 /**
    146  * @brief destroys and deallocates mechanism list
    147  * @param list mechanisms list
    148  */
    149 void
    150 saslc__mech_list_destroy(saslc__mech_list_t *list)
    151 {
    152 	saslc__mech_list_node_t *node;
    153 
    154 	while (!LIST_EMPTY(list)) {
    155 		node = LIST_FIRST(list);
    156 		LIST_REMOVE(node, nodes);
    157 		saslc__dict_destroy(node->prop);
    158 		free(node);
    159 	}
    160 	free(list);
    161 }
    162 
    163 /**
    164  * @brief doing copy of the session property, on error sets
    165  * error message for the session. Copied data is located in *out and *outlen
    166  * @param sess sasl session
    167  * @param out out buffer for the session property copy
    168  * @param outlen length of the session property copy
    169  * @param name name of the property
    170  * @param error_msg error messages set on failure
    171  * @return MECH_OK - on success
    172  * MECH_ERROR - on failure
    173  */
    174 int
    175 saslc__mech_strdup(saslc_sess_t *sess, char **out, size_t *outlen,
    176     const char *name, const char *error_msg)
    177 {
    178 	const char *value; /* property value */
    179 
    180 	/* get value */
    181 	if ((value = saslc_sess_getprop(sess, name)) == NULL) {
    182 		saslc__error_set(ERR(sess), ERROR_MECH, error_msg);
    183 		return MECH_ERROR;
    184 	}
    185 	saslc__msg_dbg("saslc__mech_strdup: value='%s'\n", value);
    186 
    187 	/* copy value */
    188 	if ((*out = strdup(value)) == NULL) {
    189 		saslc__error_set_errno(ERR(sess), ERROR_NOMEM);
    190 		return MECH_ERROR;
    191 	}
    192 	if (outlen != NULL)
    193 		*outlen = strlen(value);
    194 
    195 	return MECH_OK;
    196 }
    197 
    198 /**
    199  * @brief generic session create function, this
    200  * function is suitable for the most mechanisms.
    201  * @return 0 on success, -1 on failure
    202  */
    203 int
    204 saslc__mech_generic_create(saslc_sess_t *sess)
    205 {
    206 	saslc__mech_sess_t *ms;
    207 
    208 	if ((ms = calloc(1, sizeof(*ms))) == NULL) {
    209 		saslc__error_set(ERR(sess), ERROR_NOMEM, NULL);
    210 		return -1;
    211 	}
    212 	sess->mech_sess = ms;
    213 	return 0;
    214 }
    215 
    216 /**
    217  * @brief generic session destroy function, this
    218  * function is suitable for the most mechanisms.
    219  * @return function always returns 0
    220  */
    221 int
    222 saslc__mech_generic_destroy(saslc_sess_t *sess)
    223 {
    224 
    225 	free(sess->mech_sess);
    226 	sess->mech_sess = NULL;
    227 	return 0;
    228 }
    229