1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/rcache/rc_dfl.c - default replay cache type */
3 /*
4 * Copyright (C) 2019 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * The dfl rcache type is a wrapper around the file2 rcache type, selecting a
35 * filename and (on Unix-like systems) applying open() safety appropriate for
36 * using a shared temporary directory.
37 */
38
39 #include "k5-int.h"
40 #include "rc-int.h"
41 #ifdef _WIN32
42 #include "../os/os-proto.h"
43 #else
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #endif
47
48 #ifdef _WIN32
49
50 static krb5_error_code
open_file(krb5_context context,int * fd_out)51 open_file(krb5_context context, int *fd_out)
52 {
53 krb5_error_code ret;
54 char *fname;
55 const char *dir;
56
57 *fd_out = -1;
58
59 dir = getenv("KRB5RCACHEDIR");
60 if (dir != NULL) {
61 if (asprintf(&fname, "%s\\krb5.rcache2") < 0)
62 return ENOMEM;
63 } else {
64 ret = k5_expand_path_tokens(context, "%{LOCAL_APPDATA}\\krb5.rcache2",
65 &fname);
66 if (ret)
67 return ret;
68 }
69
70 *fd_out = open(fname, O_CREAT | O_RDWR | O_BINARY, 0600);
71 ret = (*fd_out < 0) ? errno : 0;
72 if (ret) {
73 k5_setmsg(context, ret, "%s (filename: %s)",
74 error_message(ret), fname);
75 }
76 free(fname);
77 return ret;
78 }
79
80 #else /* _WIN32 */
81
82 static krb5_error_code
open_file(krb5_context context,int * fd_out)83 open_file(krb5_context context, int *fd_out)
84 {
85 krb5_error_code ret;
86 int fd = -1;
87 char *fname = NULL;
88 const char *dir;
89 struct stat statbuf;
90 uid_t euid = geteuid();
91
92 *fd_out = -1;
93
94 dir = secure_getenv("KRB5RCACHEDIR");
95 if (dir == NULL) {
96 dir = secure_getenv("TMPDIR");
97 if (dir == NULL)
98 dir = RCTMPDIR;
99 }
100 if (asprintf(&fname, "%s/krb5_%lu.rcache2", dir, (unsigned long)euid) < 0)
101 return ENOMEM;
102
103 fd = open(fname, O_CREAT | O_RDWR | O_NOFOLLOW, 0600);
104 if (fd < 0) {
105 ret = errno;
106 k5_setmsg(context, ret, "%s (filename: %s)",
107 error_message(ret), fname);
108 goto cleanup;
109 }
110
111 if (fstat(fd, &statbuf) < 0 || statbuf.st_uid != euid) {
112 ret = EIO;
113 k5_setmsg(context, ret, "Replay cache file %s is not owned by uid %lu",
114 fname, (unsigned long)euid);
115 goto cleanup;
116 }
117
118 *fd_out = fd;
119 fd = -1;
120 ret = 0;
121
122 cleanup:
123 if (fd != -1)
124 close(fd);
125 free(fname);
126 return ret;
127 }
128
129 #endif /* not _WIN32 */
130
131 static krb5_error_code
dfl_resolve(krb5_context context,const char * residual,void ** rcdata_out)132 dfl_resolve(krb5_context context, const char *residual, void **rcdata_out)
133 {
134 *rcdata_out = NULL;
135 return 0;
136 }
137
138 static void
dfl_close(krb5_context context,void * rcdata)139 dfl_close(krb5_context context, void *rcdata)
140 {
141 }
142
143 static krb5_error_code
dfl_store(krb5_context context,void * rcdata,const krb5_data * tag)144 dfl_store(krb5_context context, void *rcdata, const krb5_data *tag)
145 {
146 krb5_error_code ret;
147 int fd;
148
149 ret = open_file(context, &fd);
150 if (ret)
151 return ret;
152
153 ret = k5_rcfile2_store(context, fd, tag);
154 close(fd);
155 return ret;
156 }
157
158 const krb5_rc_ops k5_rc_dfl_ops =
159 {
160 "dfl",
161 dfl_resolve,
162 dfl_close,
163 dfl_store
164 };
165