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