Postfix3.3.1
xsasl_dovecot_server.c
[詳解]
1 /*++
2 /* NAME
3 /* xsasl_dovecot_server 3
4 /* SUMMARY
5 /* Dovecot SASL server-side plug-in
6 /* SYNOPSIS
7 /* XSASL_SERVER_IMPL *xsasl_dovecot_server_init(server_type, appl_name)
8 /* const char *server_type;
9 /* const char *appl_name;
10 /* DESCRIPTION
11 /* This module implements the Dovecot SASL server-side authentication
12 /* plug-in.
13 /*
14 /* .IP server_type
15 /* The plug-in type that was specified to xsasl_server_init().
16 /* The argument is ignored, because the Dovecot plug-in
17 /* implements only one plug-in type.
18 /* .IP path_info
19 /* The location of the Dovecot authentication server's UNIX-domain
20 /* socket. Note: the Dovecot plug-in uses late binding, therefore
21 /* all connect operations are done with Postfix privileges.
22 /* DIAGNOSTICS
23 /* Fatal: out of memory.
24 /*
25 /* Panic: interface violation.
26 /*
27 /* Other: the routines log a warning and return an error result
28 /* as specified in xsasl_server(3).
29 /* LICENSE
30 /* .ad
31 /* .fi
32 /* The Secure Mailer license must be distributed with this software.
33 /* AUTHOR(S)
34 /* Initial implementation by:
35 /* Timo Sirainen
36 /* Procontrol
37 /* Finland
38 /*
39 /* Adopted by:
40 /* Wietse Venema
41 /* IBM T.J. Watson Research
42 /* P.O. Box 704
43 /* Yorktown Heights, NY 10598, USA
44 /*
45 /* Wietse Venema
46 /* Google, Inc.
47 /* 111 8th Avenue
48 /* New York, NY 10011, USA
49 /*--*/
50 
51 /* System library. */
52 
53 #include <sys_defs.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #ifdef STRCASECMP_IN_STRINGS_H
59 #include <strings.h>
60 #endif
61 
62 /* Utility library. */
63 
64 #include <msg.h>
65 #include <mymalloc.h>
66 #include <connect.h>
67 #include <split_at.h>
68 #include <stringops.h>
69 #include <vstream.h>
70 #include <vstring_vstream.h>
71 #include <name_mask.h>
72 #include <argv.h>
73 #include <myaddrinfo.h>
74 
75 /* Global library. */
76 
77 #include <mail_params.h>
78 
79 /* Application-specific. */
80 
81 #include <xsasl.h>
82 #include <xsasl_dovecot.h>
83 
84 #ifdef USE_SASL_AUTH
85 
86 /* Major version changes are not backwards compatible,
87  minor version numbers can be ignored. */
88 #define AUTH_PROTOCOL_MAJOR_VERSION 1
89 #define AUTH_PROTOCOL_MINOR_VERSION 0
90 
91  /*
92  * Encorce read/write time limits, so that we can produce accurate
93  * diagnostics instead of getting killed by the watchdog timer.
94  */
95 #define AUTH_TIMEOUT 10
96 
97  /*
98  * Security property bitmasks.
99  */
100 #define SEC_PROPS_NOPLAINTEXT (1 << 0)
101 #define SEC_PROPS_NOACTIVE (1 << 1)
102 #define SEC_PROPS_NODICTIONARY (1 << 2)
103 #define SEC_PROPS_NOANONYMOUS (1 << 3)
104 #define SEC_PROPS_FWD_SECRECY (1 << 4)
105 #define SEC_PROPS_MUTUAL_AUTH (1 << 5)
106 #define SEC_PROPS_PRIVATE (1 << 6)
107 
108 #define SEC_PROPS_POS_MASK (SEC_PROPS_MUTUAL_AUTH | SEC_PROPS_FWD_SECRECY)
109 #define SEC_PROPS_NEG_MASK (SEC_PROPS_NOPLAINTEXT | SEC_PROPS_NOACTIVE | \
110  SEC_PROPS_NODICTIONARY | SEC_PROPS_NOANONYMOUS)
111 
112  /*
113  * Security properties as specified in the Postfix main.cf file.
114  */
115 static const NAME_MASK xsasl_dovecot_conf_sec_props[] = {
116  "noplaintext", SEC_PROPS_NOPLAINTEXT,
117  "noactive", SEC_PROPS_NOACTIVE,
118  "nodictionary", SEC_PROPS_NODICTIONARY,
119  "noanonymous", SEC_PROPS_NOANONYMOUS,
120  "forward_secrecy", SEC_PROPS_FWD_SECRECY,
121  "mutual_auth", SEC_PROPS_MUTUAL_AUTH,
122  0, 0,
123 };
124 
125  /*
126  * Security properties as specified in the Dovecot protocol. See
127  * http://wiki.dovecot.org/Authentication_Protocol.
128  */
129 static const NAME_MASK xsasl_dovecot_serv_sec_props[] = {
130  "plaintext", SEC_PROPS_NOPLAINTEXT,
131  "active", SEC_PROPS_NOACTIVE,
132  "dictionary", SEC_PROPS_NODICTIONARY,
133  "anonymous", SEC_PROPS_NOANONYMOUS,
134  "forward-secrecy", SEC_PROPS_FWD_SECRECY,
135  "mutual-auth", SEC_PROPS_MUTUAL_AUTH,
136  "private", SEC_PROPS_PRIVATE,
137  0, 0,
138 };
139 
140  /*
141  * Class variables.
142  */
143 typedef struct XSASL_DCSRV_MECH {
144  char *mech_name; /* mechanism name */
145  int sec_props; /* mechanism properties */
146  struct XSASL_DCSRV_MECH *next;
147 } XSASL_DCSRV_MECH;
148 
149 typedef struct {
150  XSASL_SERVER_IMPL xsasl;
151  VSTREAM *sasl_stream;
152  char *socket_path;
153  XSASL_DCSRV_MECH *mechanism_list; /* unfiltered mechanism list */
154  unsigned int request_id_counter;
155 } XSASL_DOVECOT_SERVER_IMPL;
156 
157  /*
158  * The XSASL_DOVECOT_SERVER object is derived from the generic XSASL_SERVER
159  * object.
160  */
161 typedef struct {
162  XSASL_SERVER xsasl; /* generic members, must be first */
163  XSASL_DOVECOT_SERVER_IMPL *impl;
164  unsigned int last_request_id;
165  char *service;
166  char *username; /* authenticated user */
167  VSTRING *sasl_line;
168  unsigned int sec_props; /* Postfix mechanism filter */
169  int tls_flag; /* TLS enabled in this session */
170  char *mechanism_list; /* filtered mechanism list */
171  ARGV *mechanism_argv; /* ditto */
172  char *client_addr; /* remote IP address */
173  char *server_addr; /* remote IP address */
174 } XSASL_DOVECOT_SERVER;
175 
176  /*
177  * Forward declarations.
178  */
179 static void xsasl_dovecot_server_done(XSASL_SERVER_IMPL *);
180 static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *,
182 static void xsasl_dovecot_server_free(XSASL_SERVER *);
183 static int xsasl_dovecot_server_first(XSASL_SERVER *, const char *,
184  const char *, VSTRING *);
185 static int xsasl_dovecot_server_next(XSASL_SERVER *, const char *, VSTRING *);
186 static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *);
187 static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *);
188 
189 /* xsasl_dovecot_server_mech_append - append server mechanism entry */
190 
191 static void xsasl_dovecot_server_mech_append(XSASL_DCSRV_MECH **mech_list,
192  const char *mech_name, int sec_props)
193 {
194  XSASL_DCSRV_MECH **mpp;
195  XSASL_DCSRV_MECH *mp;
196 
197  for (mpp = mech_list; *mpp != 0; mpp = &mpp[0]->next)
198  /* void */ ;
199 
200  mp = (XSASL_DCSRV_MECH *) mymalloc(sizeof(*mp));
201  mp->mech_name = mystrdup(mech_name);
202  mp->sec_props = sec_props;
203  mp->next = 0;
204  *mpp = mp;
205 }
206 
207 /* xsasl_dovecot_server_mech_free - destroy server mechanism list */
208 
209 static void xsasl_dovecot_server_mech_free(XSASL_DCSRV_MECH *mech_list)
210 {
211  XSASL_DCSRV_MECH *mp;
212  XSASL_DCSRV_MECH *next;
213 
214  for (mp = mech_list; mp != 0; mp = next) {
215  myfree(mp->mech_name);
216  next = mp->next;
217  myfree((void *) mp);
218  }
219 }
220 
221 /* xsasl_dovecot_server_mech_filter - filter server mechanism list */
222 
223 static char *xsasl_dovecot_server_mech_filter(ARGV *mechanism_argv,
224  XSASL_DCSRV_MECH *mechanism_list,
225  unsigned int conf_props)
226 {
227  const char *myname = "xsasl_dovecot_server_mech_filter";
228  unsigned int pos_conf_props = (conf_props & SEC_PROPS_POS_MASK);
229  unsigned int neg_conf_props = (conf_props & SEC_PROPS_NEG_MASK);
230  VSTRING *mechanisms_str = vstring_alloc(10);
231  XSASL_DCSRV_MECH *mp;
232 
233  /*
234  * Match Postfix properties against Dovecot server properties.
235  */
236  for (mp = mechanism_list; mp != 0; mp = mp->next) {
237  if ((mp->sec_props & pos_conf_props) == pos_conf_props
238  && (mp->sec_props & neg_conf_props) == 0) {
239  if (VSTRING_LEN(mechanisms_str) > 0)
240  VSTRING_ADDCH(mechanisms_str, ' ');
241  vstring_strcat(mechanisms_str, mp->mech_name);
242  argv_add(mechanism_argv, mp->mech_name, (char *) 0);
243  if (msg_verbose)
244  msg_info("%s: keep mechanism: %s", myname, mp->mech_name);
245  } else {
246  if (msg_verbose)
247  msg_info("%s: skip mechanism: %s", myname, mp->mech_name);
248  }
249  }
250  return (vstring_export(mechanisms_str));
251 }
252 
253 /* xsasl_dovecot_server_connect - initial auth server handshake */
254 
255 static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp)
256 {
257  const char *myname = "xsasl_dovecot_server_connect";
258  VSTRING *line_str;
259  VSTREAM *sasl_stream;
260  char *line, *cmd, *mech_name;
261  unsigned int major_version, minor_version;
262  int fd, success, have_mech_line;
263  int sec_props;
264  const char *path;
265 
266  if (msg_verbose)
267  msg_info("%s: Connecting", myname);
268 
269  /*
270  * Not documented, but necessary for testing.
271  */
272  path = xp->socket_path;
273  if (strncmp(path, "inet:", 5) == 0) {
274  fd = inet_connect(path + 5, BLOCKING, AUTH_TIMEOUT);
275  } else {
276  if (strncmp(path, "unix:", 5) == 0)
277  path += 5;
278  fd = unix_connect(path, BLOCKING, AUTH_TIMEOUT);
279  }
280  if (fd < 0) {
281  msg_warn("SASL: Connect to %s failed: %m", xp->socket_path);
282  return (-1);
283  }
284  sasl_stream = vstream_fdopen(fd, O_RDWR);
285  vstream_control(sasl_stream,
286  CA_VSTREAM_CTL_PATH(xp->socket_path),
287  CA_VSTREAM_CTL_TIMEOUT(AUTH_TIMEOUT),
289 
290  /* XXX Encapsulate for logging. */
291  vstream_fprintf(sasl_stream,
292  "VERSION\t%u\t%u\n"
293  "CPID\t%u\n",
294  AUTH_PROTOCOL_MAJOR_VERSION,
295  AUTH_PROTOCOL_MINOR_VERSION,
296  (unsigned int) getpid());
297  if (vstream_fflush(sasl_stream) == VSTREAM_EOF) {
298  msg_warn("SASL: Couldn't send handshake: %m");
299  return (-1);
300  }
301  success = 0;
302  have_mech_line = 0;
303  line_str = vstring_alloc(256);
304  /* XXX Encapsulate for logging. */
305  while (vstring_get_nonl(line_str, sasl_stream) != VSTREAM_EOF) {
306  line = vstring_str(line_str);
307 
308  if (msg_verbose)
309  msg_info("%s: auth reply: %s", myname, line);
310 
311  cmd = line;
312  line = split_at(line, '\t');
313 
314  if (strcmp(cmd, "VERSION") == 0) {
315  if (sscanf(line, "%u\t%u", &major_version, &minor_version) != 2) {
316  msg_warn("SASL: Protocol version error");
317  break;
318  }
319  if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) {
320  /* Major version is different from ours. */
321  msg_warn("SASL: Protocol version mismatch (%d vs. %d)",
322  major_version, AUTH_PROTOCOL_MAJOR_VERSION);
323  break;
324  }
325  } else if (strcmp(cmd, "MECH") == 0 && line != NULL) {
326  mech_name = line;
327  have_mech_line = 1;
328  line = split_at(line, '\t');
329  if (line != 0) {
330  sec_props =
331  name_mask_delim_opt(myname,
332  xsasl_dovecot_serv_sec_props,
333  line, "\t",
335  if ((sec_props & SEC_PROPS_PRIVATE) != 0)
336  continue;
337  } else
338  sec_props = 0;
339  xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name,
340  sec_props);
341  } else if (strcmp(cmd, "SPID") == 0) {
342 
343  /*
344  * Unfortunately the auth protocol handshake wasn't designed well
345  * to differentiate between auth-client/userdb/master.
346  * auth-userdb and auth-master send VERSION + SPID lines only and
347  * nothing afterwards, while auth-client sends VERSION + MECH +
348  * SPID + CUID + more. The simplest way that we can determine if
349  * we've connected to the correct socket is to see if MECH line
350  * exists or not (alternatively we'd have to have a small timeout
351  * after SPID to see if CUID is sent or not).
352  */
353  if (!have_mech_line) {
354  msg_warn("SASL: Connected to wrong auth socket (auth-master instead of auth-client)");
355  break;
356  }
357  } else if (strcmp(cmd, "DONE") == 0) {
358  /* Handshake finished. */
359  success = 1;
360  break;
361  } else {
362  /* ignore any unknown commands */
363  }
364  }
365  vstring_free(line_str);
366 
367  if (!success) {
368  /* handshake failed */
369  (void) vstream_fclose(sasl_stream);
370  return (-1);
371  }
372  xp->sasl_stream = sasl_stream;
373  return (0);
374 }
375 
376 /* xsasl_dovecot_server_disconnect - dispose of server connection state */
377 
378 static void xsasl_dovecot_server_disconnect(XSASL_DOVECOT_SERVER_IMPL *xp)
379 {
380  if (xp->sasl_stream) {
381  (void) vstream_fclose(xp->sasl_stream);
382  xp->sasl_stream = 0;
383  }
384  if (xp->mechanism_list) {
385  xsasl_dovecot_server_mech_free(xp->mechanism_list);
386  xp->mechanism_list = 0;
387  }
388 }
389 
390 /* xsasl_dovecot_server_init - create implementation handle */
391 
392 XSASL_SERVER_IMPL *xsasl_dovecot_server_init(const char *server_type,
393  const char *path_info)
394 {
395  XSASL_DOVECOT_SERVER_IMPL *xp;
396 
397  xp = (XSASL_DOVECOT_SERVER_IMPL *) mymalloc(sizeof(*xp));
398  xp->xsasl.create = xsasl_dovecot_server_create;
399  xp->xsasl.done = xsasl_dovecot_server_done;
400  xp->socket_path = mystrdup(path_info);
401  xp->sasl_stream = 0;
402  xp->mechanism_list = 0;
403  xp->request_id_counter = 0;
404  return (&xp->xsasl);
405 }
406 
407 /* xsasl_dovecot_server_done - dispose of implementation */
408 
409 static void xsasl_dovecot_server_done(XSASL_SERVER_IMPL *impl)
410 {
411  XSASL_DOVECOT_SERVER_IMPL *xp = (XSASL_DOVECOT_SERVER_IMPL *) impl;
412 
413  xsasl_dovecot_server_disconnect(xp);
414  myfree(xp->socket_path);
415  myfree((void *) impl);
416 }
417 
418 /* xsasl_dovecot_server_create - create server instance */
419 
420 static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *impl,
422 {
423  const char *myname = "xsasl_dovecot_server_create";
424  XSASL_DOVECOT_SERVER *server;
425  struct sockaddr_storage ss;
426  struct sockaddr *sa = (struct sockaddr *) &ss;
427  SOCKADDR_SIZE salen;
428  MAI_HOSTADDR_STR server_addr;
429 
430  if (msg_verbose)
431  msg_info("%s: SASL service=%s, realm=%s",
432  myname, args->service, args->user_realm ?
433  args->user_realm : "(null)");
434 
435  /*
436  * Extend the XSASL_SERVER_IMPL object with our own data. We use
437  * long-lived conversion buffers rather than local variables to avoid
438  * memory leaks in case of read/write timeout or I/O error.
439  */
440  server = (XSASL_DOVECOT_SERVER *) mymalloc(sizeof(*server));
441  server->xsasl.free = xsasl_dovecot_server_free;
442  server->xsasl.first = xsasl_dovecot_server_first;
443  server->xsasl.next = xsasl_dovecot_server_next;
444  server->xsasl.get_mechanism_list = xsasl_dovecot_server_get_mechanism_list;
445  server->xsasl.get_username = xsasl_dovecot_server_get_username;
446  server->impl = (XSASL_DOVECOT_SERVER_IMPL *) impl;
447  server->sasl_line = vstring_alloc(256);
448  server->username = 0;
449  server->service = mystrdup(args->service);
450  server->last_request_id = 0;
451  server->mechanism_list = 0;
452  server->mechanism_argv = 0;
453  server->tls_flag = args->tls_flag;
454  server->sec_props =
455  name_mask_opt(myname, xsasl_dovecot_conf_sec_props,
456  args->security_options,
458  server->client_addr = mystrdup(args->client_addr);
459 
460  /*
461  * XXX Temporary code until smtpd_peer.c is updated.
462  */
463  if (args->server_addr && *args->server_addr) {
464  server->server_addr = mystrdup(args->server_addr);
465  } else {
466  salen = sizeof(ss);
467  if (getsockname(vstream_fileno(args->stream), sa, &salen) < 0
468  || sockaddr_to_hostaddr(sa, salen, &server_addr, 0, 0) != 0)
469  server_addr.buf[0] = 0;
470  server->server_addr = mystrdup(server_addr.buf);
471  }
472 
473  return (&server->xsasl);
474 }
475 
476 /* xsasl_dovecot_server_get_mechanism_list - get available mechanisms */
477 
478 static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *xp)
479 {
480  XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
481 
482  if (!server->impl->sasl_stream) {
483  if (xsasl_dovecot_server_connect(server->impl) < 0)
484  return (0);
485  }
486  if (server->mechanism_list == 0) {
487  server->mechanism_argv = argv_alloc(2);
488  server->mechanism_list =
489  xsasl_dovecot_server_mech_filter(server->mechanism_argv,
490  server->impl->mechanism_list,
491  server->sec_props);
492  }
493  return (server->mechanism_list[0] ? server->mechanism_list : 0);
494 }
495 
496 /* xsasl_dovecot_server_free - destroy server instance */
497 
498 static void xsasl_dovecot_server_free(XSASL_SERVER *xp)
499 {
500  XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
501 
502  vstring_free(server->sasl_line);
503  if (server->username)
504  myfree(server->username);
505  if (server->mechanism_list) {
506  myfree(server->mechanism_list);
507  argv_free(server->mechanism_argv);
508  }
509  myfree(server->service);
510  myfree(server->server_addr);
511  myfree(server->client_addr);
512  myfree((void *) server);
513 }
514 
515 /* xsasl_dovecot_server_auth_response - encode server first/next response */
516 
517 static int xsasl_dovecot_parse_reply(XSASL_DOVECOT_SERVER *server, char **line)
518 {
519  char *id;
520 
521  if (*line == NULL) {
522  msg_warn("SASL: Protocol error");
523  return -1;
524  }
525  id = *line;
526  *line = split_at(*line, '\t');
527 
528  if (strtoul(id, NULL, 0) != server->last_request_id) {
529  /* reply to another request, shouldn't really happen.. */
530  return -1;
531  }
532  return 0;
533 }
534 
535 static void xsasl_dovecot_parse_reply_args(XSASL_DOVECOT_SERVER *server,
536  char *line, VSTRING *reply,
537  int success)
538 {
539  char *next;
540 
541  if (server->username) {
542  myfree(server->username);
543  server->username = 0;
544  }
545 
546  /*
547  * Note: TAB is part of the Dovecot protocol and must not appear in
548  * legitimate Dovecot usernames, otherwise the protocol would break.
549  */
550  for (; line != NULL; line = next) {
551  next = split_at(line, '\t');
552  if (strncmp(line, "user=", 5) == 0) {
553  server->username = mystrdup(line + 5);
554  printable(server->username, '?');
555  } else if (strncmp(line, "reason=", 7) == 0) {
556  if (!success) {
557  printable(line + 7, '?');
558  vstring_strcpy(reply, line + 7);
559  }
560  }
561  }
562 }
563 
564 /* xsasl_dovecot_handle_reply - receive and process auth reply */
565 
566 static int xsasl_dovecot_handle_reply(XSASL_DOVECOT_SERVER *server,
567  VSTRING *reply)
568 {
569  const char *myname = "xsasl_dovecot_handle_reply";
570  char *line, *cmd;
571 
572  /* XXX Encapsulate for logging. */
573  while (vstring_get_nonl(server->sasl_line,
574  server->impl->sasl_stream) != VSTREAM_EOF) {
575  line = vstring_str(server->sasl_line);
576 
577  if (msg_verbose)
578  msg_info("%s: auth reply: %s", myname, line);
579 
580  cmd = line;
581  line = split_at(line, '\t');
582 
583  if (strcmp(cmd, "OK") == 0) {
584  if (xsasl_dovecot_parse_reply(server, &line) == 0) {
585  /* authentication successful */
586  xsasl_dovecot_parse_reply_args(server, line, reply, 1);
587  return XSASL_AUTH_DONE;
588  }
589  } else if (strcmp(cmd, "CONT") == 0) {
590  if (xsasl_dovecot_parse_reply(server, &line) == 0) {
591  vstring_strcpy(reply, line);
592  return XSASL_AUTH_MORE;
593  }
594  } else if (strcmp(cmd, "FAIL") == 0) {
595  if (xsasl_dovecot_parse_reply(server, &line) == 0) {
596  /* authentication failure */
597  xsasl_dovecot_parse_reply_args(server, line, reply, 0);
598  return XSASL_AUTH_FAIL;
599  }
600  } else {
601  /* ignore */
602  }
603  }
604 
605  vstring_strcpy(reply, "Connection lost to authentication server");
606  return XSASL_AUTH_TEMP;
607 }
608 
609 /* is_valid_base64 - input sanitized */
610 
611 static int is_valid_base64(const char *data)
612 {
613 
614  /*
615  * XXX Maybe use ISALNUM() (isascii && isalnum, i.e. locale independent).
616  */
617  for (; *data != '\0'; data++) {
618  if (!((*data >= '0' && *data <= '9') ||
619  (*data >= 'a' && *data <= 'z') ||
620  (*data >= 'A' && *data <= 'Z') ||
621  *data == '+' || *data == '/' || *data == '='))
622  return 0;
623  }
624  return 1;
625 }
626 
627 /* xsasl_dovecot_server_first - per-session authentication */
628 
629 int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method,
630  const char *init_response, VSTRING *reply)
631 {
632  const char *myname = "xsasl_dovecot_server_first";
633  XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
634  int i;
635  char **cpp;
636 
637 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
638 
639  if (msg_verbose)
640  msg_info("%s: sasl_method %s%s%s", myname, sasl_method,
641  IFELSE(init_response, ", init_response ", ""),
642  IFELSE(init_response, init_response, ""));
643 
644  if (server->mechanism_argv == 0)
645  msg_panic("%s: no mechanism list", myname);
646 
647  for (cpp = server->mechanism_argv->argv; /* see below */ ; cpp++) {
648  if (*cpp == 0) {
649  vstring_strcpy(reply, "Invalid authentication mechanism");
650  return XSASL_AUTH_FAIL;
651  }
652  if (strcasecmp(sasl_method, *cpp) == 0)
653  break;
654  }
655  if (init_response)
656  if (!is_valid_base64(init_response)) {
657  vstring_strcpy(reply, "Invalid base64 data in initial response");
658  return XSASL_AUTH_FAIL;
659  }
660  for (i = 0; i < 2; i++) {
661  if (!server->impl->sasl_stream) {
662  if (xsasl_dovecot_server_connect(server->impl) < 0)
663  return XSASL_AUTH_TEMP;
664  }
665  /* send the request */
666  server->last_request_id = ++server->impl->request_id_counter;
667  /* XXX Encapsulate for logging. */
668  vstream_fprintf(server->impl->sasl_stream,
669  "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s",
670  server->last_request_id, sasl_method,
671  server->service, server->server_addr,
672  server->client_addr);
673  if (server->tls_flag)
674  /* XXX Encapsulate for logging. */
675  vstream_fputs("\tsecured", server->impl->sasl_stream);
676  if (init_response) {
677 
678  /*
679  * initial response is already base64 encoded, so we can send it
680  * directly.
681  */
682  /* XXX Encapsulate for logging. */
683  vstream_fprintf(server->impl->sasl_stream,
684  "\tresp=%s", init_response);
685  }
686  /* XXX Encapsulate for logging. */
687  VSTREAM_PUTC('\n', server->impl->sasl_stream);
688 
689  if (vstream_fflush(server->impl->sasl_stream) != VSTREAM_EOF)
690  break;
691 
692  if (i == 1) {
693  vstring_strcpy(reply, "Can't connect to authentication server");
694  return XSASL_AUTH_TEMP;
695  }
696 
697  /*
698  * Reconnect and try again.
699  */
700  xsasl_dovecot_server_disconnect(server->impl);
701  }
702 
703  return xsasl_dovecot_handle_reply(server, reply);
704 }
705 
706 /* xsasl_dovecot_server_next - continue authentication */
707 
708 static int xsasl_dovecot_server_next(XSASL_SERVER *xp, const char *request,
709  VSTRING *reply)
710 {
711  XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
712 
713  if (!is_valid_base64(request)) {
714  vstring_strcpy(reply, "Invalid base64 data in continued response");
715  return XSASL_AUTH_FAIL;
716  }
717  /* XXX Encapsulate for logging. */
718  vstream_fprintf(server->impl->sasl_stream,
719  "CONT\t%u\t%s\n", server->last_request_id, request);
720  if (vstream_fflush(server->impl->sasl_stream) == VSTREAM_EOF) {
721  vstring_strcpy(reply, "Connection lost to authentication server");
722  return XSASL_AUTH_TEMP;
723  }
724  return xsasl_dovecot_handle_reply(server, reply);
725 }
726 
727 /* xsasl_dovecot_server_get_username - get authenticated username */
728 
729 static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *xp)
730 {
731  XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
732 
733  return (server->username);
734 }
735 
736 #endif
const char * server_addr
Definition: xsasl.h:50
int msg_verbose
Definition: msg.c:177
#define VSTREAM_EOF
Definition: vstream.h:110
void myfree(void *ptr)
Definition: mymalloc.c:207
#define XSASL_AUTH_FAIL
Definition: xsasl.h:127
#define CA_VSTREAM_CTL_TIMEOUT(v)
Definition: vstream.h:163
char * mystrdup(const char *str)
Definition: mymalloc.c:225
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
#define NAME_MASK_IGNORE
Definition: name_mask.h:34
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
#define VSTRING_LEN(vp)
Definition: vstring.h:72
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
int sockaddr_to_hostaddr(const struct sockaddr *sa, SOCKADDR_SIZE salen, MAI_HOSTADDR_STR *hostaddr, MAI_SERVPORT_STR *portnum, int unused_socktype)
Definition: myaddrinfo.c:580
#define SOCKADDR_SIZE
Definition: sys_defs.h:1411
#define XSASL_AUTH_DONE
Definition: xsasl.h:125
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
char buf[MAI_HOSTADDR_STRSIZE]
Definition: myaddrinfo.h:146
const char * client_addr
Definition: xsasl.h:52
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
Definition: vstream.c:1348
int inet_connect(const char *, int, int)
Definition: inet_connect.c:77
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
int unix_connect(const char *, int, int)
Definition: unix_connect.c:59
void msg_warn(const char *fmt,...)
Definition: msg.c:215
int name_mask_delim_opt(const char *context, const NAME_MASK *table, const char *names, const char *delim, int flags)
Definition: name_mask.c:206
const char * user_realm
Definition: xsasl.h:55
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
const char * username(void)
Definition: username.c:38
#define XSASL_AUTH_TEMP
Definition: xsasl.h:128
VSTREAM * stream
Definition: xsasl.h:48
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define XSASL_AUTH_MORE
Definition: xsasl.h:124
const char * security_options
Definition: xsasl.h:56
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:41
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
#define vstream_fileno(vp)
Definition: vstream.h:115
#define NAME_MASK_FATAL
Definition: name_mask.h:27
#define NAME_MASK_ANY_CASE
Definition: name_mask.h:28
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
#define CA_VSTREAM_CTL_PATH(v)
Definition: vstream.h:158
const char * service
Definition: xsasl.h:54
#define VSTREAM_PUTC(ch, vp)
Definition: vstream.h:107
char * printable(char *string, int replacement)
Definition: printable.c:49
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
#define BLOCKING
Definition: iostuff.h:48
#define name_mask_opt(tag, table, str, flags)
Definition: name_mask.h:46
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
char * vstring_export(VSTRING *vp)
Definition: vstring.c:569
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
int vstream_fputs(const char *str, VSTREAM *stream)
Definition: vstream.c:1360
void msg_info(const char *fmt,...)
Definition: msg.c:199