]> diplodocus.org Git - nmh/blob - sbr/mts.c
Make the test suite work on systems other than Linux. Still needs work.
[nmh] / sbr / mts.c
1
2 /*
3 * mts.c -- definitions for the mail transport system
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h> /* for snprintf() */
11 #include <h/nmh.h>
12 #include <h/utils.h>
13
14 #define nmhetcdir(file) NMHETCDIR#file
15
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <h/mts.h>
19 #include <pwd.h>
20 #include <sys/socket.h>
21 #include <netdb.h>
22
23 /*
24 * static prototypes
25 */
26 static char *tailor_value (unsigned char *);
27 static void getuserinfo (void);
28 static const char *get_mtsconf_pathname(void);
29 static const char *get_mtsuserconf_pathname(void);
30 static void mts_read_conf_file (FILE *fp);
31
32 /*
33 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
34 * are kept in the user's home directory, then these should be empty
35 * strings. In this case, the appropriate ...lfil array should contain
36 * the name of the file in the user's home directory. Usually, this is
37 * something like ".mail".
38 */
39
40 /*
41 * nmh mail transport interface customization file
42 */
43 static char *mtsconf = nmhetcdir(/mts.conf);
44
45 static char *localname = "";
46 static char *localdomain = "";
47 static char *systemname = "";
48
49 char *mmdfldir = MAILSPOOL;
50 char *mmdflfil = "";
51 char *uucpldir = "/usr/spool/mail";
52 char *uucplfil = "";
53
54 char *mmdlm1 = "\001\001\001\001\n";
55 char *mmdlm2 = "\001\001\001\001\n";
56
57 /* Cache the username and fullname of the user */
58 static char username[BUFSIZ];
59 static char fullname[BUFSIZ];
60
61 /* Variables for username masquerading: */
62 boolean draft_from_masquerading = FALSE; /* also used from post.c */
63 static boolean mmailid_masquerading = FALSE;
64 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
65 static char* masquerade = "";
66
67 /*
68 * MTS specific variables
69 */
70 #if defined(SMTPMTS)
71 static char *sm_method = "smtp";
72 int sm_mts = MTS_SMTP;
73 char *hostable = nmhetcdir(/hosts);
74 char *sendmail = SENDMAILPATH;
75 #endif
76
77 /*
78 * SMTP/POP stuff
79 */
80 char *clientname = NULL;
81 char *servers = "localhost";
82 char *pophost = "";
83
84 /*
85 * Global MailDelivery file
86 */
87 char *maildelivery = nmhetcdir(/maildelivery);
88
89
90 /*
91 * Aliasing Facility (doesn't belong here)
92 */
93 int Everyone = NOTOK;
94 static char *everyone = "-1";
95 char *NoShell = "";
96
97 /*
98 * Customize the MTS settings for nmh by adjusting
99 * the file mts.conf in the nmh etc directory.
100 */
101
102 struct bind {
103 char *keyword;
104 char **value;
105 };
106
107 static struct bind binds[] = {
108 { "localname", &localname },
109 { "localdomain", &localdomain },
110 { "systemname", &systemname },
111 { "mmdfldir", &mmdfldir },
112 { "mmdflfil", &mmdflfil },
113 { "uucpldir", &uucpldir },
114 { "uucplfil", &uucplfil },
115 { "mmdelim1", &mmdlm1 },
116 { "mmdelim2", &mmdlm2 },
117 { "masquerade", &masquerade },
118
119 #if defined(SMTPMTS)
120 { "mts", &sm_method },
121 { "hostable", &hostable },
122 { "sendmail", &sendmail },
123 #endif
124
125 { "clientname", &clientname },
126 { "servers", &servers },
127 { "pophost", &pophost },
128
129 { "maildelivery", &maildelivery },
130 { "everyone", &everyone },
131 { "noshell", &NoShell },
132 { NULL, NULL }
133 };
134
135
136 /*
137 * Read the configuration file for the nmh interface
138 * to the mail transport system (MTS).
139 */
140
141 void
142 mts_init (char *name)
143 {
144 NMH_UNUSED (name);
145
146 const char *cp;
147 FILE *fp;
148 static int inited = 0;
149
150 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
151 return;
152 mts_read_conf_file(fp);
153 fclose (fp);
154
155 cp = get_mtsuserconf_pathname();
156 if (cp != NULL &&
157 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
158 mts_read_conf_file(fp);
159 fclose (fp);
160 }
161
162 Everyone = atoi (everyone);
163
164 if (strstr(masquerade, "draft_from") != NULL)
165 draft_from_masquerading = TRUE;
166
167 if (strstr(masquerade, "mmailid") != NULL)
168 mmailid_masquerading = TRUE;
169
170 if (strstr(masquerade, "username_extension") != NULL)
171 username_extension_masquerading = TRUE;
172
173 #ifdef SMTPMTS
174 if (strcmp(sm_method, "smtp") == 0)
175 sm_mts = MTS_SMTP;
176 else if (strcmp(sm_method, "sendmail") == 0)
177 sm_mts = MTS_SENDMAIL;
178 else {
179 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
180 sm_mts = MTS_SMTP;
181 }
182 #endif
183 }
184
185
186 #define QUOTE '\\'
187
188 /*
189 * Convert escaped values, malloc some new space,
190 * and copy string to malloc'ed memory.
191 */
192
193 static char *
194 tailor_value (unsigned char *s)
195 {
196 int i, r;
197 char *bp;
198 char buffer[BUFSIZ];
199 size_t len;
200
201 for (bp = buffer; *s; bp++, s++) {
202 if (*s != QUOTE) {
203 *bp = *s;
204 } else {
205 switch (*++s) {
206 case 'b': *bp = '\b'; break;
207 case 'f': *bp = '\f'; break;
208 case 'n': *bp = '\n'; break;
209 case 't': *bp = '\t'; break;
210
211 case 0: s--;
212 case QUOTE:
213 *bp = QUOTE;
214 break;
215
216 default:
217 if (!isdigit (*s)) {
218 *bp++ = QUOTE;
219 *bp = *s;
220 }
221 r = *s != '0' ? 10 : 8;
222 for (i = 0; isdigit (*s); s++)
223 i = i * r + *s - '0';
224 s--;
225 *bp = toascii (i);
226 break;
227 }
228 }
229 }
230 *bp = 0;
231
232 len = strlen (buffer) + 1;
233 bp = mh_xmalloc (len);
234 memcpy (bp, buffer, len);
235
236 return bp;
237 }
238
239 /*
240 * Get the fully qualified name of the local host.
241 *
242 * If flag is 0, then use anything out of mts.conf (like localname).
243 * If flag is 1, then only use the "proper" local hostname.
244 */
245
246 char *
247 LocalName (int flag)
248 {
249 static char buffer0[BUFSIZ] = "";
250 static char buffer1[BUFSIZ] = "";
251 static char *buffer[] = { buffer0, buffer1 };
252 char *buf;
253 struct addrinfo hints, *res;
254
255 if (flag < 0 || flag > 1)
256 return NULL;
257
258 buf = buffer[flag];
259
260 /* check if we have cached the local name */
261 if (buf[0])
262 return buf;
263
264 mts_init ("mts");
265
266 /* check if the mts.conf file specifies a "localname" */
267 if (*localname && flag == 0) {
268 strncpy (buf, localname, sizeof(buffer0));
269 } else {
270 memset(buf, 0, sizeof(buffer0));
271 /* first get our local name */
272 gethostname (buf, sizeof(buffer0) - 1);
273 /* now fully qualify our name */
274
275 memset(&hints, 0, sizeof(hints));
276 hints.ai_flags = AI_CANONNAME;
277 hints.ai_family = PF_UNSPEC;
278 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
279 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
280 freeaddrinfo(res);
281 }
282 }
283
284 /*
285 * If the mts.conf file specifies a "localdomain",
286 * we append that now. This should rarely be needed.
287 */
288 if (*localdomain) {
289 strcat (buf, ".");
290 strcat (buf, localdomain);
291 }
292
293 return buf;
294 }
295
296
297 /*
298 * This is only for UUCP mail. It gets the hostname
299 * as part of the UUCP "domain".
300 */
301
302 char *
303 SystemName (void)
304 {
305 static char buffer[BUFSIZ] = "";
306
307 /* check if we have cached the system name */
308 if (buffer[0])
309 return buffer;
310
311 mts_init ("mts");
312
313 /* check if mts.conf file specifies a "systemname" */
314 if (*systemname) {
315 strncpy (buffer, systemname, sizeof(buffer));
316 return buffer;
317 }
318
319 gethostname (buffer, sizeof(buffer));
320
321 return buffer;
322 }
323
324
325 /*
326 * Get the username of current user
327 */
328
329 char *
330 getusername (void)
331 {
332 if (username[0] == '\0')
333 getuserinfo();
334
335 return username;
336 }
337
338
339 /*
340 * Get full name of current user (typically from GECOS
341 * field of password file).
342 */
343
344 char *
345 getfullname (void)
346 {
347 if (username[0] == '\0')
348 getuserinfo();
349
350 return fullname;
351 }
352
353
354 /*
355 * Find the user's username and full name, and cache them.
356 * Also, handle "mmailid" username masquerading controlled from the GECOS field
357 * of the passwd file.
358 */
359
360 static void
361 getuserinfo (void)
362 {
363 register unsigned char *cp;
364 register char *np;
365 register struct passwd *pw;
366
367 if ((pw = getpwuid (getuid ())) == NULL
368 || pw->pw_name == NULL
369 || *pw->pw_name == '\0') {
370 strncpy (username, "unknown", sizeof(username));
371 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
372 (int) getuid ());
373 return;
374 }
375
376 np = pw->pw_gecos;
377
378 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
379 which some OSes use to separate other 'finger' information in the GECOS
380 field, like phone number. Also, if mmailid masquerading is turned on due
381 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
382 hit a '<' (which should precede any ','s). */
383 if (mmailid_masquerading)
384 /* Stop at ',' or '<'. */
385 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
386 *cp++ = *np++)
387 continue;
388 else
389 /* Allow '<' as a legal character of the user's name. This code is
390 basically a duplicate of the code above the "else" -- we don't
391 collapse it down to one copy and put the mmailid_masquerading check
392 inside the loop with "(x ? y : z)" because that's inefficient and the
393 value'll never change while it's in there. */
394 for (cp = fullname; *np != '\0' && *np != ',';
395 *cp++ = *np++)
396 continue;
397 *cp = '\0';
398
399 if (mmailid_masquerading) {
400 /* Do mmailid processing. The GECOS field should have the form
401 "Full Name <fakeusername>". For instance,
402 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
403 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
404 account name. */
405 if (*np)
406 np++;
407 for (cp = username; *np && *np != '>'; *cp++ = *np++)
408 continue;
409 *cp = '\0';
410 }
411 if (!mmailid_masquerading || *np == '\0')
412 strncpy (username, pw->pw_name, sizeof(username));
413
414 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
415 your real name. */
416 if ((cp = getenv ("SIGNATURE")) && *cp)
417 strncpy (fullname, cp, sizeof(fullname));
418
419 if (strchr(fullname, '.')) { /* quote any .'s */
420 char tmp[BUFSIZ];
421
422 /* should quote "'s too */
423 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
424 strncpy (fullname, tmp, sizeof(fullname));
425 }
426
427 return;
428 }
429
430 static const char*
431 get_mtsconf_pathname (void)
432 {
433 const char *cp = getenv ( "MHMTSCONF ");
434 if (cp != NULL && *cp != '\0') {
435 return cp;
436 }
437 return mtsconf;
438 }
439
440 static const char*
441 get_mtsuserconf_pathname (void)
442 {
443 const char *cp = getenv ( "MHMTSUSERCONF" );
444 if (cp != NULL && *cp != '\0') {
445 return cp;
446 }
447 return NULL;
448 }
449
450 static void
451 mts_read_conf_file (FILE *fp)
452 {
453 unsigned char *bp;
454 char *cp, buffer[BUFSIZ];
455 struct bind *b;
456
457 while (fgets (buffer, sizeof(buffer), fp)) {
458 if (!(cp = strchr(buffer, '\n')))
459 break;
460 *cp = 0;
461 if (*buffer == '#' || *buffer == '\0')
462 continue;
463 if (!(bp = strchr(buffer, ':')))
464 break;
465 *bp++ = 0;
466 while (isspace (*bp))
467 *bp++ = 0;
468
469 for (b = binds; b->keyword; b++)
470 if (!strcmp (buffer, b->keyword))
471 break;
472 if (b->keyword && (cp = tailor_value (bp)))
473 *b->value = cp;
474 }
475 }