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