1 /* smtp.c --- Implement SMTP profile of SASL login.
2 * Copyright (C) 2002-2021 Simon Josefsson
3 *
4 * This file is part of GNU SASL.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "smtp.h"
22
23 int
smtp_greeting(void)24 smtp_greeting (void)
25 {
26 char *in;
27
28 if (!readln (&in))
29 return 0;
30
31 return 1;
32 }
33
34 int
smtp_has_starttls(void)35 smtp_has_starttls (void)
36 {
37 char *in;
38 int has_tls = 0;
39
40 if (!writeln ("EHLO [127.0.0.1]"))
41 return 0;
42
43 do
44 {
45 if (!readln (&in))
46 return 0;
47
48 #define TLSGREETING "250-STARTTLS"
49 if (strncmp (in, TLSGREETING, strlen (TLSGREETING)) == 0)
50 has_tls = 1;
51 }
52 while (strncmp (in, "250 ", 4) != 0);
53
54 return has_tls;
55 }
56
57 int
smtp_starttls(void)58 smtp_starttls (void)
59 {
60 char *in;
61
62 if (!writeln ("STARTTLS"))
63 return 0;
64
65 if (!readln (&in))
66 return 0;
67
68 return 1;
69 }
70
71 int
smtp_select_mechanism(char ** mechlist)72 smtp_select_mechanism (char **mechlist)
73 {
74 char *in;
75
76 if (args_info.server_flag)
77 {
78 if (!args_info.quiet_given)
79 fprintf (stderr, _("Input list of SASL mechanisms:\n"));
80 if (!readln (&in))
81 return 0;
82 *mechlist = in;
83 }
84 else
85 {
86 if (!writeln ("EHLO [127.0.0.1]"))
87 return 0;
88
89 do
90 {
91 if (!readln (&in))
92 return 0;
93
94 #define GREETING1 "250-AUTH "
95 #define GREETING2 "250 AUTH "
96 if (strncmp (in, GREETING1, strlen (GREETING1)) == 0)
97 *mechlist = in + strlen (GREETING1);
98 else if (strncmp (in, GREETING2, strlen (GREETING2)) == 0)
99 *mechlist = in + strlen (GREETING2);
100 }
101 while (strncmp (in, "250 ", 4) != 0);
102 }
103
104 return 1;
105 }
106
107 int
smtp_authenticate(const char * mech)108 smtp_authenticate (const char *mech)
109 {
110 if (args_info.server_flag)
111 {
112 if (!args_info.quiet_given)
113 fprintf (stderr, _("Using mechanism:\n"));
114 puts (mech);
115 }
116 else
117 {
118 char *buf;
119 int rc;
120 int len;
121
122 len = asprintf (&buf, "AUTH %s", mech);
123 if (len < 0)
124 return 0;
125 rc = writeln (buf);
126 free (buf);
127 if (!rc)
128 return 0;
129 }
130
131 return 1;
132 }
133
134 int
smtp_step_send(const char * data)135 smtp_step_send (const char *data)
136 {
137 char *buf;
138 int rc;
139 int len;
140
141 if (args_info.server_flag)
142 len = asprintf (&buf, "334 %s", data);
143 else
144 len = asprintf (&buf, "%s", data);
145 if (len < 0)
146 return 0;
147 rc = writeln (buf);
148 free (buf);
149 if (!rc)
150 return 0;
151
152 return 1;
153 }
154
155 /* Return 1 on token, 2 on protocol success, 3 on protocol fail, 0 on
156 errors. */
157 int
smtp_step_recv(char ** data)158 smtp_step_recv (char **data)
159 {
160 char *p;
161
162 if (!readln (data))
163 return 0;
164
165 p = *data;
166
167 if (strlen (p) <= 3)
168 return 0;
169
170 if (strncmp (p, "334 ", 4) == 0)
171 {
172 memmove (&p[0], &p[4], strlen (p) - 3);
173
174 if (p[strlen (p) - 1] == '\n')
175 p[strlen (p) - 1] = '\0';
176 if (p[strlen (p) - 1] == '\r')
177 p[strlen (p) - 1] = '\0';
178
179 return 1;
180 }
181
182 if (strncmp (p, "235 ", 4) == 0)
183 {
184 /* Never a token here, we don't support additional server
185 information on success. */
186 return 2;
187 }
188
189 if (strncmp (p, "535 ", 4) == 0)
190 return 3;
191
192 fprintf (stderr, _("error: could not parse server data:\n%s\n"), p);
193
194 return 0;
195 }
196
197 int
smtp_logout(void)198 smtp_logout (void)
199 {
200 char *in;
201
202 if (!writeln ("QUIT"))
203 return 0;
204
205 /* read "221 2.0.0 foo closing ..." */
206 if (!readln (&in))
207 return 0;
208
209 free (in);
210
211 return 1;
212 }
213