~ubuntu-branches/ubuntu/vivid/postfix/vivid-proposed

« back to all changes in this revision

Viewing changes to src/qmqpd/qmqpd_peer.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      qmqpd_peer 3
 
4
/* SUMMARY
 
5
/*      look up peer name/address information
 
6
/* SYNOPSIS
 
7
/*      #include "qmqpd.h"
 
8
/*
 
9
/*      void    qmqpd_peer_init(state)
 
10
/*      QMQPD_STATE *state;
 
11
/*
 
12
/*      void    qmqpd_peer_reset(state)
 
13
/*      QMQPD_STATE *state;
 
14
/* DESCRIPTION
 
15
/*      The qmqpd_peer_init() routine attempts to produce a printable
 
16
/*      version of the peer name and address of the specified socket.
 
17
/*      Where information is unavailable, the name and/or address
 
18
/*      are set to "unknown".
 
19
/*
 
20
/*      qmqpd_peer_init() updates the following fields:
 
21
/* .IP name
 
22
/*      The client hostname. An unknown name is represented by the
 
23
/*      string "unknown".
 
24
/* .IP addr
 
25
/*      Printable representation of the client address.
 
26
/* .IP namaddr
 
27
/*      String of the form: "name[addr]".
 
28
/* .PP
 
29
/*      qmqpd_peer_reset() releases memory allocate by qmqpd_peer_init().
 
30
/* LICENSE
 
31
/* .ad
 
32
/* .fi
 
33
/*      The Secure Mailer license must be distributed with this software.
 
34
/* AUTHOR(S)
 
35
/*      Wietse Venema
 
36
/*      IBM T.J. Watson Research
 
37
/*      P.O. Box 704
 
38
/*      Yorktown Heights, NY 10598, USA
 
39
/*--*/
 
40
 
 
41
/* System library. */
 
42
 
 
43
#include <sys_defs.h>
 
44
#include <sys/socket.h>
 
45
#include <netinet/in.h>
 
46
#include <arpa/inet.h>
 
47
#include <stdio.h>                      /* strerror() */
 
48
#include <errno.h>
 
49
#include <netdb.h>
 
50
#include <string.h>
 
51
 
 
52
 /*
 
53
  * Older systems don't have h_errno. Even modern systems don't have
 
54
  * hstrerror().
 
55
  */
 
56
#ifdef NO_HERRNO
 
57
 
 
58
static int h_errno = TRY_AGAIN;
 
59
 
 
60
#define  HSTRERROR(err) "Host not found"
 
61
 
 
62
#else
 
63
 
 
64
#define  HSTRERROR(err) (\
 
65
        err == TRY_AGAIN ? "Host not found, try again" : \
 
66
        err == HOST_NOT_FOUND ? "Host not found" : \
 
67
        err == NO_DATA ? "Host name has no address" : \
 
68
        err == NO_RECOVERY ? "Name server failure" : \
 
69
        strerror(errno) \
 
70
    )
 
71
#endif
 
72
 
 
73
/* Utility library. */
 
74
 
 
75
#include <msg.h>
 
76
#include <mymalloc.h>
 
77
#include <valid_hostname.h>
 
78
#include <stringops.h>
 
79
 
 
80
/* Global library. */
 
81
 
 
82
 
 
83
/* Application-specific. */
 
84
 
 
85
#include "qmqpd.h"
 
86
 
 
87
/* qmqpd_peer_init - initialize peer information */
 
88
 
 
89
void    qmqpd_peer_init(QMQPD_STATE *state)
 
90
{
 
91
    struct sockaddr_in sin;
 
92
    SOCKADDR_SIZE len = sizeof(sin);
 
93
    struct hostent *hp;
 
94
    int     i;
 
95
 
 
96
    /*
 
97
     * Look up the peer address information.
 
98
     */
 
99
    if (getpeername(vstream_fileno(state->client),
 
100
                    (struct sockaddr *) & sin, &len) >= 0) {
 
101
        errno = 0;
 
102
    }
 
103
 
 
104
    /*
 
105
     * If peer went away, give up.
 
106
     */
 
107
    if (errno == ECONNRESET || errno == ECONNABORTED) {
 
108
        state->name = mystrdup(CLIENT_ATTR_UNKNOWN);
 
109
        state->addr = mystrdup(CLIENT_ATTR_UNKNOWN);
 
110
    }
 
111
 
 
112
    /*
 
113
     * Look up and "verify" the client hostname.
 
114
     */
 
115
    else if (errno == 0 && sin.sin_family == AF_INET) {
 
116
        state->addr = mystrdup(inet_ntoa(sin.sin_addr));
 
117
        hp = gethostbyaddr((char *) &(sin.sin_addr),
 
118
                           sizeof(sin.sin_addr), AF_INET);
 
119
        if (hp == 0) {
 
120
            state->name = mystrdup(CLIENT_ATTR_UNKNOWN);
 
121
        } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) {
 
122
            state->name = mystrdup(CLIENT_ATTR_UNKNOWN);
 
123
        } else {
 
124
            state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */
 
125
 
 
126
            /*
 
127
             * Reject the hostname if it does not list the peer address.
 
128
             */
 
129
#define REJECT_PEER_NAME(state) { \
 
130
        myfree(state->name); \
 
131
        state->name = mystrdup(CLIENT_ATTR_UNKNOWN); \
 
132
    }
 
133
 
 
134
            hp = gethostbyname(state->name);    /* clobbers hp->name!! */
 
135
            if (hp == 0) {
 
136
                msg_warn("%s: hostname %s verification failed: %s",
 
137
                         state->addr, state->name, HSTRERROR(h_errno));
 
138
                REJECT_PEER_NAME(state);
 
139
            } else if (hp->h_length != sizeof(sin.sin_addr)) {
 
140
                msg_warn("%s: hostname %s verification failed: bad address size %d",
 
141
                         state->addr, state->name, hp->h_length);
 
142
                REJECT_PEER_NAME(state);
 
143
            } else {
 
144
                for (i = 0; /* void */ ; i++) {
 
145
                    if (hp->h_addr_list[i] == 0) {
 
146
                        msg_warn("%s: address not listed for hostname %s",
 
147
                                 state->addr, state->name);
 
148
                        REJECT_PEER_NAME(state);
 
149
                        break;
 
150
                    }
 
151
                    if (memcmp(hp->h_addr_list[i],
 
152
                               (char *) &sin.sin_addr,
 
153
                               sizeof(sin.sin_addr)) == 0)
 
154
                        break;                  /* keep peer name */
 
155
                }
 
156
            }
 
157
        }
 
158
    }
 
159
 
 
160
    /*
 
161
     * If it's not Internet, assume the client is local, and avoid using the
 
162
     * naming service because that can hang when the machine is disconnected.
 
163
     */
 
164
    else {
 
165
        state->name = mystrdup("localhost");
 
166
        state->addr = mystrdup("127.0.0.1");    /* XXX bogus. */
 
167
    }
 
168
 
 
169
    /*
 
170
     * Do the name[addr] formatting for pretty reports.
 
171
     */
 
172
    state->namaddr =
 
173
        concatenate(state->name, "[", state->addr, "]", (char *) 0);
 
174
}
 
175
 
 
176
/* qmqpd_peer_reset - destroy peer information */
 
177
 
 
178
void    qmqpd_peer_reset(QMQPD_STATE *state)
 
179
{
 
180
    myfree(state->name);
 
181
    myfree(state->addr);
 
182
    myfree(state->namaddr);
 
183
}