1 1.3 christos /* $NetBSD: client.c,v 1.4 2023/06/19 21:41:41 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 2005, PADL Software Pty Ltd. 5 1.1 elric * All rights reserved. 6 1.1 elric * 7 1.1 elric * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 8 1.1 elric * 9 1.1 elric * Redistribution and use in source and binary forms, with or without 10 1.1 elric * modification, are permitted provided that the following conditions 11 1.1 elric * are met: 12 1.1 elric * 13 1.1 elric * 1. Redistributions of source code must retain the above copyright 14 1.1 elric * notice, this list of conditions and the following disclaimer. 15 1.1 elric * 16 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 elric * notice, this list of conditions and the following disclaimer in the 18 1.1 elric * documentation and/or other materials provided with the distribution. 19 1.1 elric * 20 1.1 elric * 3. Neither the name of PADL Software nor the names of its contributors 21 1.1 elric * may be used to endorse or promote products derived from this software 22 1.1 elric * without specific prior written permission. 23 1.1 elric * 24 1.1 elric * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 25 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 28 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 elric * SUCH DAMAGE. 35 1.1 elric */ 36 1.1 elric 37 1.1 elric #include "kcm_locl.h" 38 1.1 elric #include <pwd.h> 39 1.1 elric 40 1.1 elric krb5_error_code 41 1.1 elric kcm_ccache_resolve_client(krb5_context context, 42 1.1 elric kcm_client *client, 43 1.1 elric kcm_operation opcode, 44 1.1 elric const char *name, 45 1.1 elric kcm_ccache *ccache) 46 1.1 elric { 47 1.1 elric krb5_error_code ret; 48 1.2 christos const char *estr; 49 1.1 elric 50 1.1 elric ret = kcm_ccache_resolve(context, name, ccache); 51 1.1 elric if (ret) { 52 1.2 christos estr = krb5_get_error_message(context, ret); 53 1.2 christos kcm_log(1, "Failed to resolve cache %s: %s", name, estr); 54 1.2 christos krb5_free_error_message(context, estr); 55 1.1 elric return ret; 56 1.1 elric } 57 1.1 elric 58 1.1 elric ret = kcm_access(context, client, opcode, *ccache); 59 1.1 elric if (ret) { 60 1.1 elric ret = KRB5_FCC_NOFILE; /* don't disclose */ 61 1.1 elric kcm_release_ccache(context, *ccache); 62 1.1 elric } 63 1.1 elric 64 1.1 elric return ret; 65 1.1 elric } 66 1.1 elric 67 1.1 elric krb5_error_code 68 1.1 elric kcm_ccache_destroy_client(krb5_context context, 69 1.1 elric kcm_client *client, 70 1.1 elric const char *name) 71 1.1 elric { 72 1.1 elric krb5_error_code ret; 73 1.1 elric kcm_ccache ccache; 74 1.2 christos const char *estr; 75 1.1 elric 76 1.1 elric ret = kcm_ccache_resolve(context, name, &ccache); 77 1.1 elric if (ret) { 78 1.2 christos estr = krb5_get_error_message(context, ret); 79 1.2 christos kcm_log(1, "Failed to resolve cache %s: %s", name, estr); 80 1.2 christos krb5_free_error_message(context, estr); 81 1.1 elric return ret; 82 1.1 elric } 83 1.1 elric 84 1.1 elric ret = kcm_access(context, client, KCM_OP_DESTROY, ccache); 85 1.1 elric kcm_cleanup_events(context, ccache); 86 1.1 elric kcm_release_ccache(context, ccache); 87 1.1 elric if (ret) 88 1.1 elric return ret; 89 1.1 elric 90 1.1 elric return kcm_ccache_destroy(context, name); 91 1.1 elric } 92 1.1 elric 93 1.1 elric krb5_error_code 94 1.1 elric kcm_ccache_new_client(krb5_context context, 95 1.1 elric kcm_client *client, 96 1.1 elric const char *name, 97 1.1 elric kcm_ccache *ccache_p) 98 1.1 elric { 99 1.1 elric krb5_error_code ret; 100 1.1 elric kcm_ccache ccache; 101 1.2 christos const char *estr; 102 1.1 elric 103 1.1 elric /* We insist the ccache name starts with UID or UID: */ 104 1.1 elric if (name_constraints != 0) { 105 1.1 elric char prefix[64]; 106 1.1 elric size_t prefix_len; 107 1.1 elric int bad = 1; 108 1.1 elric 109 1.1 elric snprintf(prefix, sizeof(prefix), "%ld:", (long)client->uid); 110 1.1 elric prefix_len = strlen(prefix); 111 1.1 elric 112 1.1 elric if (strncmp(name, prefix, prefix_len) == 0) 113 1.1 elric bad = 0; 114 1.1 elric else { 115 1.1 elric prefix[prefix_len - 1] = '\0'; 116 1.1 elric if (strcmp(name, prefix) == 0) 117 1.1 elric bad = 0; 118 1.1 elric } 119 1.1 elric 120 1.1 elric /* Allow root to create badly-named ccaches */ 121 1.1 elric if (bad && !CLIENT_IS_ROOT(client)) 122 1.1 elric return KRB5_CC_BADNAME; 123 1.1 elric } 124 1.2 christos 125 1.1 elric ret = kcm_ccache_resolve(context, name, &ccache); 126 1.1 elric if (ret == 0) { 127 1.1 elric if ((ccache->uid != client->uid || 128 1.1 elric ccache->gid != client->gid) && !CLIENT_IS_ROOT(client)) 129 1.1 elric return KRB5_FCC_PERM; 130 1.1 elric } else if (ret != KRB5_FCC_NOFILE && !(CLIENT_IS_ROOT(client) && ret == KRB5_FCC_PERM)) { 131 1.1 elric return ret; 132 1.1 elric } 133 1.1 elric 134 1.1 elric if (ret == KRB5_FCC_NOFILE) { 135 1.1 elric ret = kcm_ccache_new(context, name, &ccache); 136 1.1 elric if (ret) { 137 1.2 christos estr = krb5_get_error_message(context, ret); 138 1.2 christos kcm_log(1, "Failed to initialize cache %s: %s", name, estr); 139 1.2 christos krb5_free_error_message(context, estr); 140 1.1 elric return ret; 141 1.1 elric } 142 1.1 elric 143 1.1 elric /* bind to current client */ 144 1.1 elric ccache->uid = client->uid; 145 1.1 elric ccache->gid = client->gid; 146 1.1 elric ccache->session = client->session; 147 1.1 elric } else { 148 1.1 elric ret = kcm_zero_ccache_data(context, ccache); 149 1.1 elric if (ret) { 150 1.2 christos estr = krb5_get_error_message(context, ret); 151 1.2 christos kcm_log(1, "Failed to empty cache %s: %s", name, estr); 152 1.2 christos krb5_free_error_message(context, estr); 153 1.1 elric kcm_release_ccache(context, ccache); 154 1.1 elric return ret; 155 1.1 elric } 156 1.1 elric kcm_cleanup_events(context, ccache); 157 1.1 elric } 158 1.1 elric 159 1.1 elric ret = kcm_access(context, client, KCM_OP_INITIALIZE, ccache); 160 1.1 elric if (ret) { 161 1.1 elric kcm_release_ccache(context, ccache); 162 1.1 elric kcm_ccache_destroy(context, name); 163 1.1 elric return ret; 164 1.1 elric } 165 1.1 elric 166 1.1 elric /* 167 1.1 elric * Finally, if the user is root and the cache was created under 168 1.1 elric * another user's name, chown the cache to that user and their 169 1.1 elric * default gid. 170 1.1 elric */ 171 1.1 elric if (CLIENT_IS_ROOT(client)) { 172 1.1 elric unsigned long uid; 173 1.1 elric int matches = sscanf(name,"%ld:",&uid); 174 1.1 elric if (matches == 0) 175 1.1 elric matches = sscanf(name,"%ld",&uid); 176 1.1 elric if (matches == 1) { 177 1.3 christos struct passwd pw, *pwd = NULL; 178 1.3 christos char pwbuf[2048]; 179 1.3 christos 180 1.3 christos if (rk_getpwuid_r(getuid(), &pw, pwbuf, sizeof(pwbuf), &pwd) == 0) { 181 1.1 elric gid_t gid = pwd->pw_gid; 182 1.1 elric kcm_chown(context, client, ccache, uid, gid); 183 1.1 elric } 184 1.1 elric } 185 1.1 elric } 186 1.1 elric 187 1.1 elric *ccache_p = ccache; 188 1.1 elric return 0; 189 1.1 elric } 190 1.1 elric 191