1 /*
2 * Copyright (c) 2006-2010 Internet Initiative Japan Inc. All rights reserved.
3 *
4 * The terms and conditions of the accompanying program
5 * shall be provided separately by Internet Initiative Japan Inc.
6 * Any use, reproduction or distribution of the program are permitted
7 * provided that you agree to be bound to such terms and conditions.
8 *
9 * $Id: dkimauthor.c 1366 2011-10-16 08:13:40Z takahiko $
10 */
11
12 #include "rcsid.h"
13 RCSID("$Id: dkimauthor.c 1366 2011-10-16 08:13:40Z takahiko $");
14
15 #include <assert.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <stdbool.h>
19
20 #include "dkimlogger.h"
21 #include "inetmailbox.h"
22 #include "ptrop.h"
23 #include "xskip.h"
24 #include "strarray.h"
25 #include "dkim.h"
26 #include "dkimpolicybase.h"
27 #include "mailheaders.h"
28
29 /**
30 * @return DSTAT_OK for success, otherwise status code that indicates error.
31 * @error DSTAT_PERMFAIL_AUTHOR_UNPARSABLE unable to parse Author header field value
32 * @error DSTAT_SYSERR_NORESOURCE memory allocation error
33 */
34 static DkimStatus
DkimAuthor_parse(const DkimPolicyBase * policy,const char * head,const char * tail,InetMailbox ** mailbox)35 DkimAuthor_parse(const DkimPolicyBase *policy, const char *head, const char *tail,
36 InetMailbox **mailbox)
37 {
38 assert(NULL != head);
39 assert(NULL != tail);
40 assert(NULL != mailbox);
41
42 const char *p, *errptr;
43 InetMailbox *build_mailbox = InetMailbox_build2822Mailbox(head, tail, &p, &errptr);
44
45 if (NULL == build_mailbox) {
46 if (NULL != errptr) { // parse error
47 DkimLogPermFail(policy, "Mailbox parse error: near %.50s", p);
48 return DSTAT_PERMFAIL_AUTHOR_UNPARSABLE;
49 } else { // memory allocation error
50 DkimLogNoResource(policy);
51 return DSTAT_SYSERR_NORESOURCE;
52 } // end if
53 } // end if
54
55 XSkip_fws(p, tail, &p); // ignore trailing FWS
56 if (p == tail) {
57 *mailbox = build_mailbox;
58 return DSTAT_OK;
59 } else {
60 // Though the parsing has succeeded, unmatched sequence has been left.
61 DkimLogPermFail(policy, "Author field has unused portion: %d bytes, near %.50s", tail - p,
62 head);
63 InetMailbox_free(build_mailbox);
64 return DSTAT_PERMFAIL_AUTHOR_UNPARSABLE;
65 } // end if
66 } // end function: DkimAuthor_parse
67
68 /**
69 * @param header_index A pointer to a variable to receive the index of the header field
70 * extracted as "Author" in the "headers" object.
71 * Undefined if the return value is not DSTAT_OK.
72 * @param header_field A pointer to a variable to receive the header field name
73 * in the "headers" object.
74 * Undefined if the return value is not DSTAT_OK.
75 * @param header_value A pointer to a variable to receive the header field value
76 * in the "headers" object.
77 * Undefined if the return value is not DSTAT_OK.
78 * @param mailbox A pointer to a variable to receive the InetMailbox object
79 * build from the extracted "Author" header.
80 * Undefined if the return value is not DSTAT_OK.
81 * @return DSTAT_OK for success, otherwise status code that indicates error.
82 * @error DSTAT_PERMFAIL_AUTHOR_AMBIGUOUS No or multiple Author headers are found
83 * @error DSTAT_PERMFAIL_AUTHOR_UNPARSABLE unable to parse Author header field value
84 * @error DSTAT_SYSERR_NORESOURCE memory allocation error
85 */
86 DkimStatus
DkimAuthor_extract(const DkimPolicyBase * policy,const MailHeaders * headers,size_t * header_index,const char ** header_field,const char ** header_value,InetMailbox ** mailbox)87 DkimAuthor_extract(const DkimPolicyBase *policy, const MailHeaders *headers, size_t *header_index,
88 const char **header_field, const char **header_value, InetMailbox **mailbox)
89 {
90 assert(NULL != policy);
91 assert(NULL != headers);
92 assert(NULL != mailbox);
93
94 size_t num = StrArray_getCount(policy->author_priority);
95 for (size_t i = 0; i < num; ++i) {
96 const char *targetField = StrArray_get(policy->author_priority, i);
97
98 bool multiple;
99 int index = MailHeaders_getHeaderIndex(headers, targetField, &multiple);
100 if (index < 0) {
101 // No headers looking for are found. Try next "Author"-candidate header.
102 continue;
103 } // end if
104 if (multiple) {
105 // Multiple "Author"-candidate headers are found. It must be unique.
106 DkimLogPermFail(policy, "Multiple %s Header is found, unable to extract Author",
107 targetField);
108 return DSTAT_PERMFAIL_AUTHOR_AMBIGUOUS;
109 } // end if
110
111 // An unique "Author" header is found.
112
113 // Extracts "mailbox" by parsing the found "Author" header.
114 const char *headerf, *headerv;
115 MailHeaders_get(headers, index, &headerf, &headerv);
116 DkimStatus dstat = DkimAuthor_parse(policy, headerv, STRTAIL(headerv), mailbox);
117 if (DSTAT_OK == dstat) {
118 // set the references to the original values if the parsing has succeeded.
119 SETDEREF(header_index, index);
120 SETDEREF(header_field, headerf);
121 SETDEREF(header_value, headerv);
122 } // end if
123 // If the parsing fails, this function returns an error
124 // whether or not next "Author"-candidate header is found.
125 return dstat;
126 } // end for
127
128 DkimLogPermFail(policy, "No Author header found");
129 return DSTAT_PERMFAIL_AUTHOR_AMBIGUOUS;
130 } // end function: DkimAuthor_extract
131