Removed draft_from masquerading.
[mmh] / sbr / mts.c
1 /*
2 ** mts.c -- definitions for the mail transport system
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>   /* for snprintf() */
10 #include <h/nmh.h>
11 #include <h/utils.h>
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <h/mts.h>
15 #include <pwd.h>
16 #include <netdb.h>
17
18 #ifdef HAVE_SYS_UTSNAME_H
19 # include <sys/utsname.h>
20 #endif
21
22 #define NOTOK  (-1)
23 #define OK     0
24
25 /*
26 ** static prototypes
27 */
28 static char *tailor_value(unsigned char *);
29 static void getuserinfo(void);
30 static const char *get_mtsconf_pathname(void);
31 static const char *get_mtsuserconf_pathname(void);
32 static void mts_read_conf_file(FILE *fp);
33
34 /*
35 ** nmh mail transport interface customization file
36 */
37 static char *mtsconf = NMHETCDIR"/mts.conf";
38
39
40 /* Cache the username and fullname of the user */
41 static char username[BUFSIZ];
42 static char fullname[BUFSIZ];
43
44 /* Variables for username masquerading: */
45 boolean  username_extension_masquerading = FALSE;  /* " from addrsbr.c */
46 static char* masquerade = "";
47
48 /*
49 ** Global MailDelivery file
50 */
51 char *maildelivery = NMHETCDIR"/maildelivery";
52
53 /*
54 ** Customize the MTS settings for nmh by adjusting
55 ** the file mts.conf in the nmh etc directory.
56 */
57
58 struct bind {
59         char *keyword;
60         char **value;
61 };
62
63 static struct bind binds[] = {
64         { "masquerade", &masquerade },
65         { "maildelivery", &maildelivery },
66         { NULL, NULL }
67 };
68
69
70 /*
71 ** Read the configuration file for the nmh interface
72 ** to the mail transport system (MTS).
73 */
74
75 void
76 mts_init(char *name)
77 {
78         const char *cp;
79         FILE *fp;
80         static int inited = 0;
81
82         if (inited++ || (fp = fopen(get_mtsconf_pathname(), "r")) == NULL)
83                 return;
84         mts_read_conf_file(fp);
85         fclose(fp);
86
87         cp = get_mtsuserconf_pathname();
88         if (cp != NULL &&
89                 ((fp = fopen(get_mtsuserconf_pathname(), "r")) != NULL)) {
90                 mts_read_conf_file(fp);
91                 fclose(fp);
92         }
93
94         if (strstr(masquerade, "username_extension") != NULL)
95                 username_extension_masquerading = TRUE;
96 }
97
98
99 #define QUOTE  '\\'
100
101 /*
102 ** Convert escaped values, malloc some new space,
103 ** and copy string to malloc'ed memory.
104 */
105
106 static char *
107 tailor_value(unsigned char *s)
108 {
109         int i, r;
110         char *bp;
111         char buffer[BUFSIZ];
112         size_t len;
113
114         for (bp = buffer; *s; bp++, s++) {
115                 if (*s != QUOTE) {
116                         *bp = *s;
117                 } else {
118                         switch (*++s) {
119                         case 'b': *bp = '\b'; break;
120                         case 'f': *bp = '\f'; break;
121                         case 'n': *bp = '\n'; break;
122                         case 't': *bp = '\t'; break;
123
124                         case 0: s--;
125                         case QUOTE:
126                                 *bp = QUOTE;
127                                 break;
128
129                         default:
130                                 if (!isdigit(*s)) {
131                                         *bp++ = QUOTE;
132                                         *bp = *s;
133                                 }
134                                 r = *s != '0' ? 10 : 8;
135                                 for (i = 0; isdigit(*s); s++)
136                                         i = i * r + *s - '0';
137                                 s--;
138                                 *bp = toascii(i);
139                                 break;
140                         }
141                 }
142         }
143         *bp = 0;
144
145         len = strlen(buffer) + 1;
146         bp = mh_xmalloc(len);
147         memcpy(bp, buffer, len);
148
149         return bp;
150 }
151
152 /*
153 ** Get the fully qualified name of the local host.
154 */
155
156 char *
157 LocalName(void)
158 {
159         static char buffer[BUFSIZ] = "";
160         struct addrinfo hints, *res;
161 #ifdef HAVE_UNAME
162         struct utsname name;
163 #endif
164
165         /* check if we have cached the local name */
166         if (buffer[0])
167                 return buffer;
168
169         mts_init("mts");
170
171         memset(buffer, 0, sizeof(buffer));
172 #ifdef HAVE_UNAME
173         /* first get our local name */
174         uname(&name);
175         strncpy(buffer, name.nodename, sizeof(buffer) - 1);
176 #else
177         /* first get our local name */
178         gethostname(buffer, sizeof(buffer) - 1);
179 #endif
180         /* now fully qualify our name */
181
182         memset(&hints, 0, sizeof(hints));
183         hints.ai_flags = AI_CANONNAME;
184         hints.ai_family = PF_UNSPEC;
185         if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
186                 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
187                 freeaddrinfo(res);
188         }
189
190         return buffer;
191 }
192
193
194 /*
195 ** This is only for UUCP mail.  It gets the hostname
196 ** as part of the UUCP "domain".
197 */
198
199 char *
200 SystemName(void)
201 {
202         static char buffer[BUFSIZ] = "";
203
204 #ifdef HAVE_UNAME
205         struct utsname name;
206 #endif
207
208         /* check if we have cached the system name */
209         if (buffer[0])
210                 return buffer;
211
212         mts_init("mts");
213
214 #ifdef HAVE_UNAME
215         uname(&name);
216         strncpy(buffer, name.nodename, sizeof(buffer));
217 #else
218         gethostname(buffer, sizeof(buffer));
219 #endif
220
221         return buffer;
222 }
223
224
225 /*
226 ** Get the username of current user
227 */
228
229 char *
230 getusername(void)
231 {
232         if (username[0] == '\0')
233                 getuserinfo();
234
235         return username;
236 }
237
238
239 /*
240 ** Get full name of current user (typically from GECOS
241 ** field of password file).
242 */
243
244 char *
245 getfullname(void)
246 {
247         if (username[0] == '\0')
248                 getuserinfo();
249
250         return fullname;
251 }
252
253
254 /*
255 ** Find the user's username and full name, and cache them.
256 */
257 static void
258 getuserinfo(void)
259 {
260         register unsigned char *cp;
261         register char *np;
262         register struct passwd *pw;
263
264         if ((pw = getpwuid(getuid())) == NULL
265                 || pw->pw_name == NULL
266                 || *pw->pw_name == '\0') {
267                 strncpy(username, "unknown", sizeof(username));
268                 snprintf(fullname, sizeof(fullname), "The Unknown User-ID (%d)",
269                         (int) getuid());
270                 return;
271         }
272
273         np = pw->pw_gecos;
274
275         /*
276         ** Get the user's real name from the GECOS field.  Stop once
277         ** we hit a ',', which some OSes use to separate other 'finger'
278         ** information in the GECOS field, like phone number.
279         */
280         for (cp = fullname; *np != '\0' && *np != ',';) {
281 #ifndef BSD42
282                 *cp++ = *np++;
283 #else /* BSD42 */
284                 /*
285                 ** On BSD(-derived) systems, the system utilities that
286                 ** deal with the GECOS field (finger, mail, sendmail,
287                 ** etc.) translate any '&' character in it to the login name,
288                 ** with the first letter capitalized.  So, for instance,
289                 ** fingering a user "bob" with the GECOS field "& Jones"
290                 ** would reveal him to be "In real life: Bob Jones".
291                 ** Surprisingly, though, the OS doesn't do the translation
292                 ** for you, so we have to do it manually here.
293                 */
294                 if (*np == '&') {  /* blech! */
295                         strcpy(cp, pw->pw_name);
296                         *cp = toupper(*cp);
297                         while (*cp)
298                                 cp++;
299                         np++;
300                 } else {
301                         *cp++ = *np++;
302                 }
303 #endif /* BSD42 */
304         }
305         *cp = '\0';
306         strncpy(username, pw->pw_name, sizeof(username));
307
308         /*
309         ** The $SIGNATURE environment variable overrides the GECOS field's
310         ** idea of your real name.
311         */
312         if ((cp = getenv("SIGNATURE")) && *cp)
313                 strncpy(fullname, cp, sizeof(fullname));
314
315         if (strchr(fullname, '.')) {  /*  quote any .'s */
316                 char tmp[BUFSIZ];
317
318                 /* should quote "'s too */
319                 snprintf(tmp, sizeof(tmp), "\"%s\"", fullname);
320                 strncpy(fullname, tmp, sizeof(fullname));
321         }
322
323         return;
324 }
325
326 static const char*
327 get_mtsconf_pathname(void)
328 {
329         const char *cp = getenv( "MHMTSCONF ");
330         if (cp != NULL && *cp != '\0') {
331                 return cp;
332         }
333         return mtsconf;
334 }
335
336 static const char*
337 get_mtsuserconf_pathname(void)
338 {
339         const char *cp = getenv( "MHMTSUSERCONF" );
340         if (cp != NULL && *cp != '\0') {
341                 return cp;
342         }
343         return NULL;
344 }
345
346 static void
347 mts_read_conf_file(FILE *fp)
348 {
349         unsigned char *bp;
350         char *cp, buffer[BUFSIZ];
351         struct bind *b;
352
353         while (fgets(buffer, sizeof(buffer), fp)) {
354                 if (!(cp = strchr(buffer, '\n')))
355                         break;
356                 *cp = 0;
357                 if (*buffer == '#' || *buffer == '\0')
358                         continue;
359                 if (!(bp = strchr(buffer, ':')))
360                         break;
361                 *bp++ = 0;
362                 while (isspace(*bp))
363                         *bp++ = 0;
364
365                 for (b = binds; b->keyword; b++)
366                         if (strcmp(buffer, b->keyword)==0)
367                                 break;
368                 if (b->keyword && (cp = tailor_value(bp)))
369                         *b->value = cp;
370         }
371 }