NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
gsasl.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <gsasl.h>
31#include <stdbool.h>
32#include "mutt/lib.h"
33#include "connaccount.h"
34#include "connection.h"
35#include "gsasl2.h"
36#include "mutt_account.h"
37
38static Gsasl *mutt_gsasl_ctx = NULL;
39
47static int mutt_gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
48{
49 int rc = GSASL_NO_CALLBACK;
50
51 struct Connection *conn = gsasl_session_hook_get(sctx);
52 if (!conn)
53 {
54 mutt_debug(LL_DEBUG1, "missing session hook data!\n");
55 return rc;
56 }
57
58 switch (prop)
59 {
60 case GSASL_PASSWORD:
61 if (mutt_account_getpass(&conn->account))
62 return rc;
63 gsasl_property_set(sctx, GSASL_PASSWORD, conn->account.pass);
64 rc = GSASL_OK;
65 break;
66
67 case GSASL_AUTHID:
68 /* whom the provided password belongs to: login */
70 return rc;
71 gsasl_property_set(sctx, GSASL_AUTHID, conn->account.login);
72 rc = GSASL_OK;
73 break;
74
75 case GSASL_AUTHZID:
76 /* name of the user whose mail/resources you intend to access: user */
77 if (mutt_account_getuser(&conn->account))
78 return rc;
79 gsasl_property_set(sctx, GSASL_AUTHZID, conn->account.user);
80 rc = GSASL_OK;
81 break;
82
83 case GSASL_ANONYMOUS_TOKEN:
84 gsasl_property_set(sctx, GSASL_ANONYMOUS_TOKEN, "dummy");
85 rc = GSASL_OK;
86 break;
87
88 case GSASL_SERVICE:
89 {
90 const char *service = NULL;
91 switch (conn->account.type)
92 {
94 service = "imap";
95 break;
97 service = "pop";
98 break;
100 service = "smtp";
101 break;
102 default:
103 return rc;
104 }
105 gsasl_property_set(sctx, GSASL_SERVICE, service);
106 rc = GSASL_OK;
107 break;
108 }
109
110 case GSASL_HOSTNAME:
111 gsasl_property_set(sctx, GSASL_HOSTNAME, conn->account.host);
112 rc = GSASL_OK;
113 break;
114
115 default:
116 break;
117 }
118
119 return rc;
120}
121
126static bool mutt_gsasl_init(void)
127{
128 if (mutt_gsasl_ctx)
129 return true;
130
131 int rc = gsasl_init(&mutt_gsasl_ctx);
132 if (rc != GSASL_OK)
133 {
134 mutt_gsasl_ctx = NULL;
135 mutt_debug(LL_DEBUG1, "libgsasl initialisation failed (%d): %s.\n", rc,
136 gsasl_strerror(rc));
137 return false;
138 }
139
140 gsasl_callback_set(mutt_gsasl_ctx, mutt_gsasl_callback);
141 return true;
142}
143
148{
149 if (!mutt_gsasl_ctx)
150 return;
151
152 gsasl_done(mutt_gsasl_ctx);
153 mutt_gsasl_ctx = NULL;
154}
155
162const char *mutt_gsasl_get_mech(const char *requested_mech, const char *server_mechlist)
163{
164 if (!mutt_gsasl_init())
165 return NULL;
166
167 /* libgsasl does not do case-independent string comparisons,
168 * and stores its methods internally in uppercase. */
169 char *uc_server_mechlist = mutt_str_dup(server_mechlist);
170 if (uc_server_mechlist)
171 mutt_str_upper(uc_server_mechlist);
172
173 char *uc_requested_mech = mutt_str_dup(requested_mech);
174 if (uc_requested_mech)
175 mutt_str_upper(uc_requested_mech);
176
177 const char *sel_mech = NULL;
178 if (uc_requested_mech)
179 sel_mech = gsasl_client_suggest_mechanism(mutt_gsasl_ctx, uc_requested_mech);
180 else
181 sel_mech = gsasl_client_suggest_mechanism(mutt_gsasl_ctx, uc_server_mechlist);
182
183 FREE(&uc_requested_mech);
184 FREE(&uc_server_mechlist);
185
186 return sel_mech;
187}
188
197int mutt_gsasl_client_new(struct Connection *conn, const char *mech, Gsasl_session **sctx)
198{
199 if (!mutt_gsasl_init())
200 return -1;
201
202 int rc = gsasl_client_start(mutt_gsasl_ctx, mech, sctx);
203 if (rc != GSASL_OK)
204 {
205 *sctx = NULL;
206 mutt_debug(LL_DEBUG1, "gsasl_client_start failed (%d): %s.\n", rc, gsasl_strerror(rc));
207 return -1;
208 }
209
210 gsasl_session_hook_set(*sctx, conn);
211 return 0;
212}
213
218void mutt_gsasl_client_finish(Gsasl_session **sctx)
219{
220 gsasl_finish(*sctx);
221 *sctx = NULL;
222}
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:129
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:49
int mutt_account_getlogin(struct ConnAccount *cac)
Retrieve login info into ConnAccount, if necessary.
Definition: connaccount.c:99
Connection Credentials.
An open network connection (socket)
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
GNU SASL authentication support.
void mutt_gsasl_done(void)
Shutdown GNU SASL library.
Definition: gsasl.c:147
static int mutt_gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
Callback to retrieve authname or user from ConnAccount.
Definition: gsasl.c:47
const char * mutt_gsasl_get_mech(const char *requested_mech, const char *server_mechlist)
Pick a connection mechanism.
Definition: gsasl.c:162
int mutt_gsasl_client_new(struct Connection *conn, const char *mech, Gsasl_session **sctx)
Create a new GNU SASL client.
Definition: gsasl.c:197
void mutt_gsasl_client_finish(Gsasl_session **sctx)
Free a GNU SASL client.
Definition: gsasl.c:218
static bool mutt_gsasl_init(void)
Initialise GNU SASL library.
Definition: gsasl.c:126
static Gsasl * mutt_gsasl_ctx
Definition: gsasl.c:38
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define FREE(x)
Definition: memory.h:43
Convenience wrapper for the library headers.
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
char * mutt_str_upper(char *str)
Convert all characters in the string to uppercase.
Definition: string.c:407
ConnAccount object used by POP and IMAP.
@ MUTT_ACCT_TYPE_SMTP
Smtp Account.
Definition: mutt_account.h:39
@ MUTT_ACCT_TYPE_POP
Pop Account.
Definition: mutt_account.h:38
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
Definition: mutt_account.h:37
char login[128]
Login name.
Definition: connaccount.h:55
char user[128]
Username.
Definition: connaccount.h:56
char pass[256]
Password.
Definition: connaccount.h:57
char host[128]
Server to login to.
Definition: connaccount.h:54
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:59
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50