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 */ 53static int 54smbfs_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 142out: 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 */ 156int 157smbfs_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. */ 177int 178smbfs_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 */ 187int 188smbfs_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 */ 197int 198smbfs_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 */ 211int 212smbfs_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 */ 223int 224smbfs_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 */ 234int 235smb_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 */ 282int 283smbfs_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 315out: 316 smb_ctx_free(ctx); 317 return (err); 318} 319