Remove OS-specific defines. As part of it, remove scary longjmp() inside
[mmh] / 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     if (mmailid_masquerading)
374         /* Stop at ',' or '<'. */
375         for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
376              *cp++ = *np++)
377             continue;
378     else
379         /* Allow '<' as a legal character of the user's name.  This code is
380            basically a duplicate of the code above the "else" -- we don't
381            collapse it down to one copy and put the mmailid_masquerading check
382            inside the loop with "(x ? y : z)" because that's inefficient and the
383            value'll never change while it's in there. */
384         for (cp = fullname; *np != '\0' && *np != ',';
385              *cp++ = *np++)
386             continue;
387     *cp = '\0';
388
389     if (mmailid_masquerading) {
390         /* Do mmailid processing.  The GECOS field should have the form
391            "Full Name <fakeusername>".  For instance,
392            "Dan Harkless <Dan.Harkless>".  Naturally, you'll want your MTA to
393            have an alias (e.g. in /etc/aliases) from "fakeusername" to your
394            account name.  */ 
395         if (*np)
396             np++;
397         for (cp = username; *np && *np != '>'; *cp++ = *np++)
398             continue;
399         *cp = '\0';
400     }
401     if (!mmailid_masquerading || *np == '\0')
402         strncpy (username, pw->pw_name, sizeof(username));
403
404     /* The $SIGNATURE environment variable overrides the GECOS field's idea of
405        your real name. */
406     if ((cp = getenv ("SIGNATURE")) && *cp)
407         strncpy (fullname, cp, sizeof(fullname));
408
409     if (strchr(fullname, '.')) {                /*  quote any .'s */
410         char tmp[BUFSIZ];
411
412         /* should quote "'s too */
413         snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
414         strncpy (fullname, tmp, sizeof(fullname));
415     }
416
417     return;
418 }
419
420 static const char*
421 get_mtsconf_pathname (void)
422 {
423     const char *cp = getenv ( "MHMTSCONF ");
424     if (cp != NULL && *cp != '\0') {
425         return cp;
426     }
427     return mtsconf;
428 }
429
430 static const char*
431 get_mtsuserconf_pathname (void)
432 {
433     const char *cp = getenv ( "MHMTSUSERCONF" );
434     if (cp != NULL && *cp != '\0') {
435         return cp;
436     }
437     return NULL;
438 }
439
440 static void
441 mts_read_conf_file (FILE *fp)
442 {
443     unsigned char *bp;
444     char *cp, buffer[BUFSIZ];
445     struct bind *b;
446
447     while (fgets (buffer, sizeof(buffer), fp)) {
448         if (!(cp = strchr(buffer, '\n')))
449             break;
450         *cp = 0;
451         if (*buffer == '#' || *buffer == '\0')
452             continue;
453         if (!(bp = strchr(buffer, ':')))
454             break;
455         *bp++ = 0;
456         while (isspace (*bp))
457             *bp++ = 0;
458
459         for (b = binds; b->keyword; b++)
460             if (!strcmp (buffer, b->keyword))
461                 break;
462         if (b->keyword && (cp = tailor_value (bp)))
463             *b->value = cp;
464     }
465 }