~ubuntu-branches/ubuntu/utopic/gnome-online-accounts/utopic

« back to all changes in this revision

Viewing changes to src/goabackend/goasmtpauth.c

  • Committer: Package Import Robot
  • Author(s): Andreas Henriksson, Laurent Bigonville, Andreas Henriksson
  • Date: 2014-05-16 11:42:52 UTC
  • mfrom: (1.1.28) (0.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20140516114252-u5ect6mk6ht8i38x
Tags: 3.12.2-1
[ Laurent Bigonville ]
* debian/control.in: Recommends realmd package (Closes: #725965)

[ Andreas Henriksson ]
* New upstream release.
  - Removes chat support from Windows Live provider (XMPP gateway gone).
* Bump Standards-Version to 3.9.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
/*
 
3
 * Copyright (C) 2011, 2013, 2014 Red Hat, Inc.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General
 
16
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 
17
 *
 
18
 * Authors: David Zeuthen <davidz@redhat.com>
 
19
 *          Debarshi Ray <debarshir@gnome.org>
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <string.h>
 
25
 
 
26
#include <glib/gi18n-lib.h>
 
27
 
 
28
#include "goasmtpauth.h"
 
29
#include "goaprovider.h"
 
30
#include "goautils.h"
 
31
 
 
32
/**
 
33
 * SECTION:goasmtpauth
 
34
 * @title: GoaSmtpAuth
 
35
 * @short_description: Authentication mechanisms for SMTP
 
36
 *
 
37
 * #GoaSmtpAuth implements the <ulink
 
38
 * url="http://tools.ietf.org/html/rfc4616">PLAIN</ulink> and <ulink
 
39
 * url="http://msdn.microsoft.com/en-us/library/cc433484(v=EXCHG.80).aspx">LOGIN</ulink>
 
40
 * SASL mechanisms (e.g. using usernames / passwords) for SMTP.
 
41
 */
 
42
 
 
43
/**
 
44
 * GoaSmtpAuth:
 
45
 *
 
46
 * The #GoaSmtpAuth structure contains only private data and should
 
47
 * only be accessed using the provided API.
 
48
 */
 
49
struct _GoaSmtpAuth
 
50
{
 
51
  GoaMailAuth parent_instance;
 
52
 
 
53
  GoaProvider *provider;
 
54
  GoaObject *object;
 
55
  gboolean auth_supported;
 
56
  gboolean greeting_absent;
 
57
  gboolean login_supported;
 
58
  gboolean plain_supported;
 
59
  gchar *domain;
 
60
  gchar *username;
 
61
  gchar *password;
 
62
};
 
63
 
 
64
typedef struct
 
65
{
 
66
  GoaMailAuthClass parent_class;
 
67
 
 
68
} GoaSmtpAuthClass;
 
69
 
 
70
enum
 
71
{
 
72
  PROP_0,
 
73
  PROP_PROVIDER,
 
74
  PROP_OBJECT,
 
75
  PROP_DOMAIN,
 
76
  PROP_USERNAME,
 
77
  PROP_PASSWORD
 
78
};
 
79
 
 
80
static gboolean goa_smtp_auth_is_needed (GoaMailAuth        *_auth);
 
81
static gboolean goa_smtp_auth_run_sync (GoaMailAuth         *_auth,
 
82
                                        GCancellable        *cancellable,
 
83
                                        GError             **error);
 
84
static gboolean goa_smtp_auth_starttls_sync (GoaMailAuth    *_auth,
 
85
                                             GCancellable   *cancellable,
 
86
                                             GError        **error);
 
87
 
 
88
G_DEFINE_TYPE (GoaSmtpAuth, goa_smtp_auth, GOA_TYPE_MAIL_AUTH);
 
89
 
 
90
/* ---------------------------------------------------------------------------------------------------- */
 
91
 
 
92
static gboolean
 
93
smtp_auth_check_not_220 (const gchar *response, GError **error)
 
94
{
 
95
  if (!g_str_has_prefix (response, "220"))
 
96
    {
 
97
      g_set_error (error,
 
98
                   GOA_ERROR,
 
99
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
100
                   "Unexpected response `%s'",
 
101
                   response);
 
102
      return TRUE;
 
103
    }
 
104
 
 
105
  return FALSE;
 
106
}
 
107
 
 
108
static gboolean
 
109
smtp_auth_check_not_235 (const gchar *response, GError **error)
 
110
{
 
111
  if (!g_str_has_prefix (response, "235"))
 
112
    {
 
113
      g_set_error (error,
 
114
                   GOA_ERROR,
 
115
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
116
                   _("Authentication failed"));
 
117
      return TRUE;
 
118
    }
 
119
 
 
120
  return FALSE;
 
121
}
 
122
 
 
123
static gboolean
 
124
smtp_auth_check_not_250 (const gchar *response, GError **error)
 
125
{
 
126
  if (!g_str_has_prefix (response, "250") || strlen (response) < 4)
 
127
    {
 
128
      g_set_error (error,
 
129
                   GOA_ERROR,
 
130
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
131
                   "Unexpected response `%s'",
 
132
                   response);
 
133
      return TRUE;
 
134
    }
 
135
 
 
136
  return FALSE;
 
137
}
 
138
 
 
139
static gboolean
 
140
smtp_auth_check_not_334_login_password (const gchar *response, GError **error)
 
141
{
 
142
  if (!g_str_has_prefix (response, "334 UGFzc3dvcmQ6"))
 
143
    {
 
144
      g_set_error (error,
 
145
                   GOA_ERROR,
 
146
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
147
                   "Unexpected response `%s'",
 
148
                   response);
 
149
      return TRUE;
 
150
    }
 
151
 
 
152
  return FALSE;
 
153
}
 
154
 
 
155
static gboolean
 
156
smtp_auth_check_421 (const gchar *response, GError **error)
 
157
{
 
158
  if (g_str_has_prefix (response, "421"))
 
159
    {
 
160
      g_set_error (error,
 
161
                   GOA_ERROR,
 
162
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
163
                   _("Service not available"));
 
164
      return TRUE;
 
165
    }
 
166
 
 
167
  return FALSE;
 
168
}
 
169
 
 
170
static gboolean
 
171
smtp_auth_check_454 (const gchar *response, GError **error)
 
172
{
 
173
  if (g_str_has_prefix (response, "454"))
 
174
    {
 
175
      g_set_error (error,
 
176
                   GOA_ERROR,
 
177
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
178
                   _("TLS not available"));
 
179
      return TRUE;
 
180
    }
 
181
 
 
182
  return FALSE;
 
183
}
 
184
 
 
185
/* ---------------------------------------------------------------------------------------------------- */
 
186
 
 
187
static gboolean
 
188
smtp_auth_check_greeting (GDataInputStream *input, GCancellable *cancellable, GError **error)
 
189
{
 
190
  gboolean ret;
 
191
  gchar *response;
 
192
 
 
193
  response = NULL;
 
194
  ret = FALSE;
 
195
 
 
196
 greeting_again:
 
197
  response = g_data_input_stream_read_line (input, NULL, cancellable, error);
 
198
  if (response == NULL)
 
199
    goto out;
 
200
  g_debug ("< %s", response);
 
201
  if (smtp_auth_check_421 (response, error))
 
202
    goto out;
 
203
  if (smtp_auth_check_not_220 (response, error))
 
204
    goto out;
 
205
 
 
206
  if (response[3] == '-')
 
207
    {
 
208
      g_clear_pointer (&response, g_free);
 
209
      goto greeting_again;
 
210
    }
 
211
 
 
212
  ret = TRUE;
 
213
 
 
214
 out:
 
215
  g_free (response);
 
216
  return ret;
 
217
}
 
218
 
 
219
/* ---------------------------------------------------------------------------------------------------- */
 
220
 
 
221
static gchar *
 
222
smtp_auth_get_domain (GoaSmtpAuth   *auth,
 
223
                      GError       **error)
 
224
{
 
225
  gchar *domain;
 
226
 
 
227
  domain = NULL;
 
228
 
 
229
  if (auth->domain != NULL)
 
230
    {
 
231
      domain = g_strdup (auth->domain);
 
232
    }
 
233
  else if (auth->object != NULL)
 
234
    {
 
235
      GoaMail *mail;
 
236
      gchar *email_address;
 
237
 
 
238
      mail = goa_object_get_mail (auth->object);
 
239
      if (mail == NULL)
 
240
        {
 
241
          g_set_error (error,
 
242
                       GOA_ERROR,
 
243
                       GOA_ERROR_FAILED, /* TODO: more specific */
 
244
                       _("org.gnome.OnlineAccounts.Mail is not available"));
 
245
          goto out;
 
246
        }
 
247
 
 
248
      email_address = goa_mail_dup_email_address (mail);
 
249
      if (!goa_utils_parse_email_address (email_address, NULL, &domain))
 
250
        {
 
251
          g_set_error (error,
 
252
                       GOA_ERROR,
 
253
                       GOA_ERROR_FAILED, /* TODO: more specific */
 
254
                       _("Failed to parse email address"));
 
255
          goto out;
 
256
        }
 
257
 
 
258
      g_free (email_address);
 
259
      g_object_unref (mail);
 
260
    }
 
261
  else
 
262
    {
 
263
      g_set_error (error,
 
264
                   GOA_ERROR,
 
265
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
266
                   _("Cannot do SMTP authentication without a domain"));
 
267
      goto out;
 
268
    }
 
269
 
 
270
 out:
 
271
  return domain;
 
272
}
 
273
 
 
274
static gchar *
 
275
smtp_auth_get_password (GoaSmtpAuth       *auth,
 
276
                        GCancellable      *cancellable,
 
277
                        GError           **error)
 
278
{
 
279
  gchar *password;
 
280
 
 
281
  password = NULL;
 
282
 
 
283
  if (auth->password != NULL)
 
284
    {
 
285
      password = g_strdup (auth->password);
 
286
    }
 
287
  else if (auth->provider != NULL && auth->object != NULL)
 
288
    {
 
289
      GVariant *credentials;
 
290
      credentials = goa_utils_lookup_credentials_sync (auth->provider,
 
291
                                                       auth->object,
 
292
                                                       cancellable,
 
293
                                                       error);
 
294
      if (credentials == NULL)
 
295
        {
 
296
          g_prefix_error (error, "Error looking up credentials for SMTP in keyring: ");
 
297
          goto out;
 
298
        }
 
299
      if (!g_variant_lookup (credentials, "smtp-password", "s", &password))
 
300
        {
 
301
          g_set_error (error,
 
302
                       GOA_ERROR,
 
303
                       GOA_ERROR_FAILED, /* TODO: more specific */
 
304
                       _("Did not find smtp-password in credentials"));
 
305
          g_variant_unref (credentials);
 
306
          goto out;
 
307
        }
 
308
      g_variant_unref (credentials);
 
309
    }
 
310
  else
 
311
    {
 
312
      g_set_error (error,
 
313
                   GOA_ERROR,
 
314
                   GOA_ERROR_FAILED, /* TODO: more specific */
 
315
                   _("Cannot do SMTP authentication without a password"));
 
316
      goto out;
 
317
    }
 
318
 
 
319
 out:
 
320
  return password;
 
321
}
 
322
 
 
323
/* ---------------------------------------------------------------------------------------------------- */
 
324
 
 
325
static void
 
326
goa_smtp_auth_finalize (GObject *object)
 
327
{
 
328
  GoaSmtpAuth *auth = GOA_SMTP_AUTH (object);
 
329
 
 
330
  g_clear_object (&auth->provider);
 
331
  g_clear_object (&auth->object);
 
332
  g_free (auth->domain);
 
333
  g_free (auth->username);
 
334
  g_free (auth->password);
 
335
 
 
336
  G_OBJECT_CLASS (goa_smtp_auth_parent_class)->finalize (object);
 
337
}
 
338
 
 
339
static void
 
340
goa_smtp_auth_get_property (GObject      *object,
 
341
                            guint         prop_id,
 
342
                            GValue       *value,
 
343
                            GParamSpec   *pspec)
 
344
{
 
345
  GoaSmtpAuth *auth = GOA_SMTP_AUTH (object);
 
346
 
 
347
  switch (prop_id)
 
348
    {
 
349
    case PROP_PROVIDER:
 
350
      g_value_set_object (value, auth->provider);
 
351
      break;
 
352
 
 
353
    case PROP_OBJECT:
 
354
      g_value_set_object (value, auth->object);
 
355
      break;
 
356
 
 
357
    case PROP_DOMAIN:
 
358
      g_value_set_string (value, auth->domain);
 
359
      break;
 
360
 
 
361
    case PROP_USERNAME:
 
362
      g_value_set_string (value, auth->username);
 
363
      break;
 
364
 
 
365
    case PROP_PASSWORD:
 
366
      g_value_set_string (value, auth->password);
 
367
      break;
 
368
 
 
369
    default:
 
370
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
371
      break;
 
372
    }
 
373
}
 
374
 
 
375
static void
 
376
goa_smtp_auth_set_property (GObject      *object,
 
377
                            guint         prop_id,
 
378
                            const GValue *value,
 
379
                            GParamSpec   *pspec)
 
380
{
 
381
  GoaSmtpAuth *auth = GOA_SMTP_AUTH (object);
 
382
 
 
383
  switch (prop_id)
 
384
    {
 
385
    case PROP_PROVIDER:
 
386
      auth->provider = g_value_dup_object (value);
 
387
      break;
 
388
 
 
389
    case PROP_OBJECT:
 
390
      auth->object = g_value_dup_object (value);
 
391
      break;
 
392
 
 
393
    case PROP_DOMAIN:
 
394
      auth->domain = g_value_dup_string (value);
 
395
      break;
 
396
 
 
397
    case PROP_USERNAME:
 
398
      auth->username = g_value_dup_string (value);
 
399
      break;
 
400
 
 
401
    case PROP_PASSWORD:
 
402
      auth->password = g_value_dup_string (value);
 
403
      break;
 
404
 
 
405
    default:
 
406
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
407
      break;
 
408
    }
 
409
}
 
410
 
 
411
/* ---------------------------------------------------------------------------------------------------- */
 
412
 
 
413
 
 
414
static void
 
415
goa_smtp_auth_init (GoaSmtpAuth *client)
 
416
{
 
417
}
 
418
 
 
419
static void
 
420
goa_smtp_auth_class_init (GoaSmtpAuthClass *klass)
 
421
{
 
422
  GObjectClass *gobject_class;
 
423
  GoaMailAuthClass *auth_class;
 
424
 
 
425
  gobject_class = G_OBJECT_CLASS (klass);
 
426
  gobject_class->finalize = goa_smtp_auth_finalize;
 
427
  gobject_class->get_property = goa_smtp_auth_get_property;
 
428
  gobject_class->set_property = goa_smtp_auth_set_property;
 
429
 
 
430
  auth_class = GOA_MAIL_AUTH_CLASS (klass);
 
431
  auth_class->is_needed = goa_smtp_auth_is_needed;
 
432
  auth_class->run_sync = goa_smtp_auth_run_sync;
 
433
  auth_class->starttls_sync = goa_smtp_auth_starttls_sync;
 
434
 
 
435
  /**
 
436
   * GoaSmtpAuth:provider:
 
437
   *
 
438
   * The #GoaProvider object for the account or %NULL.
 
439
   */
 
440
  g_object_class_install_property (gobject_class,
 
441
                                   PROP_PROVIDER,
 
442
                                   g_param_spec_object ("provider",
 
443
                                                        "provider",
 
444
                                                        "provider",
 
445
                                                        GOA_TYPE_PROVIDER,
 
446
                                                        G_PARAM_READABLE |
 
447
                                                        G_PARAM_WRITABLE |
 
448
                                                        G_PARAM_CONSTRUCT_ONLY |
 
449
                                                        G_PARAM_STATIC_STRINGS));
 
450
 
 
451
  /**
 
452
   * GoaSmtpAuth:object:
 
453
   *
 
454
   * The #GoaObject object for the account.
 
455
   */
 
456
  g_object_class_install_property (gobject_class,
 
457
                                   PROP_OBJECT,
 
458
                                   g_param_spec_object ("object",
 
459
                                                        "object",
 
460
                                                        "object",
 
461
                                                        GOA_TYPE_OBJECT,
 
462
                                                        G_PARAM_READABLE |
 
463
                                                        G_PARAM_WRITABLE |
 
464
                                                        G_PARAM_CONSTRUCT_ONLY |
 
465
                                                        G_PARAM_STATIC_STRINGS));
 
466
 
 
467
  /**
 
468
   * GoaSmtpAuth:domain:
 
469
   *
 
470
   * The domail or %NULL.
 
471
   *
 
472
   * If this is %NULL, the domain is obtained from the
 
473
   * email address associated with the #GoaObject.
 
474
   */
 
475
  g_object_class_install_property (gobject_class,
 
476
                                   PROP_DOMAIN,
 
477
                                   g_param_spec_string ("domain",
 
478
                                                        "domain",
 
479
                                                        "domain",
 
480
                                                        NULL,
 
481
                                                        G_PARAM_READABLE |
 
482
                                                        G_PARAM_WRITABLE |
 
483
                                                        G_PARAM_CONSTRUCT_ONLY |
 
484
                                                        G_PARAM_STATIC_STRINGS));
 
485
 
 
486
  /**
 
487
   * GoaSmtpAuth:user-name:
 
488
   *
 
489
   * The user name.
 
490
   */
 
491
  g_object_class_install_property (gobject_class,
 
492
                                   PROP_USERNAME,
 
493
                                   g_param_spec_string ("user-name",
 
494
                                                        "user-name",
 
495
                                                        "user-name",
 
496
                                                        NULL,
 
497
                                                        G_PARAM_READABLE |
 
498
                                                        G_PARAM_WRITABLE |
 
499
                                                        G_PARAM_CONSTRUCT_ONLY |
 
500
                                                        G_PARAM_STATIC_STRINGS));
 
501
 
 
502
  /**
 
503
   * GoaSmtpAuth:password:
 
504
   *
 
505
   * The password or %NULL.
 
506
   *
 
507
   * If this is %NULL, the credentials are looked up using
 
508
   * goa_utils_lookup_credentials_sync() using the
 
509
   * #GoaSmtpAuth:provider and #GoaSmtpAuth:object for @provider and
 
510
   * @object. The credentials are expected to be a %G_VARIANT_VARDICT
 
511
   * and the key <literal>smtp-password</literal> is used to look up
 
512
   * the password.
 
513
   */
 
514
  g_object_class_install_property (gobject_class,
 
515
                                   PROP_PASSWORD,
 
516
                                   g_param_spec_string ("password",
 
517
                                                        "password",
 
518
                                                        "password",
 
519
                                                        NULL,
 
520
                                                        G_PARAM_READABLE |
 
521
                                                        G_PARAM_WRITABLE |
 
522
                                                        G_PARAM_CONSTRUCT_ONLY |
 
523
                                                        G_PARAM_STATIC_STRINGS));
 
524
}
 
525
 
 
526
/* ---------------------------------------------------------------------------------------------------- */
 
527
 
 
528
/**
 
529
 * goa_smtp_auth_new:
 
530
 * @provider: (allow-none): A #GoaPlainProvider or %NULL.
 
531
 * @object: (allow-none): An account object or %NULL.
 
532
 * @domain: (allow-none): The domain to use or %NULL to look it up
 
533
 * (see the #GoaSmtpAuth:domain property).
 
534
 * @username: The user name to use.
 
535
 * @password: (allow-none): The password to use or %NULL to look it up
 
536
 * (see the #GoaSmtpAuth:password property).
 
537
 *
 
538
 * Creates a new #GoaMailAuth to be used for username/password
 
539
 * authentication using LOGIN or PLAIN over SMTP.
 
540
 *
 
541
 * Returns: (type GoaSmtpAuth): A #GoaSmtpAuth. Free with
 
542
 * g_object_unref().
 
543
 */
 
544
GoaMailAuth *
 
545
goa_smtp_auth_new (GoaProvider       *provider,
 
546
                   GoaObject         *object,
 
547
                   const gchar       *domain,
 
548
                   const gchar       *username,
 
549
                   const gchar       *password)
 
550
{
 
551
  g_return_val_if_fail (provider == NULL || GOA_IS_PROVIDER (provider), NULL);
 
552
  g_return_val_if_fail (object == NULL || GOA_IS_OBJECT (object), NULL);
 
553
  g_return_val_if_fail (username != NULL, NULL);
 
554
  return GOA_MAIL_AUTH (g_object_new (GOA_TYPE_SMTP_AUTH,
 
555
                                      "provider", provider,
 
556
                                      "object", object,
 
557
                                      "domain", domain,
 
558
                                      "user-name", username,
 
559
                                      "password", password,
 
560
                                      NULL));
 
561
}
 
562
 
 
563
/* ---------------------------------------------------------------------------------------------------- */
 
564
 
 
565
gboolean
 
566
goa_smtp_auth_is_login (GoaSmtpAuth *auth)
 
567
{
 
568
  return auth->login_supported;
 
569
}
 
570
 
 
571
gboolean
 
572
goa_smtp_auth_is_plain (GoaSmtpAuth *auth)
 
573
{
 
574
  return auth->plain_supported;
 
575
}
 
576
 
 
577
/* ---------------------------------------------------------------------------------------------------- */
 
578
 
 
579
static gboolean
 
580
goa_smtp_auth_is_needed (GoaMailAuth *_auth)
 
581
{
 
582
  GoaSmtpAuth *auth = GOA_SMTP_AUTH (_auth);
 
583
  return auth->auth_supported;
 
584
}
 
585
 
 
586
/* ---------------------------------------------------------------------------------------------------- */
 
587
 
 
588
static gboolean
 
589
goa_smtp_auth_run_sync (GoaMailAuth         *_auth,
 
590
                        GCancellable        *cancellable,
 
591
                        GError             **error)
 
592
{
 
593
  GoaSmtpAuth *auth = GOA_SMTP_AUTH (_auth);
 
594
  GDataInputStream *input;
 
595
  GDataOutputStream *output;
 
596
  gboolean ret;
 
597
  gchar *auth_arg_base64;
 
598
  gchar *auth_arg_plain;
 
599
  gchar *domain;
 
600
  gchar *password;
 
601
  gchar *request;
 
602
  gchar *response;
 
603
  gsize auth_arg_plain_len;
 
604
 
 
605
  auth_arg_base64 = NULL;
 
606
  auth_arg_plain = NULL;
 
607
  domain = NULL;
 
608
  password = NULL;
 
609
  request = NULL;
 
610
  response = NULL;
 
611
 
 
612
  ret = FALSE;
 
613
 
 
614
  password = smtp_auth_get_password (auth, cancellable, error);
 
615
  if (password == NULL)
 
616
    goto out;
 
617
 
 
618
  domain = smtp_auth_get_domain (auth, error);
 
619
  if (domain == NULL)
 
620
    goto out;
 
621
 
 
622
  input = goa_mail_auth_get_input (_auth);
 
623
  output = goa_mail_auth_get_output (_auth);
 
624
 
 
625
  /* Check the greeting, if there is one */
 
626
 
 
627
  if (!auth->greeting_absent)
 
628
    {
 
629
      if (!smtp_auth_check_greeting (input, cancellable, error))
 
630
        goto out;
 
631
    }
 
632
 
 
633
  /* Send EHLO */
 
634
 
 
635
  request = g_strdup_printf ("EHLO %s\r\n", domain);
 
636
  g_debug ("> %s", request);
 
637
  if (!g_data_output_stream_put_string (output, request, cancellable, error))
 
638
    goto out;
 
639
  g_clear_pointer (&request, g_free);
 
640
 
 
641
  /* Check which SASL mechanisms are supported */
 
642
 
 
643
 ehlo_again:
 
644
  response = g_data_input_stream_read_line (input, NULL, cancellable, error);
 
645
  if (response == NULL)
 
646
    goto out;
 
647
  g_debug ("< %s", response);
 
648
  if (smtp_auth_check_421 (response, error))
 
649
    goto out;
 
650
  if (smtp_auth_check_not_250 (response, error))
 
651
    goto out;
 
652
 
 
653
  if (g_str_has_prefix (response + 4, "AUTH"))
 
654
    {
 
655
      auth->auth_supported = TRUE;
 
656
      if (strstr (response, "PLAIN") != NULL)
 
657
        auth->plain_supported = TRUE;
 
658
      else if (strstr (response, "LOGIN") != NULL)
 
659
        auth->login_supported = TRUE;
 
660
    }
 
661
 
 
662
  if (response[3] == '-')
 
663
    {
 
664
      g_free (response);
 
665
      goto ehlo_again;
 
666
    }
 
667
  else if (!auth->auth_supported)
 
668
    {
 
669
      ret = TRUE;
 
670
      goto out;
 
671
    }
 
672
  else if (!auth->login_supported && !auth->plain_supported)
 
673
    {
 
674
      g_set_error (error,
 
675
                   GOA_ERROR,
 
676
                   GOA_ERROR_NOT_SUPPORTED,
 
677
                   _("Unknown authentication mechanism"));
 
678
      goto out;
 
679
    }
 
680
  g_clear_pointer (&response, g_free);
 
681
 
 
682
  /* Try different SASL mechanisms */
 
683
 
 
684
  if (auth->plain_supported)
 
685
    {
 
686
      /* AUTH PLAIN */
 
687
 
 
688
      auth_arg_plain = g_strdup_printf ("%s%c%s%c%s", auth->username, '\0', auth->username, '\0', password);
 
689
      auth_arg_plain_len = 2 * strlen (auth->username) + 2 + strlen (password);
 
690
      auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
 
691
 
 
692
      request = g_strdup_printf ("AUTH PLAIN %s\r\n", auth_arg_base64);
 
693
      g_debug ("> AUTH PLAIN ********************");
 
694
      if (!g_data_output_stream_put_string (output, request, cancellable, error))
 
695
        goto out;
 
696
      g_clear_pointer (&request, g_free);
 
697
    }
 
698
  else
 
699
    {
 
700
      /* AUTH LOGIN */
 
701
 
 
702
      auth_arg_plain = g_strdup (auth->username);
 
703
      auth_arg_plain_len = strlen (auth->username);
 
704
      auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
 
705
 
 
706
      request = g_strdup_printf ("AUTH LOGIN %s\r\n", auth_arg_base64);
 
707
      g_debug ("> AUTH LOGIN ********************");
 
708
      if (!g_data_output_stream_put_string (output, request, cancellable, error))
 
709
        goto out;
 
710
      g_clear_pointer (&request, g_free);
 
711
 
 
712
      response = g_data_input_stream_read_line (input, NULL, cancellable, error);
 
713
      if (response == NULL)
 
714
        goto out;
 
715
      g_debug ("< %s", response);
 
716
      if (smtp_auth_check_not_334_login_password (response, error))
 
717
        goto out;
 
718
 
 
719
      g_free (auth_arg_plain);
 
720
      g_free (auth_arg_base64);
 
721
 
 
722
      auth_arg_plain = g_strdup (password);
 
723
      auth_arg_plain_len = strlen (password);
 
724
      auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
 
725
 
 
726
      request = g_strdup_printf ("%s\r\n", auth_arg_base64);
 
727
      g_debug ("> ********************");
 
728
      if (!g_data_output_stream_put_string (output, request, cancellable, error))
 
729
        goto out;
 
730
      g_clear_pointer (&request, g_free);
 
731
    }
 
732
 
 
733
  response = g_data_input_stream_read_line (input, NULL, cancellable, error);
 
734
  if (response == NULL)
 
735
    goto out;
 
736
  g_debug ("< %s", response);
 
737
  if (smtp_auth_check_not_235 (response, error))
 
738
    goto out;
 
739
  g_clear_pointer (&response, g_free);
 
740
 
 
741
  ret = TRUE;
 
742
 
 
743
 out:
 
744
  g_free (auth_arg_base64);
 
745
  g_free (auth_arg_plain);
 
746
  g_free (domain);
 
747
  g_free (password);
 
748
  g_free (response);
 
749
  g_free (request);
 
750
  return ret;
 
751
}
 
752
 
 
753
/* ---------------------------------------------------------------------------------------------------- */
 
754
 
 
755
static gboolean
 
756
goa_smtp_auth_starttls_sync (GoaMailAuth         *_auth,
 
757
                             GCancellable        *cancellable,
 
758
                             GError             **error)
 
759
{
 
760
  GoaSmtpAuth *auth = GOA_SMTP_AUTH (_auth);
 
761
  GDataInputStream *input;
 
762
  GDataOutputStream *output;
 
763
  gboolean ret;
 
764
  gboolean starttls_supported;
 
765
  gchar *domain;
 
766
  gchar *request;
 
767
  gchar *response;
 
768
 
 
769
  starttls_supported = FALSE;
 
770
  domain = NULL;
 
771
  request = NULL;
 
772
  response = NULL;
 
773
 
 
774
  ret = FALSE;
 
775
 
 
776
  domain = smtp_auth_get_domain (auth, error);
 
777
  if (domain == NULL)
 
778
    goto out;
 
779
 
 
780
  input = goa_mail_auth_get_input (_auth);
 
781
  output = goa_mail_auth_get_output (_auth);
 
782
 
 
783
  /* Check the greeting */
 
784
 
 
785
  if (!smtp_auth_check_greeting (input, cancellable, error))
 
786
    goto out;
 
787
 
 
788
  /* Send EHLO */
 
789
 
 
790
  request = g_strdup_printf ("EHLO %s\r\n", domain);
 
791
  g_debug ("> %s", request);
 
792
  if (!g_data_output_stream_put_string (output, request, cancellable, error))
 
793
    goto out;
 
794
  g_clear_pointer (&request, g_free);
 
795
 
 
796
  /* Check if STARTTLS is supported or not */
 
797
 
 
798
 ehlo_again:
 
799
  response = g_data_input_stream_read_line (input, NULL, cancellable, error);
 
800
  if (response == NULL)
 
801
    goto out;
 
802
  g_debug ("< %s", response);
 
803
  if (smtp_auth_check_421 (response, error))
 
804
    goto out;
 
805
  if (smtp_auth_check_not_250 (response, error))
 
806
    goto out;
 
807
 
 
808
  if (g_str_has_prefix (response + 4, "STARTTLS"))
 
809
    starttls_supported = TRUE;
 
810
 
 
811
  if (response[3] == '-')
 
812
    {
 
813
      g_free (response);
 
814
      goto ehlo_again;
 
815
    }
 
816
  else if (!starttls_supported)
 
817
    {
 
818
      g_set_error (error,
 
819
                   GOA_ERROR,
 
820
                   GOA_ERROR_NOT_SUPPORTED,
 
821
                   _("Server does not support STARTTLS"));
 
822
      goto out;
 
823
    }
 
824
  g_clear_pointer (&response, g_free);
 
825
 
 
826
  /* Send STARTTLS */
 
827
 
 
828
  request = g_strdup ("STARTTLS\r\n");
 
829
  g_debug ("> %s", request);
 
830
  if (!g_data_output_stream_put_string (output, request, cancellable, error))
 
831
    goto out;
 
832
  g_clear_pointer (&request, g_free);
 
833
 
 
834
  response = g_data_input_stream_read_line (input, NULL, cancellable, error);
 
835
  if (response == NULL)
 
836
    goto out;
 
837
  g_debug ("< %s", response);
 
838
  if (smtp_auth_check_454 (response, error))
 
839
    goto out;
 
840
  if (smtp_auth_check_not_220 (response, error))
 
841
    goto out;
 
842
  g_clear_pointer (&response, g_free);
 
843
 
 
844
  /* There won't be a greeting after this */
 
845
  auth->greeting_absent = TRUE;
 
846
 
 
847
  ret = TRUE;
 
848
 
 
849
 out:
 
850
  g_free (domain);
 
851
  g_free (response);
 
852
  g_free (request);
 
853
  return ret;
 
854
}