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