]> diplodocus.org Git - nmh/blob - uip/mhlogin.c
oauth.c: Alter permissions from 0755 to 0644.
[nmh] / uip / mhlogin.c
1 /* mhlogin.c -- login to external (OAuth) services
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 <errno.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include "h/mh.h"
13 #include "sbr/getarguments.h"
14 #include "sbr/concat.h"
15 #include "sbr/smatch.h"
16 #include "sbr/ambigsw.h"
17 #include "sbr/print_version.h"
18 #include "sbr/print_help.h"
19 #include "sbr/error.h"
20 #include "h/done.h"
21 #include "h/utils.h"
22 #include "h/oauth.h"
23 #include "sbr/lock_file.h"
24
25 #define MHLOGIN_SWITCHES \
26 X("user username", 0, USERSW) \
27 X("saslmech", 0, SASLMECHSW) \
28 X("authservice", 0, AUTHSERVICESW) \
29 X("browser", 0, BROWSERSW) \
30 X("snoop", 0, SNOOPSW) \
31 X("help", 0, HELPSW) \
32 X("version", 0, VERSIONSW) \
33
34 #define X(sw, minchars, id) id,
35 DEFINE_SWITCH_ENUM(MHLOGIN);
36 #undef X
37
38 #define X(sw, minchars, id) { sw, minchars, id },
39 DEFINE_SWITCH_ARRAY(MHLOGIN, switches);
40 #undef X
41
42 #ifdef OAUTH_SUPPORT
43 /* XXX copied from install-mh.c */
44 static char *
45 geta (void)
46 {
47 static char line[BUFSIZ];
48
49 if (fgets(line, sizeof(line), stdin) == NULL)
50 done (1);
51 trim_suffix_c(line, '\n');
52
53 return line;
54 }
55
56 static int
57 do_login(const char *svc, const char *user, const char *browser, int snoop)
58 {
59 char *fn, *code;
60 mh_oauth_ctx *ctx;
61 mh_oauth_cred *cred;
62 FILE *cred_file;
63 int failed_to_lock = 0;
64 const char *url;
65
66 if (svc == NULL) {
67 die("missing -authservice switch");
68 }
69
70 if (user == NULL) {
71 die("missing -user switch");
72 }
73
74 if (!mh_oauth_new(&ctx, svc)) {
75 die("%s", mh_oauth_get_err_string(ctx));
76 }
77
78 if (snoop) {
79 mh_oauth_log_to(stderr, ctx);
80 }
81
82 fn = mh_oauth_cred_fn(svc);
83
84 if ((url = mh_oauth_get_authorize_url(ctx)) == NULL) {
85 die("%s", mh_oauth_get_err_string(ctx));
86 }
87
88 if (browser) {
89 char *command = concat(browser, " '", url, "'", NULL);
90 int status = OK;
91
92 printf("Follow the prompts in your browser to authorize nmh"
93 " to access %s.\n",
94 mh_oauth_svc_display_name(ctx));
95 sleep(1);
96
97 status = system(command);
98 free(command);
99
100 if (status != OK) {
101 adios ((char *) browser, "SYSTEM");
102 }
103 } else {
104 printf("Load the following URL in your browser and authorize nmh"
105 " to access %s:\n\n%s\n\n",
106 mh_oauth_svc_display_name(ctx), url);
107 }
108 fputs("Enter the authorization code: ", stdout);
109 fflush(stdout);
110 code = geta();
111
112 while (!*code ||
113 ((cred = mh_oauth_authorize(code, ctx)) == NULL
114 && mh_oauth_get_err_code(ctx) == MH_OAUTH_BAD_GRANT)) {
115 printf(!*code ? "Empty code; try again? " : "Code rejected; try again? ");
116 fflush(stdout);
117 code = geta();
118 }
119 if (cred == NULL) {
120 inform("error exchanging code for OAuth2 token");
121 die("%s", mh_oauth_get_err_string(ctx));
122 }
123
124 cred_file = lkfopendata(fn, "r+", &failed_to_lock);
125 if (cred_file == NULL && errno == ENOENT) {
126 cred_file = lkfopendata(fn, "w+", &failed_to_lock);
127 }
128 if (cred_file == NULL || failed_to_lock) {
129 adios(fn, "oops");
130 }
131 if (!mh_oauth_cred_save(cred_file, cred, user)) {
132 die("%s", mh_oauth_get_err_string(ctx));
133 }
134 if (lkfclosedata(cred_file, fn) != 0) {
135 adios (fn, "oops");
136 }
137
138 free(fn);
139 mh_oauth_cred_free(cred);
140 mh_oauth_free(ctx);
141
142 return 0;
143 }
144 #endif
145
146 int
147 main(int argc, char **argv)
148 {
149 char *cp, **argp, **arguments;
150 const char *user = NULL, *saslmech = NULL, *svc = NULL, *browser = NULL;
151 int snoop = 0;
152
153 if (nmh_init(argv[0], true, true)) { return 1; }
154
155 arguments = getarguments (invo_name, argc, argv, 1);
156 argp = arguments;
157
158 while ((cp = *argp++)) {
159 if (*cp == '-') {
160 char help[BUFSIZ];
161 switch (smatch (++cp, switches)) {
162 case AMBIGSW:
163 ambigsw (cp, switches);
164 done (1);
165 case UNKWNSW:
166 die("-%s unknown", cp);
167
168 case HELPSW:
169 snprintf(help, sizeof(help), "%s [switches]",
170 invo_name);
171 print_help (help, switches, 1);
172 done (0);
173 case VERSIONSW:
174 print_version(invo_name);
175 done (0);
176
177 case USERSW:
178 if (!(user = *argp++) || *user == '-')
179 die("missing argument to %s", argp[-2]);
180 continue;
181
182 case SASLMECHSW:
183 if (!(saslmech = *argp++) || *saslmech == '-')
184 die("missing argument to %s", argp[-2]);
185 continue;
186
187 case AUTHSERVICESW:
188 if (!(svc = *argp++) || *svc == '-')
189 die("missing argument to %s", argp[-2]);
190 continue;
191
192 case BROWSERSW:
193 if (!(browser = *argp++) || *browser == '-')
194 die("missing argument to %s", argp[-2]);
195 continue;
196
197 case SNOOPSW:
198 snoop++;
199 continue;
200 }
201 }
202 die("extraneous arguments");
203 }
204
205 if (saslmech && strcasecmp(saslmech, "xoauth2")) {
206 /* xoauth is assumed */
207 die("only -saslmech xoauth2 is supported");
208 }
209 free(arguments);
210
211 #ifdef OAUTH_SUPPORT
212 return do_login(svc, user, browser, snoop);
213 #else
214 NMH_UNUSED(svc);
215 NMH_UNUSED(browser);
216 NMH_UNUSED(snoop);
217 die("not built with OAuth support");
218 return 1;
219 #endif
220 }