Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  dict_proxy.c

  Sprache: C
 

/*++
/* NAME
/* dict_proxy 3
/* SUMMARY
/* generic dictionary proxy client
/* SYNOPSIS
/* #include <dict_proxy.h>
/*
/* DICT *dict_proxy_open(map, open_flags, dict_flags)
/* const char *map;
/* int open_flags;
/* int dict_flags;
/* DESCRIPTION
/* dict_proxy_open() relays read-only or read-write operations
/* through the Postfix proxymap server.
/*
/* The \fIopen_flags\fR argument must specify O_RDONLY
/* or O_RDWR. Depending on this, the client
/* connects to the proxymap multiserver or to the
/* proxywrite single updater.
/*
/* The connection to the Postfix proxymap server is automatically
/* closed after $ipc_idle seconds of idle time, or after $ipc_ttl
/* seconds of activity.
/* SECURITY
/* The proxy map server is not meant to be a trusted process. Proxy
/* maps must not be used to look up security sensitive information
/* such as user/group IDs, output files, or external commands.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* clnt_stream(3) client endpoint connection management
/* DIAGNOSTICS
/* Fatal errors: out of memory, unimplemented operation,
/* bad request parameter, map not approved for proxy access.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <errno.h>
#include <unistd.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
#include <vstring.h>
#include <vstream.h>
#include <attr.h>
#include <dict.h>

/* Global library. */

#include <mail_proto.h>
#include <mail_params.h>
#include <clnt_stream.h>
#include <dict_proxy.h>

/* Application-specific. */

typedef struct {
    DICT    dict;   /* generic members */
    CLNT_STREAM *clnt;   /* client handle (shared) */
    const char *service;  /* service name */
    int     inst_flags;   /* saved dict flags */
    VSTRING *reskey;   /* result key storage */
    VSTRING *result;   /* storage */
} DICT_PROXY;

 /*
  * SLMs.
  */

#define STR(x)  vstring_str(x)
#define VSTREQ(v,s) (strcmp(STR(v),s) == 0)

 /*
  * All proxied maps of the same type share the same query/reply socket.
  */

static CLNT_STREAM *proxymap_stream; /* read-only maps */
static CLNT_STREAM *proxywrite_stream; /* read-write maps */

/* dict_proxy_handshake - receive server protocol announcement */

static int dict_proxy_handshake(VSTREAM *stream)
{
    return (attr_scan(stream, ATTR_FLAG_STRICT,
   RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_PROXYMAP),
        ATTR_TYPE_END));
}

/* dict_proxy_sequence - find first/next entry */

static int dict_proxy_sequence(DICT *dict, int function,
                  const char **key, const char **value)
{
    const char *myname = "dict_proxy_sequence";
    DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
    VSTREAM *stream;
    int     status;
    int     count = 0;
    int     inst_flags;
    int     request_flags;

    /*
     * The client and server live in separate processes that may start and
     * terminate independently. We cannot rely on a persistent connection,
     * let alone on persistent state (such as a specific open table) that is
     * associated with a specific connection. Each lookup needs to specify
     * the table and the flags that were specified to dict_proxy_open().
     */

    VSTRING_RESET(dict_proxy->reskey);
    VSTRING_TERMINATE(dict_proxy->reskey);
    VSTRING_RESET(dict_proxy->result);
    VSTRING_TERMINATE(dict_proxy->result);
    inst_flags = dict_proxy->inst_flags;
    request_flags = dict->flags;
    for (;;) {
 stream = clnt_stream_access(dict_proxy->clnt);
 errno = 0;
 count += 1;
 if (stream == 0
     || attr_print(stream, ATTR_FLAG_NONE,
     SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_SEQUENCE),
     SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
     SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
     SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
     SEND_ATTR_INT(MAIL_ATTR_FUNC, function),
     ATTR_TYPE_END) != 0
     || vstream_fflush(stream)
     || attr_scan(stream, ATTR_FLAG_STRICT,
    RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
    RECV_ATTR_STR(MAIL_ATTR_KEY, dict_proxy->reskey),
    RECV_ATTR_STR(MAIL_ATTR_VALUE, dict_proxy->result),
    ATTR_TYPE_END) != 4) {
     if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
  msg_warn("%s: service %s: %m", myname, dict_proxy->service);
 } else {
     if (msg_verbose)
  msg_info("%s: table=%s flags=%s func=%d -> status=%d key=%s val=%s",
    myname, dict->name, dict_flags_str(request_flags),
    function, status, STR(dict_proxy->reskey),
    STR(dict_proxy->result));
     switch (status) {
     case PROXY_STAT_BAD:
  msg_fatal("%s sequence failed for table \"%s\" function %d: "
     "invalid request",
     dict_proxy->service, dict->name, function);
     case PROXY_STAT_DENY:
  msg_fatal("%s service is not configured for table \"%s\"",
     dict_proxy->service, dict->name);
     case PROXY_STAT_OK:
  *key = STR(dict_proxy->reskey);
  *value = STR(dict_proxy->result);
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
     case PROXY_STAT_NOKEY:
  *key = *value = 0;
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
     case PROXY_STAT_RETRY:
  *key = *value = 0;
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
     case PROXY_STAT_CONFIG:
  *key = *value = 0;
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_CONFIG, DICT_STAT_ERROR);
     default:
  msg_warn("%s sequence failed for table \"%s\" function %d: "
    "unexpected reply status %d",
    dict_proxy->service, dict->name, function, status);
     }
 }
 clnt_stream_recover(dict_proxy->clnt);
 sleep(1);    /* XXX make configurable */
    }
}

/* dict_proxy_lookup - find table entry */

static const char *dict_proxy_lookup(DICT *dict, const char *key)
{
    const char *myname = "dict_proxy_lookup";
    DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
    VSTREAM *stream;
    int     status;
    int     count = 0;
    int     inst_flags;
    int     request_flags;

    /*
     * The client and server live in separate processes that may start and
     * terminate independently. We cannot rely on a persistent connection,
     * let alone on persistent state (such as a specific open table) that is
     * associated with a specific connection. Each lookup needs to specify
     * the table and the flags that were specified to dict_proxy_open().
     */

    VSTRING_RESET(dict_proxy->result);
    VSTRING_TERMINATE(dict_proxy->result);
    inst_flags = dict_proxy->inst_flags;
    request_flags = dict->flags;
    for (;;) {
 stream = clnt_stream_access(dict_proxy->clnt);
 errno = 0;
 count += 1;
 if (stream == 0
     || attr_print(stream, ATTR_FLAG_NONE,
     SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_LOOKUP),
     SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
     SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
     SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
     SEND_ATTR_STR(MAIL_ATTR_KEY, key),
     ATTR_TYPE_END) != 0
     || vstream_fflush(stream)
     || attr_scan(stream, ATTR_FLAG_STRICT,
    RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
    RECV_ATTR_STR(MAIL_ATTR_VALUE, dict_proxy->result),
    ATTR_TYPE_END) != 3) {
     if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
  msg_warn("%s: service %s: %m", myname, dict_proxy->service);
 } else {
     if (msg_verbose)
  msg_info("%s: table=%s flags=%s key=%s -> status=%d result=%s",
    myname, dict->name,
    dict_flags_str(request_flags), key,
    status, STR(dict_proxy->result));
     switch (status) {
     case PROXY_STAT_BAD:
  msg_fatal("%s lookup failed for table \"%s\" key \"%s\": "
     "invalid request",
     dict_proxy->service, dict->name, key);
     case PROXY_STAT_DENY:
  msg_fatal("%s service is not configured for table \"%s\"",
     dict_proxy->service, dict->name);
     case PROXY_STAT_OK:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, STR(dict_proxy->result));
     case PROXY_STAT_NOKEY:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, (char *) 0);
     case PROXY_STAT_RETRY:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0);
     case PROXY_STAT_CONFIG:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_CONFIG, (char *) 0);
     default:
  msg_warn("%s lookup failed for table \"%s\" key \"%s\": "
    "unexpected reply status %d",
    dict_proxy->service, dict->name, key, status);
     }
 }
 clnt_stream_recover(dict_proxy->clnt);
 sleep(1);    /* XXX make configurable */
    }
}

/* dict_proxy_update - update table entry */

static int dict_proxy_update(DICT *dict, const char *key, const char *value)
{
    const char *myname = "dict_proxy_update";
    DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
    VSTREAM *stream;
    int     status;
    int     count = 0;
    int     inst_flags;
    int     request_flags;

    /*
     * The client and server live in separate processes that may start and
     * terminate independently. We cannot rely on a persistent connection,
     * let alone on persistent state (such as a specific open table) that is
     * associated with a specific connection. Each lookup needs to specify
     * the table and the flags that were specified to dict_proxy_open().
     */

    inst_flags = dict_proxy->inst_flags;
    request_flags = dict->flags;
    for (;;) {
 stream = clnt_stream_access(dict_proxy->clnt);
 errno = 0;
 count += 1;
 if (stream == 0
     || attr_print(stream, ATTR_FLAG_NONE,
     SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_UPDATE),
     SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
     SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
     SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
     SEND_ATTR_STR(MAIL_ATTR_KEY, key),
     SEND_ATTR_STR(MAIL_ATTR_VALUE, value),
     ATTR_TYPE_END) != 0
     || vstream_fflush(stream)
     || attr_scan(stream, ATTR_FLAG_STRICT,
    RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
    ATTR_TYPE_END) != 2) {
     if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
  msg_warn("%s: service %s: %m", myname, dict_proxy->service);
 } else {
     if (msg_verbose)
  msg_info("%s: table=%s flags=%s key=%s value=%s -> status=%d",
    myname, dict->name, dict_flags_str(request_flags),
    key, value, status);
     switch (status) {
     case PROXY_STAT_BAD:
  msg_fatal("%s update failed for table \"%s\" key \"%s\": "
     "invalid request",
     dict_proxy->service, dict->name, key);
     case PROXY_STAT_DENY:
  msg_fatal("%s update access is not configured for table \"%s\"",
     dict_proxy->service, dict->name);
     case PROXY_STAT_OK:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
     case PROXY_STAT_NOKEY:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
     case PROXY_STAT_RETRY:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
     case PROXY_STAT_CONFIG:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_CONFIG, DICT_STAT_ERROR);
     default:
  msg_warn("%s update failed for table \"%s\" key \"%s\": "
    "unexpected reply status %d",
    dict_proxy->service, dict->name, key, status);
     }
 }
 clnt_stream_recover(dict_proxy->clnt);
 sleep(1);    /* XXX make configurable */
    }
}

/* dict_proxy_delete - delete table entry */

static int dict_proxy_delete(DICT *dict, const char *key)
{
    const char *myname = "dict_proxy_delete";
    DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
    VSTREAM *stream;
    int     status;
    int     count = 0;
    int     inst_flags;
    int     request_flags;

    /*
     * The client and server live in separate processes that may start and
     * terminate independently. We cannot rely on a persistent connection,
     * let alone on persistent state (such as a specific open table) that is
     * associated with a specific connection. Each lookup needs to specify
     * the table and the flags that were specified to dict_proxy_open().
     */

    inst_flags = dict_proxy->inst_flags;
    request_flags = dict->flags;
    for (;;) {
 stream = clnt_stream_access(dict_proxy->clnt);
 errno = 0;
 count += 1;
 if (stream == 0
     || attr_print(stream, ATTR_FLAG_NONE,
     SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_DELETE),
     SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
     SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
     SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
     SEND_ATTR_STR(MAIL_ATTR_KEY, key),
     ATTR_TYPE_END) != 0
     || vstream_fflush(stream)
     || attr_scan(stream, ATTR_FLAG_STRICT,
    RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
    ATTR_TYPE_END) != 2) {
     if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno !=
          ENOENT))
  msg_warn("%s: service %s: %m", myname, dict_proxy->service);
 } else {
     if (msg_verbose)
  msg_info("%s: table=%s flags=%s key=%s -> status=%d",
    myname, dict->name, dict_flags_str(request_flags),
    key, status);
     switch (status) {
     case PROXY_STAT_BAD:
  msg_fatal("%s delete failed for table \"%s\" key \"%s\": "
     "invalid request",
     dict_proxy->service, dict->name, key);
     case PROXY_STAT_DENY:
  msg_fatal("%s update access is not configured for table \"%s\"",
     dict_proxy->service, dict->name);
     case PROXY_STAT_OK:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
     case PROXY_STAT_NOKEY:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
     case PROXY_STAT_RETRY:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
     case PROXY_STAT_CONFIG:
  DICT_ERR_VAL_RETURN(dict, DICT_ERR_CONFIG, DICT_STAT_ERROR);
     default:
  msg_warn("%s delete failed for table \"%s\" key \"%s\": "
    "unexpected reply status %d",
    dict_proxy->service, dict->name, key, status);
     }
 }
 clnt_stream_recover(dict_proxy->clnt);
 sleep(1);    /* XXX make configurable */
    }
}

/* dict_proxy_close - disconnect */

static void dict_proxy_close(DICT *dict)
{
    DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;

    vstring_free(dict_proxy->reskey);
    vstring_free(dict_proxy->result);
    dict_free(dict);
}

/* dict_proxy_open - open remote map */

DICT   *dict_proxy_open(const char *map, int open_flags, int dict_flags)
{
    const char *myname = "dict_proxy_open";
    DICT_PROXY *dict_proxy;
    VSTREAM *stream;
    int     server_flags;
    int     status;
    const char *service;
    char   *relative_path;
    char   *kludge = 0;
    char   *prefix;
    CLNT_STREAM **pstream;

    /*
     * If this map can't be proxied then we silently do a direct open. This
     * allows sites to benefit from proxying the virtual mailbox maps without
     * unnecessary pain.
     */

    if (dict_flags & DICT_FLAG_NO_PROXY)
 return (dict_open(map, open_flags, dict_flags));

    /*
     * Use a shared stream for proxied table lookups of the same type.
     * 
     * XXX A complete implementation would also allow O_RDWR without O_CREAT.
     * But we must not pass on every possible set of flags to the proxy
     * server; only sets that make sense. For now, the flags are passed
     * implicitly by choosing between the proxymap or proxywrite service.
     * 
     * XXX Use absolute pathname to make this work from non-daemon processes.
     */

    if (open_flags == O_RDONLY) {
 pstream = &proxymap_stream;
 service = var_proxymap_service;
    } else if ((open_flags & O_RDWR) == O_RDWR) {
 pstream = &proxywrite_stream;
 service = var_proxywrite_service;
    } else
 msg_fatal("%s: %s map open requires O_RDONLY or O_RDWR mode",
    map, DICT_TYPE_PROXY);

    if (*pstream == 0) {
 relative_path = concatenate(MAIL_CLASS_PRIVATE "/",
        service, (char *) 0);
 if (access(relative_path, F_OK) == 0)
     prefix = MAIL_CLASS_PRIVATE;
 else
     prefix = kludge = concatenate(var_queue_dir, "/",
       MAIL_CLASS_PRIVATE, (char *) 0);
 *pstream = clnt_stream_create(prefix, service, var_ipc_idle_limit,
          var_ipc_ttl_limit,
          dict_proxy_handshake);
 if (kludge)
     myfree(kludge);
 myfree(relative_path);
    }

    /*
     * Local initialization.
     */

    dict_proxy = (DICT_PROXY *)
 dict_alloc(DICT_TYPE_PROXY, map, sizeof(*dict_proxy));
    dict_proxy->dict.lookup = dict_proxy_lookup;
    dict_proxy->dict.update = dict_proxy_update;
    dict_proxy->dict.delete = dict_proxy_delete;
    dict_proxy->dict.sequence = dict_proxy_sequence;
    dict_proxy->dict.close = dict_proxy_close;
    dict_proxy->inst_flags = dict_flags;
    dict_proxy->reskey = vstring_alloc(10);
    dict_proxy->result = vstring_alloc(10);
    dict_proxy->clnt = *pstream;
    dict_proxy->service = service;

#define DICT_PROXY_ERR_RETURN(d) do { \
 DICT *_d = (d); \
 dict_proxy_close(&dict_proxy->dict); \
 return (_d); \
    } while (0)

    /*
     * Establish initial contact and get the map type specific flags.
     */

    for (;;) {
 stream = clnt_stream_access(dict_proxy->clnt);
 errno = 0;
 if (stream == 0
     || attr_print(stream, ATTR_FLAG_NONE,
     SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_OPEN),
        SEND_ATTR_STR(MAIL_ATTR_TABLE, dict_proxy->dict.name),
  SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, dict_proxy->inst_flags),
     ATTR_TYPE_END) != 0
     || vstream_fflush(stream)
     || attr_scan(stream, ATTR_FLAG_STRICT,
    RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &server_flags),
    ATTR_TYPE_END) != 2) {
     if (msg_verbose || (errno != EPIPE && errno != ENOENT))
  msg_warn("%s: service %s: %m", myname, dict_proxy->service);
 } else {
     if (msg_verbose)
  msg_info("%s: connect to map=%s status=%d server_flags=%s",
    myname, dict_proxy->dict.name, status,
    dict_flags_str(server_flags));
     switch (status) {
     case PROXY_STAT_BAD:
  DICT_PROXY_ERR_RETURN(dict_surrogate(DICT_TYPE_PROXY,
         dict_proxy->dict.name, open_flags, dict_flags,
    "%s open failed for table \"%s\": invalid request",
          dict_proxy->service, dict_proxy->dict.name));
     case PROXY_STAT_DENY:
  DICT_PROXY_ERR_RETURN(dict_surrogate(DICT_TYPE_PROXY,
         dict_proxy->dict.name, open_flags, dict_flags,
       "%s service is not configured for table \"%s\"",
          dict_proxy->service, dict_proxy->dict.name));
     case PROXY_STAT_OK:
  dict_proxy->dict.flags = server_flags;
  return (&dict_proxy->dict);
     default:
  msg_warn("%s open failed for table \"%s\": unexpected status %d",
    dict_proxy->service, dict_proxy->dict.name, status);
     }
 }
 clnt_stream_recover(dict_proxy->clnt);
 sleep(1);    /* XXX make configurable */
    }
}

Messung V0.5 in Prozent
C=71 H=95 G=83

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002