1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
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
12
#include "auth-common.h"
13
#include "hex-binary.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"
27
#include <sys/types.h>
30
#define AUTH_TOKEN_SECRET_LEN 32
32
#define AUTH_TOKEN_SECRET_FNAME "auth-token-secret.dat"
34
static unsigned char auth_token_secret[AUTH_TOKEN_SECRET_LEN];
37
auth_token_read_secret(const char *path,
38
unsigned char secret_r[AUTH_TOKEN_SECRET_LEN])
43
fd = open(path, O_RDONLY);
46
i_error("open(%s) failed: %m", path);
50
if (fstat(fd, &st) < 0) {
51
i_error("fstat(%s) failed: %m", path);
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);
61
i_error("unlink(%s) failed: %m", path);
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);
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);
80
i_error("unlink(%s) failed: %m", path);
84
/* FIXME: fail here to generate new secret if stored one is too old */
86
ret = read_full(fd, secret_r, AUTH_TOKEN_SECRET_LEN);
88
i_error("read(%s) failed: %m", path);
90
i_error("Token secret file unexpectedly shrank: %s", path);
94
i_error("close(%s) failed: %m", path);
96
if (global_auth_settings->debug)
97
i_debug("Read auth token secret from %s", path);
102
auth_token_write_secret(const char *path,
103
const unsigned char secret[AUTH_TOKEN_SECRET_LEN])
105
const char *temp_path;
109
temp_path = t_strconcat(path, ".tmp", NULL);
112
fd = open(temp_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
116
i_error("open(%s) failed: %m", temp_path);
120
ret = write_full(fd, secret, AUTH_TOKEN_SECRET_LEN);
122
i_error("write(%s) failed: %m", temp_path);
124
i_error("close(%s) failed: %m", temp_path);
129
if (unlink(temp_path) < 0)
130
i_error("unlink(%s) failed: %m", temp_path);
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);
141
if (global_auth_settings->debug)
142
i_debug("Wrote new auth token secret to %s", path);
146
void auth_token_init(void)
148
const char *secret_path =
149
t_strconcat(global_auth_settings->base_dir, "/",
150
AUTH_TOKEN_SECRET_FNAME, NULL);
152
if (auth_token_read_secret(secret_path, auth_token_secret) < 0) {
153
random_fill(auth_token_secret, sizeof(auth_token_secret));
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");
162
void auth_token_deinit(void)
164
/* not very useful, but we do it anyway */
165
safe_memset(auth_token_secret, 0, sizeof(auth_token_secret));
168
const char *auth_token_get(const char *service, const char *session_pid,
169
const char *username, const char *session_id)
171
struct hmac_context ctx;
172
unsigned char result[SHA1_RESULTLEN];
174
hmac_init(&ctx, (const unsigned char*)username, strlen(username),
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);
183
return binary_to_hex(result, sizeof(result));