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