* better checking of STRING members of lists.
* support for canonicalizing KERBEROS members of lists.
* new error reporting interface, for clients that don't want to use
com_err.
* remove potype(), and replace it with mailtype() in mail.c
SRCTOP=@top_srcdir@
BUILDTOP=../..
-OBJS=pobox.o utils.o
+OBJS=error.o mail.o member.o pobox.o utils.o
.c.o:
$(CC) -c $(ALL_CFLAGS) $<
--- /dev/null
+/* $Id$
+ *
+ * mrcl error interface
+ *
+ * Copyright (C) 1999 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <moira.h>
+#include <mrclient.h>
+#include "mrclient-internal.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <com_err.h>
+
+RCSID("$Header$");
+
+static char *mrcl_message = NULL;
+
+void mrcl_set_message(char *fmt, ...)
+{
+ int args, len;
+ char *p;
+ va_list ap;
+
+ free(mrcl_message);
+
+ /* Count "%s"s */
+ for (args = 0, p = strstr(fmt, "%s"); p; p = strstr(p + 2, "%s"))
+ args++;
+
+ /* Measure the output string. */
+ len = strlen(fmt) + 1;
+ va_start(ap, fmt);
+ while (args--)
+ {
+ p = va_arg(ap, char *);
+ len += strlen(p);
+ }
+ va_end(ap);
+
+ /* Malloc and print */
+ mrcl_message = malloc(len);
+ if (mrcl_message)
+ {
+ va_start(ap, fmt);
+ vsprintf(mrcl_message, fmt, ap);
+ va_end(ap);
+ }
+}
+
+char *mrcl_get_message(void)
+{
+ return mrcl_message;
+}
+
+void mrcl_clear_message(void)
+{
+ free(mrcl_message);
+ mrcl_message = NULL;
+}
+
+void mrcl_com_err(char *whoami)
+{
+ if (mrcl_message)
+ com_err(whoami, 0, "%s", mrcl_message);
+}
--- /dev/null
+/* $Id$
+ *
+ * Library-internal routines for categorizing machines in terms
+ * of email.
+ *
+ * Copyright (C) 1999 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <moira.h>
+#include <mrclient.h>
+#include "mrclient-internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+RCSID("$Header$");
+
+static int save_sloc_machine(int argc, char **argv, void *sq);
+static int save_alias_value(int argc, char **argv, void *sq);
+
+/* Given a canonicalized machine name, ask the Moira server if it is of type
+ * POP, LOCAL, or MAILHUB -- if none of those, we assume it's FOREIGN.
+ */
+int mailtype(char *machine)
+{
+ char *name;
+ int status, match = 0;
+ static struct save_queue *pop = NULL, *local = NULL;
+ static struct save_queue *mailhub = NULL, *mailhub_name = NULL;
+ static struct save_queue *imap = NULL,
+
+ mrcl_clear_message();
+
+ /* 1. Check if the machine is an IMAP server. */
+ if (!imap)
+ {
+ char *service = "POSTOFFICE";
+ imap = sq_create();
+ status = mr_query("get_server_locations", 1, &service,
+ save_sloc_machine, imap);
+ if (status && (status != MR_NO_MATCH))
+ {
+ mrcl_set_message("Could not read list of IMAP servers: %s",
+ error_message(status));
+ return MAILTYPE_ERROR;
+ }
+ }
+
+ /* Because of how sq_get_data works, we need to go through the entire
+ * queue even if we find a match, so that it gets reset for the next
+ * call.
+ */
+ while (sq_get_data(imap, &name))
+ {
+ if (!match && !strcasecmp(name, machine))
+ match = 1;
+ }
+
+ if (match)
+ return MAILTYPE_IMAP;
+
+
+ /* 2. Check if the machine is a POP server. */
+ if (!pop)
+ {
+ char *service = "POP";
+ pop = sq_create();
+ status = mr_query("get_server_locations", 1, &service,
+ save_sloc_machine, pop);
+ if (status && (status != MR_NO_MATCH))
+ {
+ mrcl_set_message("Could not read list of POP servers: %s",
+ error_message(status));
+ return MAILTYPE_ERROR;
+ }
+ }
+
+ /* Because of how sq_get_data works, we need to go through the entire
+ * queue even if we find a match, so that it gets reset for the next
+ * call.
+ */
+ while (sq_get_data(pop, &name))
+ {
+ if (!match && !strcasecmp(name, machine))
+ match = 1;
+ }
+ if (match)
+ return MAILTYPE_POP;
+
+
+ /* 3. Check if the machine is "LOCAL". */
+ if (!local)
+ {
+ char *service = "LOCAL";
+ local = sq_create();
+ status = mr_query("get_server_locations", 1, &service,
+ save_sloc_machine, local);
+ if (status && (status != MR_NO_MATCH))
+ {
+ mrcl_set_message("Could not read list of LOCAL servers: %s",
+ error_message(status));
+ return MAILTYPE_ERROR;
+ }
+ }
+
+ while (sq_get_data(local, &name))
+ {
+ if (!match && !strcasecmp(name, machine))
+ match = 1;
+ }
+ if (match)
+ return MAILTYPE_LOCAL;
+
+
+ /* 4. Check if the machine is one of the mailhubs. */
+ if (!mailhub)
+ {
+ char *service = "MAILHUB";
+ mailhub = sq_create();
+ status = mr_query("get_server_locations", 1, &service,
+ save_sloc_machine, mailhub);
+ if (!status || status == MR_NO_MATCH)
+ {
+ service = "NMAILHUB";
+ status = mr_query("get_server_locations", 1, &service,
+ save_sloc_machine, mailhub);
+ }
+
+ if (status && (status != MR_NO_MATCH))
+ {
+ mrcl_set_message("Could not read list of MAILHUB servers: %s",
+ error_message(status));
+ return MAILTYPE_ERROR;
+ }
+
+ }
+
+ while (sq_get_data(mailhub, &name))
+ {
+ if (!match && !strcasecmp(name, machine))
+ match = 1;
+ }
+ if (match)
+ return MAILTYPE_MAILHUB;
+
+
+ /* 5. Check if the machine is one of the external names of the mailhubs. */
+ if (!mailhub_name)
+ {
+ char *argv[3];
+ mailhub_name = sq_create();
+ argv[0] = "mailhub";
+ argv[1] = "TYPE";
+ argv[2] = "*";
+ status = mr_query("get_alias", 3, argv, save_alias_value, mailhub_name);
+ if (status && (status != MR_NO_MATCH))
+ {
+ mrcl_set_message("Could not read list of mailhub names: %s",
+ error_message(status));
+ return MAILTYPE_ERROR;
+ }
+ }
+
+ while (sq_get_data(mailhub_name, &name))
+ {
+ if (!match && !strcasecmp(name, machine))
+ match = 1;
+ }
+ if (match)
+ return MAILTYPE_MAILHUB;
+
+ return MAILTYPE_SMTP;
+}
+
+static int save_sloc_machine(int argc, char **argv, void *sq)
+{
+ sq_save_data(sq, strdup(argv[1]));
+ return MR_CONT;
+}
+
+static int save_alias_value(int argc, char **argv, void *sq)
+{
+ sq_save_data(sq, canonicalize_hostname(strdup(argv[2])));
+ return MR_CONT;
+}
--- /dev/null
+/* $Id$
+ *
+ * Shared routines for playing with list membership.
+ *
+ * Copyright (C) 1999 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <moira.h>
+#include <mrclient.h>
+#include "mrclient-internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <krb.h>
+
+RCSID("$Header$");
+
+static char default_realm[REALM_SZ];
+
+int mrcl_validate_string_member(char *str)
+{
+ char *p, *lname;
+
+ p = strchr(str, '@');
+ if (p)
+ {
+ char *host = canonicalize_hostname(strdup(++p));
+
+ if (mailtype(host) != MAILTYPE_SMTP)
+ {
+ free(host);
+ lname = strdup(str);
+ *strchr(str, '@') = '\0';
+ mrcl_set_message("STRING \"%s\" should be USER or LIST \"%s\" "
+ "because it is a local name.", lname, str);
+ free(lname);
+ return MRCL_REJECT;
+ }
+ free(host);
+ }
+ else if (!strpbrk(str, "%!"))
+ {
+ mrcl_set_message("STRING \"%s\" is not a foreign mail address.\nAdding "
+ "it to a mailing list may cause the list to break.",
+ lname);
+ return MRCL_REJECT;
+ }
+
+ mrcl_clear_message();
+ return MRCL_SUCCESS;
+}
+
+int mrcl_validate_kerberos_member(char *str, char **ret)
+{
+ char *p;
+
+ mrcl_clear_message();
+
+ p = strchr(str, '@');
+ if (!p)
+ {
+ /* An IP address is not a Kerberos principal, but we allow it
+ * for AFS purposes.
+ */
+ if (strtoul(str, &p, 10) < 256 && (*p == '.') &&
+ strtoul(p + 1, &p, 10) < 256 && (*p == '.') &&
+ strtoul(p + 1, &p, 10) < 256 && (*p == '.') &&
+ strtoul(p + 1, &p, 10) < 256 && !*p)
+ {
+ *ret = strdup(str);
+ return MRCL_SUCCESS;
+ }
+
+ if (!*default_realm)
+ krb_get_lrealm(default_realm, 1);
+
+ *ret = malloc(strlen(str) + strlen(default_realm) + 2);
+ sprintf(*ret, "%s@%s", str, default_realm);
+
+ mrcl_set_message("Warning: default realm \"%s\" added to principal "
+ "\"%s\"", default_realm, str);
+ return MRCL_SUCCESS;
+ }
+
+ /* Check capitalization. */
+ *ret = strdup(str);
+ p = strchr(*ret, '@');
+ while (*++p)
+ {
+ if (islower(*p))
+ {
+ *p = toupper(*p);
+ mrcl_set_message("Warning: set realm in \"%s\" to all caps.", *ret);
+ }
+ }
+
+ return MRCL_SUCCESS;
+}
--- /dev/null
+/* $Id$
+ *
+ * Copyright (C) 1999 by the Massachusetts Institute of Technology
+ *
+ */
+
+#ifndef _mrclient_internal_h_
+#define _mrclient_internal_h_
+
+void mrcl_set_message(char *, ...);
+void mrcl_clear_message(void);
+
+enum { MAILTYPE_ERROR, MAILTYPE_IMAP, MAILTYPE_POP,
+ MAILTYPE_LOCAL, MAILTYPE_MAILHUB, MAILTYPE_SMTP };
+int mailtype(char *machine);
+
+#endif /* _mrclient_internal_h_ */
#include <mit-copyright.h>
#include <moira.h>
#include <mrclient.h>
+#include "mrclient-internal.h"
#include <stdio.h>
#include <stdlib.h>
RCSID("$Header$");
-enum { POTYPE_ERROR, POTYPE_POP, POTYPE_LOCAL, POTYPE_MAILHUB, POTYPE_SMTP, POTYPE_IMAP };
-static int potype(char *machine);
static int save_sloc_machine(int argc, char **argv, void *sq);
static int save_alias_value(int argc, char **argv, void *sq);
}
else
{
- com_err(whoami, 0, "No at sign (@) in address \"%s\".", p);
+ mrcl_set_message("No at sign (@) in address \"%s\".", p);
status = MRCL_REJECT;
goto cleanup;
}
}
else
{
- com_err(whoami, 0, "No hostname in address \"%s@\".", p);
+ mrcl_set_message("No hostname in address \"%s@\".", p);
status = MRCL_REJECT;
goto cleanup;
}
- switch (potype(machine))
+ switch (mailtype(machine))
{
- case POTYPE_IMAP:
- com_err(whoami, 0, "Cannot forward mail to IMAP server %s",
- machine);
- com_err(NULL, 0, "Use \"chpobox -p\" if you are trying to unset "
- "your mail forwarding.");
+ case MAILTYPE_IMAP:
+ mrcl_set_message("Cannot forward mail to IMAP server %s.\n "
+ "Use \"chpobox -p\" if you are trying to unset "
+ "your mail forwarding.", machine);
status = MRCL_REJECT;
goto cleanup;
- case POTYPE_POP:
+ case MAILTYPE_POP:
if (strcmp(p, user))
{
- com_err(whoami, 0, "The name on the POP box (%s) must match "
- "the username (%s).", p, user);
+ mrcl_set_message("The name on the POP box (%s) must match "
+ "the username (%s).", p, user);
status = MRCL_REJECT;
goto cleanup;
}
/* Fall through */
- case POTYPE_LOCAL:
+ case MAILTYPE_LOCAL:
if ((m = strchr(machine, '.')))
*m = '\0';
machine = realloc(machine, strlen(machine) + 6);
strcat(machine, ".LOCAL");
break;
- case POTYPE_MAILHUB:
+ case MAILTYPE_MAILHUB:
if (!strcmp(p, user))
{
- com_err(whoami, 0, "The address \"%s@%s\" would create a mail "
- "loop.", p, machine);
- com_err(NULL, 0, "Set a POP pobox if you want local mail "
- "delivery.");
+ mrcl_set_message("The address \"%s@%s\" would create a mail "
+ "loop.\nSet a POP pobox if you want local "
+ "mail delivery.", p, machine);
status = MRCL_REJECT;
goto cleanup;
}
else
{
- com_err(whoami, 0, "Cannot forward mail to a local mailing "
- "address (%s@%s).", p, machine);
+ mrcl_set_message("Cannot forward mail to a local mailing "
+ "address (%s@%s).", p, machine);
status = MRCL_REJECT;
goto cleanup;
}
- case POTYPE_SMTP:
+ case MAILTYPE_SMTP:
if (*m != '"' && strcasecmp(m, machine))
{
- com_err(whoami, 0, "Warning: hostname %s canonicalized to %s\n",
- m, machine);
+ mrcl_set_message("Warning: hostname %s canonicalized to %s\n",
+ m, machine);
}
break;
cleanup:
free(addr);
if (status == MRCL_SUCCESS)
- *ret = retaddr;
+ {
+ *ret = retaddr;
+ mrcl_clear_message();
+ }
else
free(retaddr);
free(machine);
return status;
}
-/* Given a canonicalized machine name, ask the Moira server if it is
- * of type IMAP, POP, LOCAL, or MAILHUB -- if none of those, we assume
- * it's foreign.
- */
-static int potype(char *machine)
-{
- char *name;
- int status, match = 0;
- static struct save_queue *pop = NULL, *local = NULL;
- static struct save_queue *mailhub = NULL, *mailhub_name = NULL;
- static struct save_queue *imap = NULL;
-
- /* 0. Check if the machine is an IMAP server. */
- if (!imap)
- {
- char *service = "POSTOFFICE";
- imap = sq_create();
- status = mr_query("get_server_locations", 1, &service,
- save_sloc_machine, imap);
- if (status && (status != MR_NO_MATCH))
- {
- com_err(whoami, status, "while reading list of IMAP servers");
- return POTYPE_ERROR;
- }
- }
-
- /* Because of how sq_get_data works, we need to go through the entire
- * queue even if we find a match, so that it gets reset for the next
- * call.
- */
- while (sq_get_data(imap, &name))
- {
- if (!match && !strcasecmp(name, machine))
- match = 1;
- }
-
- if (match)
- return POTYPE_IMAP;
-
-
- /* 1. Check if the machine is a POP server. */
- if (!pop)
- {
- char *service = "POP";
- pop = sq_create();
- status = mr_query("get_server_locations", 1, &service,
- save_sloc_machine, pop);
- if (status && (status != MR_NO_MATCH))
- {
- com_err(whoami, status, "while reading list of POP servers");
- return POTYPE_ERROR;
- }
- }
-
- while (sq_get_data(pop, &name))
- {
- if (!match && !strcasecmp(name, machine))
- match = 1;
- }
- if (match)
- return POTYPE_POP;
-
-
- /* 2. Check if the machine is "LOCAL". */
- if (!local)
- {
- char *service = "LOCAL";
- local = sq_create();
- status = mr_query("get_server_locations", 1, &service,
- save_sloc_machine, local);
- if (status && (status != MR_NO_MATCH))
- {
- com_err(whoami, status, "while reading list of LOCAL servers");
- return POTYPE_ERROR;
- }
- }
-
- while (sq_get_data(local, &name))
- {
- if (!match && !strcasecmp(name, machine))
- match = 1;
- }
- if (match)
- return POTYPE_LOCAL;
-
-
- /* 3. Check if the machine is one of the mailhubs. */
- if (!mailhub)
- {
- char *service = "MAILHUB";
- mailhub = sq_create();
- status = mr_query("get_server_locations", 1, &service,
- save_sloc_machine, mailhub);
- if (status && (status != MR_NO_MATCH))
- {
- com_err(whoami, status, "while reading list of MAILHUB servers");
- return POTYPE_ERROR;
- }
- }
-
- while (sq_get_data(mailhub, &name))
- {
- if (!match && !strcasecmp(name, machine))
- match = 1;
- }
- if (match)
- return POTYPE_MAILHUB;
-
-
- /* 4. Check if the machine is one of the external names of the mailhubs. */
- if (!mailhub_name)
- {
- char *argv[3];
- mailhub_name = sq_create();
- argv[0] = "mailhub";
- argv[1] = "TYPE";
- argv[2] = "*";
- status = mr_query("get_alias", 3, argv, save_alias_value, mailhub_name);
- if (status && (status != MR_NO_MATCH))
- {
- com_err(whoami, status, "while reading list of mailhub names");
- return POTYPE_ERROR;
- }
- }
-
- while (sq_get_data(mailhub_name, &name))
- {
- if (!match && !strcasecmp(name, machine))
- match = 1;
- }
- if (match)
- return POTYPE_MAILHUB;
-
- return POTYPE_SMTP;
-}
-
static int save_sloc_machine(int argc, char **argv, void *sq)
{
sq_save_data(sq, strdup(argv[1]));