]> diplodocus.org Git - nmh/blob - sbr/mts.c
Fix a segfault that happens when using the -file option.
[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 /*
24 * static prototypes
25 */
26 static char *tailor_value (unsigned char *);
27 static void getuserinfo (void);
28 static const char *get_mtsconf_pathname(void);
29 static const char *get_mtsuserconf_pathname(void);
30 static void mts_read_conf_file (FILE *fp);
31
32 /*
33 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
34 * are kept in the user's home directory, then these should be empty
35 * strings. In this case, the appropriate ...lfil array should contain
36 * the name of the file in the user's home directory. Usually, this is
37 * something like ".mail".
38 */
39
40 /*
41 * nmh mail transport interface customization file
42 */
43 static char *mtsconf = nmhetcdir(/mts.conf);
44
45 static char *localname = "";
46 static char *localdomain = "";
47 static char *systemname = "";
48
49 char *mmdfldir = MAILSPOOL;
50 char *mmdflfil = "";
51 char *uucpldir = "/usr/spool/mail";
52 char *uucplfil = "";
53
54 char *mmdlm1 = "\001\001\001\001\n";
55 char *mmdlm2 = "\001\001\001\001\n";
56
57 /* Cache the username, fullname, and mailbox of the user */
58 static char username[BUFSIZ];
59 static char fullname[BUFSIZ];
60 static char localmbox[BUFSIZ];
61
62 /* Variables for username masquerading: */
63 boolean draft_from_masquerading = FALSE; /* also used from post.c */
64 static boolean mmailid_masquerading = FALSE;
65 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
66 static char* masquerade = "";
67
68 /*
69 * MTS specific variables
70 */
71 #if defined(SMTPMTS)
72 static char *sm_method = "smtp";
73 int sm_mts = MTS_SMTP;
74 char *hostable = nmhetcdir(/hosts);
75 char *sendmail = SENDMAILPATH;
76 #endif
77
78 /*
79 * SMTP/POP stuff
80 */
81 char *clientname = NULL;
82 char *servers = "localhost";
83 char *pophost = "";
84
85 /*
86 * Global MailDelivery file
87 */
88 char *maildelivery = nmhetcdir(/maildelivery);
89
90
91 /*
92 * Aliasing Facility (doesn't belong here)
93 */
94 int Everyone = NOTOK;
95 static char *everyone = "-1";
96 char *NoShell = "";
97
98 /*
99 * Customize the MTS settings for nmh by adjusting
100 * the file mts.conf in the nmh etc directory.
101 */
102
103 struct bind {
104 char *keyword;
105 char **value;
106 };
107
108 static struct bind binds[] = {
109 { "localname", &localname },
110 { "localdomain", &localdomain },
111 { "systemname", &systemname },
112 { "mmdfldir", &mmdfldir },
113 { "mmdflfil", &mmdflfil },
114 { "uucpldir", &uucpldir },
115 { "uucplfil", &uucplfil },
116 { "mmdelim1", &mmdlm1 },
117 { "mmdelim2", &mmdlm2 },
118 { "masquerade", &masquerade },
119
120 #if defined(SMTPMTS)
121 { "mts", &sm_method },
122 { "hostable", &hostable },
123 { "sendmail", &sendmail },
124 #endif
125
126 { "clientname", &clientname },
127 { "servers", &servers },
128 { "pophost", &pophost },
129
130 { "maildelivery", &maildelivery },
131 { "everyone", &everyone },
132 { "noshell", &NoShell },
133 { NULL, NULL }
134 };
135
136
137 /*
138 * Read the configuration file for the nmh interface
139 * to the mail transport system (MTS).
140 */
141
142 void
143 mts_init (char *name)
144 {
145 NMH_UNUSED (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 * If flag is 0, then use anything out of mts.conf (like localname).
244 * If flag is 1, then only use the "proper" local hostname.
245 */
246
247 char *
248 LocalName (int flag)
249 {
250 static char buffer0[BUFSIZ] = "";
251 static char buffer1[BUFSIZ] = "";
252 static char *buffer[] = { buffer0, buffer1 };
253 char *buf;
254 struct addrinfo hints, *res;
255
256 if (flag < 0 || flag > 1)
257 return NULL;
258
259 buf = buffer[flag];
260
261 /* check if we have cached the local name */
262 if (buf[0])
263 return buf;
264
265 mts_init ("mts");
266
267 /* check if the mts.conf file specifies a "localname" */
268 if (*localname && flag == 0) {
269 strncpy (buf, localname, sizeof(buffer0));
270 } else {
271 memset(buf, 0, sizeof(buffer0));
272 /* first get our local name */
273 gethostname (buf, sizeof(buffer0) - 1);
274 /* now fully qualify our name */
275
276 memset(&hints, 0, sizeof(hints));
277 hints.ai_flags = AI_CANONNAME;
278 hints.ai_family = PF_UNSPEC;
279 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
280 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
281 freeaddrinfo(res);
282 }
283 }
284
285 /*
286 * If the mts.conf file specifies a "localdomain",
287 * we append that now. This should rarely be needed.
288 */
289 if (*localdomain) {
290 strcat (buf, ".");
291 strcat (buf, localdomain);
292 }
293
294 return buf;
295 }
296
297
298 /*
299 * This is only for UUCP mail. It gets the hostname
300 * as part of the UUCP "domain".
301 */
302
303 char *
304 SystemName (void)
305 {
306 static char buffer[BUFSIZ] = "";
307
308 /* check if we have cached the system name */
309 if (buffer[0])
310 return buffer;
311
312 mts_init ("mts");
313
314 /* check if mts.conf file specifies a "systemname" */
315 if (*systemname) {
316 strncpy (buffer, systemname, sizeof(buffer));
317 return buffer;
318 }
319
320 gethostname (buffer, sizeof(buffer));
321
322 return buffer;
323 }
324
325
326 /*
327 * Get the username of current user
328 */
329
330 char *
331 getusername (void)
332 {
333 if (username[0] == '\0')
334 getuserinfo();
335
336 return username;
337 }
338
339
340 /*
341 * Get full name of current user (typically from GECOS
342 * field of password file).
343 */
344
345 char *
346 getfullname (void)
347 {
348 if (username[0] == '\0')
349 getuserinfo();
350
351 return fullname;
352 }
353
354
355 /*
356 * Get the full local mailbox name. This is in the form:
357 *
358 * User Name <user@name.com>
359 */
360
361 char *
362 getlocalmbox (void)
363 {
364 if (username[0] == '\0')
365 getuserinfo();
366
367 if (localmbox[0] == '\0') {
368 char *cp;
369
370 if ((cp = context_find("Local-Mailbox")) != NULL) {
371 strncpy(localmbox, cp, sizeof(localmbox));
372 } else {
373 snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
374 username, LocalName(0));
375 }
376
377 localmbox[sizeof(localmbox) - 1] = '\0';
378 }
379
380 return localmbox;
381 }
382
383 /*
384 * Find the user's username and full name, and cache them.
385 * Also, handle "mmailid" username masquerading controlled from the GECOS field
386 * of the passwd file.
387 */
388
389 static void
390 getuserinfo (void)
391 {
392 register unsigned char *cp;
393 register char *np;
394 register struct passwd *pw;
395
396 if ((pw = getpwuid (getuid ())) == NULL
397 || pw->pw_name == NULL
398 || *pw->pw_name == '\0') {
399 strncpy (username, "unknown", sizeof(username));
400 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
401 (int) getuid ());
402 return;
403 }
404
405 np = pw->pw_gecos;
406
407 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
408 which some OSes use to separate other 'finger' information in the GECOS
409 field, like phone number. Also, if mmailid masquerading is turned on due
410 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
411 hit a '<' (which should precede any ','s). */
412 if (mmailid_masquerading)
413 /* Stop at ',' or '<'. */
414 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
415 *cp++ = *np++)
416 continue;
417 else
418 /* Allow '<' as a legal character of the user's name. This code is
419 basically a duplicate of the code above the "else" -- we don't
420 collapse it down to one copy and put the mmailid_masquerading check
421 inside the loop with "(x ? y : z)" because that's inefficient and the
422 value'll never change while it's in there. */
423 for (cp = fullname; *np != '\0' && *np != ',';
424 *cp++ = *np++)
425 continue;
426 *cp = '\0';
427
428 if (mmailid_masquerading) {
429 /* Do mmailid processing. The GECOS field should have the form
430 "Full Name <fakeusername>". For instance,
431 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
432 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
433 account name. */
434 if (*np)
435 np++;
436 for (cp = username; *np && *np != '>'; *cp++ = *np++)
437 continue;
438 *cp = '\0';
439 }
440 if (!mmailid_masquerading || *np == '\0')
441 strncpy (username, pw->pw_name, sizeof(username));
442
443 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
444 your real name. If SIGNATURE isn't set, use the Signature profile
445 setting if it exists. */
446 if ((cp = getenv ("SIGNATURE")) && *cp)
447 strncpy (fullname, cp, sizeof(fullname));
448 else if ((cp = context_find("Signature")))
449 strncpy (fullname, cp, sizeof(fullname));
450
451 if (strchr(fullname, '.')) { /* quote any .'s */
452 char tmp[BUFSIZ];
453
454 /* should quote "'s too */
455 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
456 strncpy (fullname, tmp, sizeof(fullname));
457 }
458
459 fullname[sizeof(fullname) - 1] = '\0';
460
461 localmbox[0] = '\0';
462
463 return;
464 }
465
466 static const char*
467 get_mtsconf_pathname (void)
468 {
469 const char *cp = getenv ( "MHMTSCONF" );
470 if (cp != NULL && *cp != '\0') {
471 return cp;
472 }
473 return mtsconf;
474 }
475
476 static const char*
477 get_mtsuserconf_pathname (void)
478 {
479 const char *cp = getenv ( "MHMTSUSERCONF" );
480 if (cp != NULL && *cp != '\0') {
481 return cp;
482 }
483 return NULL;
484 }
485
486 static void
487 mts_read_conf_file (FILE *fp)
488 {
489 unsigned char *bp;
490 char *cp, buffer[BUFSIZ];
491 struct bind *b;
492
493 while (fgets (buffer, sizeof(buffer), fp)) {
494 if (!(cp = strchr(buffer, '\n')))
495 break;
496 *cp = 0;
497 if (*buffer == '#' || *buffer == '\0')
498 continue;
499 if (!(bp = strchr(buffer, ':')))
500 break;
501 *bp++ = 0;
502 while (isspace (*bp))
503 *bp++ = 0;
504
505 for (b = binds; b->keyword; b++)
506 if (!strcmp (buffer, b->keyword))
507 break;
508 if (b->keyword && (cp = tailor_value (bp)))
509 *b->value = cp;
510 }
511 }