~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/auth/auth-token.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
 
2
 
 
3
/* Auth process maintains a random secret. Once a user authenticates the
 
4
   response to the REQUEST command from a master service is augmented with an
 
5
   auth_token value. This token is the SHA1 hash of the secret, the service
 
6
   name and the username of the user that just logged in. Using this token the
 
7
   service (e.g. imap) can login to another service (e.g. imap-urlauth) to
 
8
   gain access to resources that require additional privileges (e.g. another
 
9
   user's e-mail).
 
10
*/
 
11
 
 
12
#include "auth-common.h"
 
13
#include "hex-binary.h"
 
14
#include "hmac.h"
 
15
#include "sha1.h"
 
16
#include "randgen.h"
 
17
#include "read-full.h"
 
18
#include "write-full.h"
 
19
#include "safe-memset.h"
 
20
#include "auth-settings.h"
 
21
#include "auth-token.h"
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <fcntl.h>
 
26
#include <unistd.h>
 
27
#include <sys/types.h>
 
28
#include <sys/stat.h>
 
29
 
 
30
#define AUTH_TOKEN_SECRET_LEN 32
 
31
 
 
32
#define AUTH_TOKEN_SECRET_FNAME "auth-token-secret.dat"
 
33
 
 
34
static unsigned char auth_token_secret[AUTH_TOKEN_SECRET_LEN];
 
35
 
 
36
static int
 
37
auth_token_read_secret(const char *path,
 
38
                       unsigned char secret_r[AUTH_TOKEN_SECRET_LEN])
 
39
{
 
40
        struct stat st, lst;
 
41
        int fd, ret;            
 
42
 
 
43
        fd = open(path, O_RDONLY);
 
44
        if (fd == -1) {
 
45
                if (errno != ENOENT)
 
46
                        i_error("open(%s) failed: %m", path);
 
47
                return -1;
 
48
        }
 
49
 
 
50
        if (fstat(fd, &st) < 0) {
 
51
                i_error("fstat(%s) failed: %m", path);
 
52
                i_close_fd(&fd);
 
53
                return -1;
 
54
        }
 
55
 
 
56
        /* check secret len and file type */
 
57
        if (st.st_size != AUTH_TOKEN_SECRET_LEN || !S_ISREG(st.st_mode)) {
 
58
                i_error("Corrupted token secret file: %s", path);
 
59
                i_close_fd(&fd);
 
60
                if (unlink(path) < 0)
 
61
                        i_error("unlink(%s) failed: %m", path);
 
62
                return -1;
 
63
        }
 
64
 
 
65
        /* verify that we're not dealing with a symbolic link */
 
66
        if (lstat(path, &lst) < 0) {
 
67
                i_error("lstat(%s) failed: %m", path);
 
68
                i_close_fd(&fd);
 
69
                return -1;              
 
70
        }
 
71
 
 
72
        /* check security parameters for compromise */
 
73
        if ((st.st_mode & 07777) != 0600 ||
 
74
            st.st_uid != geteuid() || st.st_nlink > 1 ||
 
75
            !S_ISREG(lst.st_mode) || st.st_ino != lst.st_ino ||
 
76
            !CMP_DEV_T(st.st_dev, lst.st_dev)) {
 
77
                i_error("Compromised token secret file: %s", path);
 
78
                i_close_fd(&fd);
 
79
                if (unlink(path) < 0)
 
80
                        i_error("unlink(%s) failed: %m", path);
 
81
                return -1;
 
82
        }
 
83
 
 
84
        /* FIXME: fail here to generate new secret if stored one is too old */
 
85
 
 
86
        ret = read_full(fd, secret_r, AUTH_TOKEN_SECRET_LEN);
 
87
        if (ret < 0)
 
88
                i_error("read(%s) failed: %m", path);
 
89
        else if (ret == 0) {
 
90
                i_error("Token secret file unexpectedly shrank: %s", path);
 
91
                ret = -1;
 
92
        }
 
93
        if (close(fd) < 0)
 
94
                i_error("close(%s) failed: %m", path);
 
95
 
 
96
        if (global_auth_settings->debug)
 
97
                i_debug("Read auth token secret from %s", path);
 
98
        return ret;
 
99
}
 
100
 
 
101
static int
 
102
auth_token_write_secret(const char *path,
 
103
                        const unsigned char secret[AUTH_TOKEN_SECRET_LEN])
 
104
{
 
105
        const char *temp_path;
 
106
        mode_t old_mask;
 
107
        int fd, ret;
 
108
 
 
109
        temp_path = t_strconcat(path, ".tmp", NULL);
 
110
 
 
111
        old_mask = umask(0);
 
112
        fd = open(temp_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
 
113
        umask(old_mask);
 
114
 
 
115
        if (fd == -1) {
 
116
                i_error("open(%s) failed: %m", temp_path);
 
117
                return -1;
 
118
        }
 
119
 
 
120
        ret = write_full(fd, secret, AUTH_TOKEN_SECRET_LEN);
 
121
        if (ret < 0)
 
122
                i_error("write(%s) failed: %m", temp_path);
 
123
        if (close(fd) < 0) {
 
124
                i_error("close(%s) failed: %m", temp_path);
 
125
                ret = -1;
 
126
        }
 
127
 
 
128
        if (ret < 0) {
 
129
                if (unlink(temp_path) < 0)
 
130
                        i_error("unlink(%s) failed: %m", temp_path);
 
131
                return -1;
 
132
        }
 
133
 
 
134
        if (rename(temp_path, path) < 0) {
 
135
                i_error("rename(%s, %s) failed: %m", temp_path, path);
 
136
                if (unlink(temp_path) < 0)
 
137
                        i_error("unlink(%s) failed: %m", temp_path);
 
138
                return -1;
 
139
        }
 
140
 
 
141
        if (global_auth_settings->debug)
 
142
                i_debug("Wrote new auth token secret to %s", path);
 
143
        return 0;
 
144
}
 
145
 
 
146
void auth_token_init(void)
 
147
{
 
148
        const char *secret_path =
 
149
                t_strconcat(global_auth_settings->base_dir, "/",
 
150
                            AUTH_TOKEN_SECRET_FNAME, NULL);
 
151
 
 
152
        if (auth_token_read_secret(secret_path, auth_token_secret) < 0) {
 
153
                random_fill(auth_token_secret, sizeof(auth_token_secret));
 
154
 
 
155
                if (auth_token_write_secret(secret_path, auth_token_secret) < 0) {
 
156
                        i_error("Failed to write auth token secret file; "
 
157
                                "returned tokens will be invalid once auth restarts");
 
158
                }
 
159
        }
 
160
}
 
161
 
 
162
void auth_token_deinit(void)
 
163
{
 
164
        /* not very useful, but we do it anyway */
 
165
        safe_memset(auth_token_secret, 0, sizeof(auth_token_secret));
 
166
}
 
167
 
 
168
const char *auth_token_get(const char *service, const char *session_pid,
 
169
                           const char *username, const char *session_id)
 
170
{
 
171
        struct hmac_context ctx;
 
172
        unsigned char result[SHA1_RESULTLEN];
 
173
 
 
174
        hmac_init(&ctx, (const unsigned char*)username, strlen(username),
 
175
                  &hash_method_sha1);
 
176
        hmac_update(&ctx, session_pid, strlen(session_pid));
 
177
        if (session_id != NULL && *session_id != '\0')
 
178
                hmac_update(&ctx, session_id, strlen(session_id));
 
179
        hmac_update(&ctx, service, strlen(service));
 
180
        hmac_update(&ctx, auth_token_secret, sizeof(auth_token_secret));
 
181
        hmac_final(&ctx, result);
 
182
 
 
183
        return binary_to_hex(result, sizeof(result));
 
184
}