Home | History | Annotate | Line # | Download | only in xsasl
      1 /*	$NetBSD: xsasl_saslc_client.c,v 1.2 2021/02/05 21:45:24 joerg Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	xsasl_saslc_client 3
      6 /* SUMMARY
      7 /*	saslc SASL client-side plug-in
      8 /* SYNOPSIS
      9 /*	#include <xsasl_saslc_client.h>
     10 /*
     11 /*	XSASL_CLIENT_IMPL *xsasl_saslc_client_init(client_type, path_info)
     12 /*	const char *client_type;
     13 /* DESCRIPTION
     14 /*	This module implements the saslc SASL client-side authentication
     15 /*	plug-in.
     16 /*
     17 /*	xsasl_saslc_client_init() initializes the saslc SASL library and
     18 /*	returns an implementation handle that can be used to generate
     19 /*	SASL client instances.
     20 /*
     21 /*	Arguments:
     22 /* .IP client_type
     23 /*	The plug-in SASL client type (saslc). This argument is
     24 /*	ignored, but it could be used when one implementation
     25 /*	provides multiple variants.
     26 /* .IP path_info
     27 /*	Implementation-specific information to specify the location
     28 /*	of a configuration file, rendez-vous point, etc. This
     29 /*	information is ignored by the saslc SASL client plug-in.
     30 /* DIAGNOSTICS
     31 /*	Fatal: out of memory.
     32 /*
     33 /*	Panic: interface violation.
     34 /*
     35 /*	Other: the routines log a warning and return an error result
     36 /*	as specified in xsasl_client(3).
     37 /* SEE ALSO
     38 /*	xsasl_client(3) Client API
     39 /* LICENSE
     40 /* .ad
     41 /* .fi
     42 /*	The Secure Mailer license must be distributed with this software.
     43 /* AUTHOR(S)
     44 /*	Original author:
     45 /*	Till Franke
     46 /*	SuSE Rhein/Main AG
     47 /*	65760 Eschborn, Germany
     48 /*
     49 /*	Adopted by:
     50 /*	Wietse Venema
     51 /*	IBM T.J. Watson Research
     52 /*	P.O. Box 704
     53 /*	Yorktown Heights, NY 10598, USA
     54 /*--*/
     55 
     56 #if defined(USE_SASL_AUTH) && defined(USE_SASLC_SASL)
     57 
     58  /*
     59   * System headers.
     60   */
     61 #include <errno.h>
     62 #include <saslc.h>
     63 #include <stdlib.h>
     64 #include <string.h>
     65 
     66 #include "sys_defs.h"
     67 
     68  /*
     69   * Utility library
     70   */
     71 #include "msg.h"
     72 #include "mymalloc.h"
     73 #include "stringops.h"
     74 
     75  /*
     76   * Global library
     77   */
     78 #include "mail_params.h"
     79 
     80  /*
     81   * Application-specific
     82   */
     83 #include "xsasl.h"
     84 #include "xsasl_saslc.h"
     85 
     86 
     87 #define XSASL_SASLC_APPNAME	"postfix"  /* The config files are in
     88 					      /etc/saslc.d/<appname>/ */
     89 typedef struct {
     90 	XSASL_CLIENT_IMPL xsasl;	/* generic members, must be first */
     91 	saslc_t *saslc;			/* saslc context */
     92 } XSASL_SASLC_CLIENT_IMPL;
     93 
     94 typedef struct {
     95 	XSASL_CLIENT xsasl;		/* generic members, must be first */
     96 	saslc_t *saslc;			/* saslc context */
     97 	saslc_sess_t *sess;		/* session context */
     98 	const char *service;		/* service (smtp) */
     99 	const char *hostname;		/* server host name */
    100 	const char *sec_opts;		/* security options */
    101 } XSASL_SASLC_CLIENT;
    102 
    103 static XSASL_CLIENT *xsasl_saslc_client_create(XSASL_CLIENT_IMPL *,
    104     XSASL_CLIENT_CREATE_ARGS *);
    105 static int xsasl_saslc_client_first(XSASL_CLIENT *, const char *,
    106     const char *, const char *, const char **, VSTRING *);
    107 static int xsasl_saslc_client_next(XSASL_CLIENT *, const char *,
    108     VSTRING *);
    109 static void xsasl_saslc_client_done(XSASL_CLIENT_IMPL *);
    110 static void xsasl_saslc_client_free(XSASL_CLIENT *);
    111 
    112 static void
    113 setprop(saslc_sess_t *sess, int overwrite, const char *key, const char *value)
    114 {
    115 
    116 	if (overwrite != 0 ||
    117 	    saslc_sess_getprop(sess, key) == NULL)
    118 		saslc_sess_setprop(sess, key, value);
    119 }
    120 
    121 /*
    122  * Run authentication protocol: first step.
    123  */
    124 static int
    125 xsasl_saslc_client_first(
    126 	XSASL_CLIENT *xp,
    127 	const char *mechanism_list,
    128 	const char *username,
    129 	const char *password,
    130 	const char **mechanism,
    131 	VSTRING *init_resp)
    132 {
    133 	XSASL_SASLC_CLIENT *client = (XSASL_SASLC_CLIENT *)xp;
    134 	const char *mech;
    135 	void *out;
    136 	size_t outlen;
    137 	int rv;
    138 
    139 	if (msg_verbose) {
    140 		msg_info("%s: mechanism_list='%s'", __func__, mechanism_list);
    141 		msg_info("%s: username='%s'", __func__, username);
    142 /*		msg_info("%s: password='%s'", __func__, password); */
    143 	}
    144 	client->sess = saslc_sess_init(client->saslc, mechanism_list,
    145 					client->sec_opts);
    146 	if (client->sess == NULL) {
    147 		msg_info("%s: saslc_sess_init failed", __func__);
    148 		return XSASL_AUTH_FAIL;
    149 	}
    150 	mech = saslc_sess_getmech(client->sess);
    151 	if (mechanism)
    152 		*mechanism = mech;
    153 	if (msg_verbose)
    154 		msg_info("%s: mechanism='%s'", __func__, mech);
    155 
    156 	setprop(client->sess, 0, SASLC_PROP_AUTHCID,  username);
    157 	setprop(client->sess, 1, SASLC_PROP_PASSWD,   password);
    158 	setprop(client->sess, 1, SASLC_PROP_SERVICE,  client->service);
    159 	setprop(client->sess, 1, SASLC_PROP_HOSTNAME, client->hostname);
    160 	setprop(client->sess, 1, SASLC_PROP_BASE64IO, "true");
    161 	setprop(client->sess, 0, SASLC_PROP_QOPMASK,  "auth");
    162 
    163 	if ((rv = saslc_sess_cont(client->sess, NULL, 0, &out, &outlen))
    164 	    == -1) {
    165 		msg_info("%s: saslc_sess_encode='%s'", __func__,
    166 		    saslc_sess_strerror(client->sess));
    167 		return XSASL_AUTH_FAIL;
    168 	}
    169 	vstring_strcpy(init_resp, outlen ? out : "");
    170 	if (msg_verbose) {
    171 		msg_info("%s: client_reply='%s'", __func__,
    172 		    outlen ? (const char *)out : "");
    173 	}
    174 
    175 	if (outlen > 0)
    176 		memset(out, 0, outlen);		/* XXX: silly? */
    177 	if (out != NULL)
    178 		free (out);
    179 
    180 	return XSASL_AUTH_OK;
    181 }
    182 
    183 /*
    184  * Continue authentication.
    185  */
    186 static int
    187 xsasl_saslc_client_next(XSASL_CLIENT *xp, const char *server_reply,
    188     VSTRING *client_reply)
    189 {
    190 	XSASL_SASLC_CLIENT *client;
    191 	void *out;
    192 	size_t outlen;
    193 
    194 	client = (XSASL_SASLC_CLIENT *)xp;
    195 
    196 	if (msg_verbose)
    197 		msg_info("%s: server_reply='%s'", __func__, server_reply);
    198 
    199 	if (saslc_sess_cont(client->sess, server_reply, strlen(server_reply),
    200 	    &out, &outlen) == -1) {
    201 		msg_info("%s: saslc_sess_encode='%s'", __func__,
    202 		    saslc_sess_strerror(client->sess));
    203 		return XSASL_AUTH_FAIL;
    204 	}
    205 	vstring_strcpy(client_reply, outlen ? out : "");
    206 	if (msg_verbose) {
    207 		msg_info("%s: client_reply='%s'", __func__,
    208 		    outlen ? (const char *) out : "");
    209 	}
    210 
    211 	if (outlen > 0)
    212 		memset(out, 0, outlen);		/* XXX: silly? */
    213 	if (out != NULL)
    214 		free (out);
    215 
    216 	return XSASL_AUTH_OK;
    217 }
    218 
    219 /*
    220  * Per-session cleanup.
    221  */
    222 void
    223 xsasl_saslc_client_free(XSASL_CLIENT *xp)
    224 {
    225 	XSASL_SASLC_CLIENT *client;
    226 
    227 	client = (XSASL_SASLC_CLIENT *)xp;
    228 	if (client->sess)
    229 		saslc_sess_end(client->sess);
    230 	myfree((char *)client);
    231 }
    232 
    233 /*
    234  * Per-session SASL initialization.
    235  */
    236 XSASL_CLIENT *
    237 xsasl_saslc_client_create(XSASL_CLIENT_IMPL *impl,
    238     XSASL_CLIENT_CREATE_ARGS *args)
    239 {
    240 	XSASL_SASLC_CLIENT_IMPL *xp;
    241 	XSASL_SASLC_CLIENT *client;
    242 
    243 	xp = (XSASL_SASLC_CLIENT_IMPL *)impl;
    244 	if (msg_verbose) {
    245 		msg_info("%s: service='%s'", __func__, args->service);
    246 		msg_info("%s: server_name='%s'", __func__, args->server_name);
    247 		msg_info("%s: security_options='%s'", __func__,
    248 		    args->security_options);
    249 	}
    250 
    251 	/* NB: mymalloc never returns NULL, it calls _exit(3) instead */
    252 	client = (XSASL_SASLC_CLIENT *)mymalloc(sizeof(*client));
    253 
    254 	client->xsasl.free  = xsasl_saslc_client_free;
    255 	client->xsasl.first = xsasl_saslc_client_first;
    256 	client->xsasl.next  = xsasl_saslc_client_next;
    257 
    258 	client->saslc = xp->saslc;
    259 
    260 	/* XXX: should these be strdup()ed? */
    261 	client->service  = args->service;
    262 	client->hostname = args->server_name;
    263 	client->sec_opts = args->security_options;
    264 
    265 	return &client->xsasl;
    266 }
    267 
    268 /*
    269  * Dispose of implementation.
    270  */
    271 static void
    272 xsasl_saslc_client_done(XSASL_CLIENT_IMPL *impl)
    273 {
    274 	XSASL_SASLC_CLIENT_IMPL *xp;
    275 
    276 	xp = (XSASL_SASLC_CLIENT_IMPL *)impl;
    277 	if (xp->saslc) {
    278 		saslc_end(xp->saslc);
    279 		xp->saslc = NULL;  /* XXX: unnecessary as freeing impl */
    280 	}
    281 	myfree((char *)impl);
    282 }
    283 
    284 /*
    285  * Initialize saslc SASL library.
    286  */
    287 XSASL_CLIENT_IMPL *
    288 xsasl_saslc_client_init(const char *client_type, const char *path_info)
    289 {
    290 	XSASL_SASLC_CLIENT_IMPL *xp;
    291 
    292 	/* XXX: This should be unnecessary! */
    293 	if (strcmp(client_type, XSASL_TYPE_SASLC) != 0) {
    294 		msg_info("%s: invalid client_type: '%s'", __func__,
    295 		    client_type);
    296 		return NULL;
    297 	}
    298 	if (msg_verbose) {
    299 		msg_info("%s: client_type='%s'", __func__, client_type);
    300 		msg_info("%s: path_info='%s'",   __func__, path_info);
    301 	}
    302 
    303 	/* NB: mymalloc() never returns NULL, it calls _exit(3) instead */
    304 	xp = (XSASL_SASLC_CLIENT_IMPL *)mymalloc(sizeof(*xp));
    305 	xp->xsasl.create = xsasl_saslc_client_create;
    306 	xp->xsasl.done = xsasl_saslc_client_done;
    307 
    308 	/* NB: msg_fatal() exits the program immediately after printing */
    309 	if ((xp->saslc = saslc_alloc()) == NULL)
    310 		msg_fatal("%s: saslc_alloc failed: %s", __func__,
    311 		    strerror(errno));
    312 
    313 	if (saslc_init(xp->saslc, XSASL_SASLC_APPNAME, path_info) == -1)
    314 		msg_fatal("%s: saslc_init failed: %s", __func__,
    315 		    saslc_strerror(xp->saslc));
    316 
    317 	return &xp->xsasl;
    318 }
    319 
    320 #endif /* defined(USE_SASL_AUTH) && defined(USE_SASLC_SASL) */
    321