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