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