~ubuntu-branches/ubuntu/hoary/postfix/hoary-security

« back to all changes in this revision

Viewing changes to src/global/quote_822_local.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-10-06 11:50:33 UTC
  • Revision ID: james.westby@ubuntu.com-20041006115033-ooo6yfg6kmoteu04
Tags: upstream-2.1.3
ImportĀ upstreamĀ versionĀ 2.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      quote_822_local 3
 
4
/* SUMMARY
 
5
/*      quote local part of mailbox
 
6
/* SYNOPSIS
 
7
/*      #include <quote_822_local.h>
 
8
/*
 
9
/*      VSTRING *quote_822_local(dst, src)
 
10
/*      VSTRING *dst;
 
11
/*      const char *src;
 
12
/*
 
13
/*      VSTRING *quote_822_local_flags(dst, src, flags)
 
14
/*      VSTRING *dst;
 
15
/*      const char *src;
 
16
/*      int     flags;
 
17
/*
 
18
/*      VSTRING *unquote_822_local(dst, src)
 
19
/*      VSTRING *dst;
 
20
/*      const char *src;
 
21
/* DESCRIPTION
 
22
/*      quote_822_local() quotes the local part of a mailbox and
 
23
/*      returns a result that can be used in message headers as
 
24
/*      specified by RFC 822 (actually, an 8-bit clean version of
 
25
/*      RFC 822). It implements an 8-bit clean version of RFC 822.
 
26
/*
 
27
/*      quote_822_local_flags() provides finer control.
 
28
/*
 
29
/*      unquote_822_local() transforms the local part of a mailbox
 
30
/*      address to unquoted (internal) form.
 
31
/*
 
32
/*      Arguments:
 
33
/* .IP dst
 
34
/*      The result.
 
35
/* .IP src
 
36
/*      The input address.
 
37
/* .IP flags
 
38
/*      Bit-wise OR of zero or more of the following.
 
39
/* .RS
 
40
/* .IP QUOTE_FLAG_8BITCLEAN
 
41
/*      In violation with RFCs, treat 8-bit text as ordinary text.
 
42
/* .IP QUOTE_FLAG_EXPOSE_AT
 
43
/*      In violation with RFCs, treat `@' as an ordinary character.
 
44
/* .IP QUOTE_FLAG_APPEND
 
45
/*      Append to the result buffer, instead of overwriting it.
 
46
/* .RE
 
47
/* STANDARDS
 
48
/*      RFC 822 (ARPA Internet Text Messages)
 
49
/* BUGS
 
50
/*      The code assumes that the domain is RFC 822 clean.
 
51
/* LICENSE
 
52
/* .ad
 
53
/* .fi
 
54
/*      The Secure Mailer license must be distributed with this software.
 
55
/* AUTHOR(S)
 
56
/*      Wietse Venema
 
57
/*      IBM T.J. Watson Research
 
58
/*      P.O. Box 704
 
59
/*      Yorktown Heights, NY 10598, USA
 
60
/*--*/
 
61
 
 
62
/* System library. */
 
63
 
 
64
#include <sys_defs.h>
 
65
#include <string.h>
 
66
#include <ctype.h>
 
67
 
 
68
/* Utility library. */
 
69
 
 
70
#include <vstring.h>
 
71
 
 
72
/* Global library. */
 
73
 
 
74
/* Application-specific. */
 
75
 
 
76
#include "quote_822_local.h"
 
77
 
 
78
/* Local stuff. */
 
79
 
 
80
#define YES     1
 
81
#define NO      0
 
82
 
 
83
/* is_822_dot_string - is this local-part an rfc 822 dot-string? */
 
84
 
 
85
static int is_822_dot_string(const char *local_part, const char *end, int flags)
 
86
{
 
87
    const char *cp;
 
88
    int     ch;
 
89
 
 
90
    /*
 
91
     * Detect any deviations from a sequence of atoms separated by dots. We
 
92
     * could use lookup tables to speed up some of the work, but hey, how
 
93
     * large can a local-part be anyway?
 
94
     * 
 
95
     * RFC 822 expects 7-bit data. Rather than quoting every 8-bit character
 
96
     * (and still passing it on as 8-bit data) we leave 8-bit data alone.
 
97
     */
 
98
    if (local_part == end || local_part[0] == 0 || local_part[0] == '.')
 
99
        return (NO);
 
100
    for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
 
101
        if (ch == '.' && (cp + 1) < end && cp[1] == '.')
 
102
            return (NO);
 
103
        if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
 
104
            return (NO);
 
105
        if (ch == ' ')
 
106
            return (NO);
 
107
        if (ISCNTRL(ch))
 
108
            return (NO);
 
109
        if (ch == '(' || ch == ')'
 
110
            || ch == '<' || ch == '>'
 
111
            || (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == ','
 
112
            || ch == ';' || ch == ':'
 
113
            || ch == '\\' || ch == '"'
 
114
            || ch == '[' || ch == ']')
 
115
            return (NO);
 
116
    }
 
117
    if (cp[-1] == '.')
 
118
        return (NO);
 
119
    return (YES);
 
120
}
 
121
 
 
122
/* make_822_quoted_string - make quoted-string from local-part */
 
123
 
 
124
static VSTRING *make_822_quoted_string(VSTRING *dst, const char *local_part,
 
125
                                               const char *end, int flags)
 
126
{
 
127
    const char *cp;
 
128
    int     ch;
 
129
 
 
130
    /*
 
131
     * Put quotes around the result, and prepend a backslash to characters
 
132
     * that need quoting when they occur in a quoted-string.
 
133
     */
 
134
    VSTRING_ADDCH(dst, '"');
 
135
    for (cp = local_part; cp < end && (ch = *cp) != 0; cp++) {
 
136
        if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
 
137
            || ch == '"' || ch == '\\' || ch == '\r')
 
138
            VSTRING_ADDCH(dst, '\\');
 
139
        VSTRING_ADDCH(dst, ch);
 
140
    }
 
141
    VSTRING_ADDCH(dst, '"');
 
142
    return (dst);
 
143
}
 
144
 
 
145
/* quote_822_local_flags - quote local part of mailbox according to rfc 822 */
 
146
 
 
147
VSTRING *quote_822_local_flags(VSTRING *dst, const char *mbox, int flags)
 
148
{
 
149
    const char *start;                  /* first byte of localpart */
 
150
    const char *end;                    /* first byte after localpart */
 
151
    const char *colon;
 
152
 
 
153
    /*
 
154
     * According to RFC 822, a local-part is a dot-string or a quoted-string.
 
155
     * We first see if the local-part is a dot-string. If it is not, we turn
 
156
     * it into a quoted-string. Anything else would be too painful. But
 
157
     * first, skip over any source route that precedes the local-part.
 
158
     */
 
159
    if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0)
 
160
        start = colon + 1;
 
161
    else
 
162
        start = mbox;
 
163
    if ((end = strrchr(start, '@')) == 0)
 
164
        end = start + strlen(start);
 
165
    if ((flags & QUOTE_FLAG_APPEND) == 0)
 
166
        VSTRING_RESET(dst);
 
167
    if (is_822_dot_string(start, end, flags)) {
 
168
        return (vstring_strcat(dst, mbox));
 
169
    } else {
 
170
        vstring_strncat(dst, mbox, start - mbox);
 
171
        make_822_quoted_string(dst, start, end, flags & QUOTE_FLAG_8BITCLEAN);
 
172
        return (vstring_strcat(dst, end));
 
173
    }
 
174
}
 
175
 
 
176
/* unquote_822_local - unquote local part of mailbox according to rfc 822 */
 
177
 
 
178
VSTRING *unquote_822_local(VSTRING *dst, const char *mbox)
 
179
{
 
180
    const char *start;                  /* first byte of localpart */
 
181
    const char *end;                    /* first byte after localpart */
 
182
    const char *colon;
 
183
    const char *cp;
 
184
 
 
185
    if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) {
 
186
        start = colon + 1;
 
187
        vstring_strncpy(dst, mbox, start - mbox);
 
188
    } else {
 
189
        start = mbox;
 
190
        VSTRING_RESET(dst);
 
191
    }
 
192
    if ((end = strrchr(start, '@')) == 0)
 
193
        end = start + strlen(start);
 
194
    for (cp = start; cp < end; cp++) {
 
195
        if (*cp == '"')
 
196
            continue;
 
197
        if (*cp == '\\') {
 
198
            if (cp[1] == 0)
 
199
                continue;
 
200
            cp++;
 
201
        }
 
202
        VSTRING_ADDCH(dst, *cp);
 
203
    }
 
204
    if (*end)
 
205
        vstring_strcat(dst, end);
 
206
    else
 
207
        VSTRING_TERMINATE(dst);
 
208
    return (dst);
 
209
}
 
210
 
 
211
#ifdef TEST
 
212
 
 
213
 /*
 
214
  * Proof-of-concept test program. Read an unquoted address from stdin, and
 
215
  * show the quoted and unquoted results.
 
216
  */
 
217
#include <vstream.h>
 
218
#include <vstring_vstream.h>
 
219
 
 
220
#define STR     vstring_str
 
221
 
 
222
int     main(int unused_argc, char **unused_argv)
 
223
{
 
224
    VSTRING *raw = vstring_alloc(100);
 
225
    VSTRING *quoted = vstring_alloc(100);
 
226
    VSTRING *unquoted = vstring_alloc(100);
 
227
 
 
228
    while (vstring_fgets_nonl(raw, VSTREAM_IN)) {
 
229
        quote_822_local(quoted, STR(raw));
 
230
        vstream_printf("quoted:         %s\n", STR(quoted));
 
231
        unquote_822_local(unquoted, STR(quoted));
 
232
        vstream_printf("unquoted:       %s\n", STR(unquoted));
 
233
        vstream_fflush(VSTREAM_OUT);
 
234
    }
 
235
    vstring_free(unquoted);
 
236
    vstring_free(quoted);
 
237
    vstring_free(raw);
 
238
}
 
239
 
 
240
#endif