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