]> diplodocus.org Git - nmh/blob - sbr/mts.c
* uip/new.c: cast folder_len to int to avoid warning on
[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 #include <h/utils.h>
15
16 #define nmhetcdir(file) NMHETCDIR#file
17
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <h/mts.h>
21 #include <pwd.h>
22 #include <netdb.h>
23
24 #ifdef HAVE_SYS_UTSNAME_H
25 # include <sys/utsname.h>
26 #endif
27
28 #define NOTOK (-1)
29 #define OK 0
30
31 /*
32 * static prototypes
33 */
34 static char *tailor_value (unsigned char *);
35 static void getuserinfo (void);
36
37 /*
38 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
39 * are kept in the user's home directory, then these should be empty
40 * strings. In this case, the appropriate ...lfil array should contain
41 * the name of the file in the user's home directory. Usually, this is
42 * something like ".mail".
43 */
44
45 /*
46 * nmh mail transport interface customization file
47 */
48 static char *mtsconf = nmhetcdir(/mts.conf);
49
50 static char *localname = "";
51 static char *localdomain = "";
52 static char *systemname = "";
53
54 char *mmdfldir = MAILSPOOL;
55 char *mmdflfil = "";
56 char *uucpldir = "/usr/spool/mail";
57 char *uucplfil = "";
58
59 char *mmdlm1 = "\001\001\001\001\n";
60 char *mmdlm2 = "\001\001\001\001\n";
61
62 /* Cache the username and fullname of the user */
63 static char username[BUFSIZ];
64 static char fullname[BUFSIZ];
65
66 /* Variables for username masquerading: */
67 boolean draft_from_masquerading = FALSE; /* also used from post.c */
68 static boolean mmailid_masquerading = FALSE;
69 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
70 static char* masquerade = "";
71
72 /*
73 * MTS specific variables
74 */
75 #if defined(SMTPMTS)
76 static char *sm_method = "smtp";
77 int sm_mts = MTS_SMTP;
78 char *hostable = nmhetcdir(/hosts);
79 char *sendmail = SENDMAILPATH;
80 #endif
81
82 /*
83 * SMTP/POP stuff
84 */
85 char *clientname = NULL;
86 char *servers = "localhost \01localnet";
87 char *pophost = "";
88
89 /*
90 * BBoards-specific variables
91 */
92 char *bb_domain = "";
93
94
95 /*
96 * POP BBoards-specific variables
97 */
98 #ifdef BPOP
99 char *popbbhost = "";
100 char *popbbuser = "";
101 char *popbblist = nmhetcdir(/hosts.popbb);
102 #endif /* BPOP */
103
104 /*
105 * Global MailDelivery file
106 */
107 char *maildelivery = nmhetcdir(/maildelivery);
108
109
110 /*
111 * Aliasing Facility (doesn't belong here)
112 */
113 int Everyone = NOTOK;
114 static char *everyone = "-1";
115 char *NoShell = "";
116
117 /*
118 * Customize the MTS settings for nmh by adjusting
119 * the file mts.conf in the nmh etc directory.
120 */
121
122 struct bind {
123 char *keyword;
124 char **value;
125 };
126
127 static struct bind binds[] = {
128 { "localname", &localname },
129 { "localdomain", &localdomain },
130 { "systemname", &systemname },
131 { "mmdfldir", &mmdfldir },
132 { "mmdflfil", &mmdflfil },
133 { "uucpldir", &uucpldir },
134 { "uucplfil", &uucplfil },
135 { "mmdelim1", &mmdlm1 },
136 { "mmdelim2", &mmdlm2 },
137 { "masquerade", &masquerade },
138
139 #if defined(SMTPMTS)
140 { "mts", &sm_method },
141 { "hostable", &hostable },
142 { "sendmail", &sendmail },
143 #endif
144
145 { "clientname", &clientname },
146 { "servers", &servers },
147 { "pophost", &pophost },
148 { "bbdomain", &bb_domain },
149
150 #ifdef BPOP
151 { "popbbhost", &popbbhost },
152 { "popbbuser", &popbbuser },
153 { "popbblist", &popbblist },
154 #endif
155
156 #ifdef NNTP
157 { "nntphost", &popbbhost },
158 #endif
159
160 { "maildelivery", &maildelivery },
161 { "everyone", &everyone },
162 { "noshell", &NoShell },
163 { NULL, NULL }
164 };
165
166
167 /*
168 * Read the configuration file for the nmh interface
169 * to the mail transport system (MTS).
170 */
171
172 void
173 mts_init (char *name)
174 {
175 unsigned char *bp;
176 char *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 (unsigned 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 bp = mh_xmalloc (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 addrinfo hints, *res;
291 #ifdef HAVE_UNAME
292 struct utsname name;
293 #endif
294
295 /* check if we have cached the local name */
296 if (buffer[0])
297 return buffer;
298
299 mts_init ("mts");
300
301 /* check if the mts.conf file specifies a "localname" */
302 if (*localname) {
303 strncpy (buffer, localname, sizeof(buffer));
304 } else {
305 memset(buffer, 0, sizeof(buffer));
306 #ifdef HAVE_UNAME
307 /* first get our local name */
308 uname (&name);
309 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
310 #else
311 /* first get our local name */
312 gethostname (buffer, sizeof(buffer) - 1);
313 #endif
314 /* now fully qualify our name */
315
316 memset(&hints, 0, sizeof(hints));
317 hints.ai_flags = AI_CANONNAME;
318 hints.ai_family = PF_UNSPEC;
319 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
320 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
321 freeaddrinfo(res);
322 }
323 }
324
325 /*
326 * If the mts.conf file specifies a "localdomain",
327 * we append that now. This should rarely be needed.
328 */
329 if (*localdomain) {
330 strcat (buffer, ".");
331 strcat (buffer, localdomain);
332 }
333
334 return buffer;
335 }
336
337
338 /*
339 * This is only for UUCP mail. It gets the hostname
340 * as part of the UUCP "domain".
341 */
342
343 char *
344 SystemName (void)
345 {
346 static char buffer[BUFSIZ] = "";
347
348 #ifdef HAVE_UNAME
349 struct utsname name;
350 #endif
351
352 /* check if we have cached the system name */
353 if (buffer[0])
354 return buffer;
355
356 mts_init ("mts");
357
358 /* check if mts.conf file specifies a "systemname" */
359 if (*systemname) {
360 strncpy (buffer, systemname, sizeof(buffer));
361 return buffer;
362 }
363
364 #ifdef HAVE_UNAME
365 uname (&name);
366 strncpy (buffer, name.nodename, sizeof(buffer));
367 #else
368 gethostname (buffer, sizeof(buffer));
369 #endif
370
371 return buffer;
372 }
373
374
375 /*
376 * Get the username of current user
377 */
378
379 char *
380 getusername (void)
381 {
382 if (username[0] == '\0')
383 getuserinfo();
384
385 return username;
386 }
387
388
389 /*
390 * Get full name of current user (typically from GECOS
391 * field of password file).
392 */
393
394 char *
395 getfullname (void)
396 {
397 if (username[0] == '\0')
398 getuserinfo();
399
400 return fullname;
401 }
402
403
404 /*
405 * Find the user's username and full name, and cache them.
406 * Also, handle "mmailid" username masquerading controlled from the GECOS field
407 * of the passwd file.
408 */
409
410 static void
411 getuserinfo (void)
412 {
413 register unsigned char *cp;
414 register char *np;
415 register struct passwd *pw;
416
417 #ifdef KPOP
418 uid_t uid;
419
420 uid = getuid ();
421 if (uid == geteuid () && (cp = getenv ("USER")) != NULL
422 && (pw = getpwnam (cp)) != NULL)
423 strncpy (username, cp, sizeof(username));
424 else if ((pw = getpwuid (uid)) == NULL
425 || pw->pw_name == NULL
426 || *pw->pw_name == '\0') {
427 #else /* KPOP */
428 if ((pw = getpwuid (getuid ())) == NULL
429 || pw->pw_name == NULL
430 || *pw->pw_name == '\0') {
431 #endif /* KPOP */
432 strncpy (username, "unknown", sizeof(username));
433 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
434 (int) getuid ());
435 return;
436 }
437
438 np = pw->pw_gecos;
439
440 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
441 which some OSes use to separate other 'finger' information in the GECOS
442 field, like phone number. Also, if mmailid masquerading is turned on due
443 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
444 hit a '<' (which should precede any ','s). */
445 #ifndef BSD42
446 if (mmailid_masquerading)
447 /* Stop at ',' or '<'. */
448 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
449 *cp++ = *np++)
450 continue;
451 else
452 /* Allow '<' as a legal character of the user's name. This code is
453 basically a duplicate of the code above the "else" -- we don't
454 collapse it down to one copy and put the mmailid_masquerading check
455 inside the loop with "(x ? y : z)" because that's inefficient and the
456 value'll never change while it's in there. */
457 for (cp = fullname; *np != '\0' && *np != ',';
458 *cp++ = *np++)
459 continue;
460 #else /* BSD42 */
461 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
462 field (finger, mail, sendmail, etc.) translate any '&' character in it to
463 the login name, with the first letter capitalized. So, for instance,
464 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
465 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
466 the translation for you, so we have to do it manually here. */
467 if (mmailid_masquerading)
468 /* Stop at ',' or '<'. */
469 for (cp = fullname;
470 *np != '\0' && *np != ',' && *np != '<';) {
471 if (*np == '&') { /* blech! */
472 strcpy (cp, pw->pw_name);
473 *cp = toupper(*cp);
474 while (*cp)
475 cp++;
476 np++;
477 } else {
478 *cp++ = *np++;
479 }
480 }
481 else
482 /* Allow '<' as a legal character of the user's name. This code is
483 basically a duplicate of the code above the "else" -- we don't
484 collapse it down to one copy and put the mmailid_masquerading check
485 inside the loop with "(x ? y : z)" because that's inefficient and the
486 value'll never change while it's in there. */
487 for (cp = fullname;
488 *np != '\0' && *np != ',';) {
489 if (*np == '&') { /* blech! */
490 strcpy (cp, pw->pw_name);
491 *cp = toupper(*cp);
492 while (*cp)
493 cp++;
494 np++;
495 } else {
496 *cp++ = *np++;
497 }
498 }
499 #endif /* BSD42 */
500 *cp = '\0';
501
502 if (mmailid_masquerading) {
503 /* Do mmailid processing. The GECOS field should have the form
504 "Full Name <fakeusername>". For instance,
505 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
506 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
507 account name. */
508 if (*np)
509 np++;
510 for (cp = username; *np && *np != '>'; *cp++ = *np++)
511 continue;
512 *cp = '\0';
513 }
514 if (!mmailid_masquerading || *np == '\0')
515 strncpy (username, pw->pw_name, sizeof(username));
516
517 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
518 your real name. */
519 if ((cp = getenv ("SIGNATURE")) && *cp)
520 strncpy (fullname, cp, sizeof(fullname));
521
522 if (strchr(fullname, '.')) { /* quote any .'s */
523 char tmp[BUFSIZ];
524
525 /* should quote "'s too */
526 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
527 strncpy (fullname, tmp, sizeof(fullname));
528 }
529
530 return;
531 }