1 /* $NetBSD: xsasl_saslc_client.c,v 1.1 2011/02/12 19:07:09 christos 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__, outlen ? out : ""); 172 173 if (outlen > 0) 174 memset(out, 0, outlen); /* XXX: silly? */ 175 if (out != NULL) 176 free (out); 177 178 return XSASL_AUTH_OK; 179 } 180 181 /* 182 * Continue authentication. 183 */ 184 static int 185 xsasl_saslc_client_next(XSASL_CLIENT *xp, const char *server_reply, 186 VSTRING *client_reply) 187 { 188 XSASL_SASLC_CLIENT *client; 189 void *out; 190 size_t outlen; 191 192 client = (XSASL_SASLC_CLIENT *)xp; 193 194 if (msg_verbose) 195 msg_info("%s: server_reply='%s'", __func__, server_reply); 196 197 if (saslc_sess_cont(client->sess, server_reply, strlen(server_reply), 198 &out, &outlen) == -1) { 199 msg_info("%s: saslc_sess_encode='%s'", __func__, 200 saslc_sess_strerror(client->sess)); 201 return XSASL_AUTH_FAIL; 202 } 203 vstring_strcpy(client_reply, outlen ? out : ""); 204 if (msg_verbose) 205 msg_info("%s: client_reply='%s'", __func__, 206 outlen ? out : ""); 207 208 if (outlen > 0) 209 memset(out, 0, outlen); /* XXX: silly? */ 210 if (out != NULL) 211 free (out); 212 213 return XSASL_AUTH_OK; 214 } 215 216 /* 217 * Per-session cleanup. 218 */ 219 void 220 xsasl_saslc_client_free(XSASL_CLIENT *xp) 221 { 222 XSASL_SASLC_CLIENT *client; 223 224 client = (XSASL_SASLC_CLIENT *)xp; 225 if (client->sess) 226 saslc_sess_end(client->sess); 227 myfree((char *)client); 228 } 229 230 /* 231 * Per-session SASL initialization. 232 */ 233 XSASL_CLIENT * 234 xsasl_saslc_client_create(XSASL_CLIENT_IMPL *impl, 235 XSASL_CLIENT_CREATE_ARGS *args) 236 { 237 XSASL_SASLC_CLIENT_IMPL *xp; 238 XSASL_SASLC_CLIENT *client; 239 240 xp = (XSASL_SASLC_CLIENT_IMPL *)impl; 241 if (msg_verbose) { 242 msg_info("%s: service='%s'", __func__, args->service); 243 msg_info("%s: server_name='%s'", __func__, args->server_name); 244 msg_info("%s: security_options='%s'", __func__, 245 args->security_options); 246 } 247 248 /* NB: mymalloc never returns NULL, it calls _exit(3) instead */ 249 client = (XSASL_SASLC_CLIENT *)mymalloc(sizeof(*client)); 250 251 client->xsasl.free = xsasl_saslc_client_free; 252 client->xsasl.first = xsasl_saslc_client_first; 253 client->xsasl.next = xsasl_saslc_client_next; 254 255 client->saslc = xp->saslc; 256 257 /* XXX: should these be strdup()ed? */ 258 client->service = args->service; 259 client->hostname = args->server_name; 260 client->sec_opts = args->security_options; 261 262 return &client->xsasl; 263 } 264 265 /* 266 * Dispose of implementation. 267 */ 268 static void 269 xsasl_saslc_client_done(XSASL_CLIENT_IMPL *impl) 270 { 271 XSASL_SASLC_CLIENT_IMPL *xp; 272 273 xp = (XSASL_SASLC_CLIENT_IMPL *)impl; 274 if (xp->saslc) { 275 saslc_end(xp->saslc); 276 xp->saslc = NULL; /* XXX: unnecessary as freeing impl */ 277 } 278 myfree((char *)impl); 279 } 280 281 /* 282 * Initialize saslc SASL library. 283 */ 284 XSASL_CLIENT_IMPL * 285 xsasl_saslc_client_init(const char *client_type, const char *path_info) 286 { 287 XSASL_SASLC_CLIENT_IMPL *xp; 288 289 /* XXX: This should be unnecessary! */ 290 if (strcmp(client_type, XSASL_TYPE_SASLC) != 0) { 291 msg_info("%s: invalid client_type: '%s'", __func__, 292 client_type); 293 return NULL; 294 } 295 if (msg_verbose) { 296 msg_info("%s: client_type='%s'", __func__, client_type); 297 msg_info("%s: path_info='%s'", __func__, path_info); 298 } 299 300 /* NB: mymalloc() never returns NULL, it calls _exit(3) instead */ 301 xp = (XSASL_SASLC_CLIENT_IMPL *)mymalloc(sizeof(*xp)); 302 xp->xsasl.create = xsasl_saslc_client_create; 303 xp->xsasl.done = xsasl_saslc_client_done; 304 305 /* NB: msg_fatal() exits the program immediately after printing */ 306 if ((xp->saslc = saslc_alloc()) == NULL) 307 msg_fatal("%s: saslc_alloc failed: %s", __func__, 308 strerror(errno)); 309 310 if (saslc_init(xp->saslc, XSASL_SASLC_APPNAME, path_info) == -1) 311 msg_fatal("%s: saslc_init failed: %s", __func__, 312 saslc_strerror(xp->saslc)); 313 314 return &xp->xsasl; 315 } 316 317 #endif /* defined(USE_SASL_AUTH) && defined(USE_SASLC_SASL) */ 318