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