]> diplodocus.org Git - nmh/blob - sbr/oauth_prof.c
sendsbr.c: Move interface to own file.
[nmh] / sbr / oauth_prof.c
1 /* oauth_prof.c -- OAuth 2.0 implementation for XOAUTH2 in SMTP and POP3.
2 *
3 * This code is Copyright (c) 2014, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include "h/mh.h"
9 #include "concat.h"
10 #include "getcpy.h"
11 #include "context_find.h"
12
13 #ifdef OAUTH_SUPPORT
14
15 #include <sys/stat.h>
16
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <unistd.h>
23
24 #include "h/oauth.h"
25 #include "h/utils.h"
26 #include "m_maildir.h"
27
28 static const struct mh_oauth_service_info SERVICES[] = {
29 /* https://developers.google.com/accounts/docs/OAuth2InstalledApp */
30 {
31 /* name */ "gmail",
32 /* display_name */ "Gmail",
33
34 /* client_id */ "91584523849-8lv9kgp1rvp8ahta6fa4b125tn2polcg.apps.googleusercontent.com",
35 /* client_secret */ "Ua8sX34xyv7hVrKM-U70dKI6",
36
37 /* auth_endpoint */ "https://accounts.google.com/o/oauth2/auth",
38 /* redirect_uri */ "urn:ietf:wg:oauth:2.0:oob",
39 /* token_endpoint */ "https://accounts.google.com/o/oauth2/token",
40 /* scope */ "https://mail.google.com/"
41 }
42 };
43
44 /* Copy service info so we don't have to free it only sometimes. */
45 static void
46 copy_svc(mh_oauth_service_info *to, const mh_oauth_service_info *from)
47 {
48 to->display_name = from->display_name;
49 #define copy(_field_) to->_field_ = getcpy(from->_field_)
50 copy(name);
51 copy(scope);
52 copy(client_id);
53 copy(client_secret);
54 copy(auth_endpoint);
55 copy(token_endpoint);
56 copy(redirect_uri);
57 #undef copy
58 }
59
60 /* Return profile component node name for a service parameter. */
61 char *
62 mh_oauth_node_name_for_svc(const char *base_name, const char *svc)
63 {
64 /* TODO: s/_/-/g ? */
65 return concat("oauth-", svc, "-", base_name, NULL);
66 }
67
68 /* Update one service_info field if overridden in profile. */
69 static void
70 update_svc_field(char **field, const char *base_name, const char *svc)
71 {
72 char *name = mh_oauth_node_name_for_svc(base_name, svc);
73 const char *value = context_find(name);
74 if (value != NULL) {
75 free(*field);
76 *field = mh_xstrdup(value);
77 }
78 free(name);
79 }
80
81 /* Update all service_info fields that are overridden in profile. */
82 static bool
83 update_svc(mh_oauth_service_info *svc, const char *svc_name, char *errbuf,
84 size_t errbuflen)
85 {
86 #define update(name) \
87 update_svc_field(&svc->name, #name, svc_name); \
88 if (svc->name == NULL) { \
89 snprintf(errbuf, errbuflen, "%s", #name " is missing"); \
90 errbuf[errbuflen - 1] = '\0'; \
91 return false; \
92 }
93 update(scope);
94 update(client_id);
95 update(client_secret);
96 update(auth_endpoint);
97 update(token_endpoint);
98 update(redirect_uri);
99 #undef update
100
101 if (svc->name == NULL) {
102 svc->name = getcpy(svc_name);
103 }
104
105 if (svc->display_name == NULL) {
106 svc->display_name = svc->name;
107 }
108
109 return true;
110 }
111
112 bool
113 mh_oauth_get_service_info(const char *svc_name, mh_oauth_service_info *svcinfo,
114 char *errbuf, size_t errbuflen)
115 {
116 int i;
117
118 svcinfo->name = svcinfo->display_name = NULL;
119 svcinfo->scope = svcinfo->client_id = NULL;
120 svcinfo->client_secret = svcinfo->auth_endpoint = NULL;
121 svcinfo->token_endpoint = svcinfo->redirect_uri = NULL;
122
123 for (i = 0; i < (int)DIM(SERVICES); i++) {
124 if (strcmp(SERVICES[i].name, svc_name) == 0) {
125 copy_svc(svcinfo, &SERVICES[i]);
126 break;
127 }
128 }
129
130 return update_svc(svcinfo, svc_name, errbuf, errbuflen);
131 }
132
133 /* Return value must be free(3)'d. */
134 char *
135 mh_oauth_cred_fn(const char *svc)
136 {
137 char *key = mh_oauth_node_name_for_svc("credential-file", svc);
138 char *value = context_find(key);
139 free(key);
140
141 bool found = value;
142 if (found) {
143 if (*value == '/')
144 return mh_xstrdup(value);
145 } else
146 value = concat("oauth-", svc, NULL);
147
148 const char *md = m_maildir(value);
149 if (!found)
150 free(value);
151
152 return mh_xstrdup(md);
153 }
154 #endif