1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2010-2021 Free Software Foundation, Inc.
3 
4    This library is free software; you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <mailutils/diag.h>
24 #include <mailutils/errno.h>
25 #include <mailutils/smtp.h>
26 #include <mailutils/sys/smtp.h>
27 #include <mailutils/mailbox.h> /* Strange, mu_ticket_file is declared here */
28 #include <mailutils/util.h>
29 #include <mailutils/auth.h>
30 #include <mailutils/url.h>
31 
32 #if defined(WITH_GSASL)
33 static int
get_ticket(mu_ticket_t * pticket)34 get_ticket (mu_ticket_t *pticket)
35 {
36   char *filename = mu_tilde_expansion (mu_ticket_file,
37 				       MU_HIERARCHY_DELIMITER, NULL);
38   mu_wicket_t wicket;
39   int rc;
40 
41   rc = mu_file_wicket_create (&wicket, filename);
42 
43   if (rc == 0)
44     rc = mu_wicket_get_ticket (wicket, NULL, pticket);
45   mu_wicket_destroy (&wicket);
46   free (filename);
47   return rc;
48 }
49 
50 #define _HAS_USERNAME 0x01
51 #define _HAS_PASSWORD 0x02
52 
53 static int
_mu_smtp_fixup_params(mu_smtp_t smtp)54 _mu_smtp_fixup_params (mu_smtp_t smtp)
55 {
56   const char *str;
57   mu_ticket_t ticket = NULL;
58   int flags = 0;
59   int rc;
60 
61   if (smtp->param[MU_SMTP_PARAM_USERNAME])
62     flags |= _HAS_USERNAME;
63 
64   if (smtp->secret)
65     flags |= _HAS_PASSWORD;
66 
67   if ((flags & (_HAS_USERNAME|_HAS_PASSWORD)) == (_HAS_USERNAME|_HAS_PASSWORD))
68     return 0; /* Nothing to do */
69 
70   if (!smtp->url)
71     return 0;
72 
73   if (!(flags & _HAS_USERNAME))
74     {
75       rc = mu_url_sget_user (smtp->url, &str);
76       if (rc == 0 &&
77 	  mu_smtp_set_param (smtp, MU_SMTP_PARAM_USERNAME, str) == 0)
78 	flags |= _HAS_USERNAME;
79     }
80 
81   if (!(flags & _HAS_PASSWORD) &&
82       mu_url_get_secret (smtp->url, &smtp->secret) == 0)
83     flags |= _HAS_PASSWORD;
84 
85   if ((!(flags & _HAS_USERNAME) ||
86        !(flags & _HAS_PASSWORD)) &&
87       get_ticket (&ticket) == 0)
88     {
89       if (!(flags & _HAS_USERNAME) &&
90 	  mu_ticket_get_cred (ticket, smtp->url, "SMTP User: ",
91 			      &smtp->param[MU_SMTP_PARAM_USERNAME],
92 			      NULL) == 0)
93 	flags |= _HAS_USERNAME;
94 
95       if (!(flags & _HAS_PASSWORD) && !smtp->secret)
96 	mu_ticket_get_cred (ticket, smtp->url, "SMTP Passwd: ",
97 			    NULL, &smtp->secret);
98       mu_ticket_destroy (&ticket);
99     }
100 
101   return 0;
102 }
103 #endif
104 
105 int
mu_smtp_auth(mu_smtp_t smtp)106 mu_smtp_auth (mu_smtp_t smtp)
107 {
108   if (!smtp)
109     return EINVAL;
110   if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
111     return MU_ERR_FAILURE;
112   if (MU_SMTP_FISSET (smtp, _MU_SMTP_AUTH))
113     return MU_ERR_SEQ;
114   if (smtp->state != MU_SMTP_MAIL)
115     return MU_ERR_SEQ;
116 
117 #if defined(WITH_GSASL)
118   /* Obtain missing authentication credentials either from the
119      URL (when supplied) or from the user ticket file, or by
120      asking the user, if anything else fails.
121 
122      FIXME: This needs some more work.  First of all, it should
123      be called only when really needed (e.g. by mu_smtp_get_param).
124      Secondly, it should ask the user even if no URL was supplied
125      (presently it does not).  Thirdly, there should be an API to
126      let caller determine the way of inputting missing data (by
127      default it does that on tty, which obviously will not suite
128      GUI applications). */
129   _mu_smtp_fixup_params (smtp);
130   if (!smtp->param[MU_SMTP_PARAM_USERNAME] && !smtp->secret)
131     return MU_ERR_AUTH_NO_CRED;
132   return _mu_smtp_gsasl_auth (smtp);
133 #else
134   /* FIXME: Provide support for some basic authentication methods.
135      Once done, make sure _mu_smtp_fixup_params is called for this
136      branch as well (though see the fixme above). */
137   return ENOSYS;
138 #endif
139 }
140