1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * External interface to the libsmbfs/netsmb keychain 29 * storage mechanism. This interface is consumed by 30 * the "smbutil" commands: login, logout, ... 31 * and by the SMBFS PAM module. 32 */ 33 34 #include <sys/types.h> 35 36 #include <errno.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <libintl.h> 42 43 #include <cflib.h> 44 #include <netsmb/smb_dev.h> 45 #include <netsmb/smb_lib.h> 46 #include <netsmb/smb_keychain.h> 47 48 #include "charsets.h" 49 #include "private.h" 50 #include "ntlm.h" 51 52 /* common func. for add/del/chk */ 53 static int 54 smbfs_keychain_cmn( 55 int cmd, 56 uid_t uid, 57 const char *dom, 58 const char *usr, 59 uchar_t *lmhash, 60 uchar_t *nthash) 61 { 62 smbioc_pk_t pk; 63 int err, fd, sz; 64 65 memset(&pk, 0, sizeof (pk)); 66 pk.pk_uid = uid; 67 err = 0; 68 fd = -1; 69 70 switch (cmd) { 71 72 case SMBIOC_PK_ADD: 73 /* 74 * Add password hashes to the keychain. 75 */ 76 if (lmhash == NULL || nthash == NULL) { 77 err = SMB_KEYCHAIN_BADPASSWD; 78 goto out; 79 } 80 memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ); 81 memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ); 82 /* FALLTHROUGH */ 83 84 case SMBIOC_PK_CHK: 85 case SMBIOC_PK_DEL: 86 /* 87 * Copy domain and user. 88 */ 89 if (dom == NULL) { 90 err = SMB_KEYCHAIN_BADDOMAIN; 91 goto out; 92 } 93 sz = sizeof (pk.pk_dom); 94 if (strlcpy(pk.pk_dom, dom, sz) >= sz) { 95 err = SMB_KEYCHAIN_BADDOMAIN; 96 goto out; 97 } 98 if (usr == NULL) { 99 err = SMB_KEYCHAIN_BADUSER; 100 goto out; 101 } 102 sz = sizeof (pk.pk_usr); 103 if (strlcpy(pk.pk_usr, usr, sz) >= sz) { 104 err = SMB_KEYCHAIN_BADUSER; 105 goto out; 106 } 107 break; 108 109 case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */ 110 case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */ 111 /* 112 * These two do not copyin any args, but we'll 113 * pass pk here anyway just so we can use the 114 * common code path below. 115 */ 116 break; 117 118 default: 119 err = SMB_KEYCHAIN_UNKNOWN; 120 goto out; 121 } 122 123 fd = smb_open_driver(); 124 if (fd < 0) { 125 err = SMB_KEYCHAIN_NODRIVER; 126 goto out; 127 } 128 129 err = 0; 130 if (ioctl(fd, cmd, &pk) < 0) { 131 err = errno; 132 goto out; 133 } 134 135 if (cmd == SMBIOC_PK_CHK) { 136 if (lmhash != NULL) 137 memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ); 138 if (nthash != NULL) 139 memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ); 140 } 141 142 out: 143 if (fd != -1) 144 close(fd); 145 146 return (err); 147 } 148 149 /* 150 * Add a password to the keychain. 151 * 152 * Note: pass is a cleartext password. 153 * We use it here to compute the LM hash and NT hash, 154 * and then store ONLY the hashes. 155 */ 156 int 157 smbfs_keychain_add(uid_t uid, const char *dom, const char *usr, 158 const char *pass) 159 { 160 uchar_t lmhash[SMBIOC_HASH_SZ]; 161 uchar_t nthash[SMBIOC_HASH_SZ]; 162 int err, cmd = SMBIOC_PK_ADD; 163 164 if (pass == NULL) 165 return (SMB_KEYCHAIN_BADPASSWD); 166 167 if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0) 168 return (err); 169 if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0) 170 return (err); 171 172 err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 173 return (err); 174 } 175 176 /* Delete a password from the keychain. */ 177 int 178 smbfs_keychain_del(uid_t uid, const char *dom, const char *usr) 179 { 180 return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL)); 181 } 182 183 /* 184 * Check for existence of a keychain entry. 185 * Returns 0 if it exists, else ENOENT. 186 */ 187 int 188 smbfs_keychain_chk(const char *dom, const char *usr) 189 { 190 uid_t uid = (uid_t)-1; 191 return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL)); 192 } 193 194 /* 195 * Get the stored hashes 196 */ 197 int 198 smbfs_keychain_get(const char *dom, const char *usr, 199 uchar_t *lmhash, uchar_t *nthash) 200 { 201 uid_t uid = (uid_t)-1; 202 int err, cmd = SMBIOC_PK_CHK; 203 204 err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 205 return (err); 206 } 207 208 /* 209 * Delete all keychain entries owned by the caller. 210 */ 211 int 212 smbfs_keychain_del_owner() 213 { 214 int cmd = SMBIOC_PK_DEL_OWNER; 215 uid_t uid = getuid(); 216 return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 217 } 218 219 /* 220 * Delete all keychain entries (regardless of onwer). 221 * Requires super-user privliege. 222 */ 223 int 224 smbfs_keychain_del_everyone() 225 { 226 int cmd = SMBIOC_PK_DEL_EVERYONE; 227 uid_t uid = getuid(); 228 return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 229 } 230 231 /* 232 * Private function to get keychain p/w hashes. 233 */ 234 int 235 smb_get_keychain(struct smb_ctx *ctx) 236 { 237 int err; 238 239 if (ctx->ct_fullserver == NULL) { 240 DPRINT("ct_fullserver == NULL"); 241 return (EINVAL); 242 } 243 244 /* 245 * 1st: try lookup using system name 246 */ 247 err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user, 248 ctx->ct_lmhash, ctx->ct_nthash); 249 if (!err) { 250 ctx->ct_flags |= SMBCF_KCFOUND; 251 DPRINT("found keychain entry for" 252 " server/user: %s/%s\n", 253 ctx->ct_fullserver, ctx->ct_user); 254 return (0); 255 } 256 257 /* 258 * 2nd: try lookup using domain name 259 */ 260 err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user, 261 ctx->ct_lmhash, ctx->ct_nthash); 262 if (!err) { 263 ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN); 264 DPRINT("found keychain entry for" 265 " domain/user: %s/%s\n", 266 ctx->ct_domain, ctx->ct_user); 267 return (0); 268 } 269 270 return (err); 271 } 272 273 274 /* 275 * This is not really part of the keychain library, 276 * but is typically needed in code that wants to 277 * provide (editable) defaults for domain/user 278 * 279 * Get default domain and user names 280 * Server name is optional. 281 */ 282 int 283 smbfs_default_dom_usr(const char *home, const char *server, 284 char *dom, int maxdom, char *usr, int maxusr) 285 { 286 struct smb_ctx *ctx; 287 int err; 288 289 err = smb_ctx_alloc(&ctx); 290 if (err) 291 return (err); 292 293 if (server) { 294 err = smb_ctx_setfullserver(ctx, server); 295 if (err != 0) 296 goto out; 297 } 298 299 if (home && *home) { 300 if (ctx->ct_home) 301 free(ctx->ct_home); 302 ctx->ct_home = strdup(home); 303 } 304 305 err = smb_ctx_readrc(ctx); 306 if (err) 307 goto out; 308 309 if (dom) 310 strlcpy(dom, ctx->ct_domain, maxdom); 311 312 if (usr) 313 strlcpy(usr, ctx->ct_user, maxusr); 314 315 out: 316 smb_ctx_free(ctx); 317 return (err); 318 } 319