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