14bff34e3Sthurlow /* 24bff34e3Sthurlow * CDDL HEADER START 34bff34e3Sthurlow * 44bff34e3Sthurlow * The contents of this file are subject to the terms of the 54bff34e3Sthurlow * Common Development and Distribution License (the "License"). 64bff34e3Sthurlow * You may not use this file except in compliance with the License. 74bff34e3Sthurlow * 84bff34e3Sthurlow * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94bff34e3Sthurlow * or http://www.opensolaris.org/os/licensing. 104bff34e3Sthurlow * See the License for the specific language governing permissions 114bff34e3Sthurlow * and limitations under the License. 124bff34e3Sthurlow * 134bff34e3Sthurlow * When distributing Covered Code, include this CDDL HEADER in each 144bff34e3Sthurlow * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154bff34e3Sthurlow * If applicable, add the following below this CDDL HEADER, with the 164bff34e3Sthurlow * fields enclosed by brackets "[]" replaced with your own identifying 174bff34e3Sthurlow * information: Portions Copyright [yyyy] [name of copyright owner] 184bff34e3Sthurlow * 194bff34e3Sthurlow * CDDL HEADER END 204bff34e3Sthurlow */ 214bff34e3Sthurlow 224bff34e3Sthurlow /* 23*430b4c46SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 254bff34e3Sthurlow * Use is subject to license terms. 264bff34e3Sthurlow */ 274bff34e3Sthurlow 284bff34e3Sthurlow /* 294bff34e3Sthurlow * External interface to the libsmbfs/netsmb keychain 304bff34e3Sthurlow * storage mechanism. This interface is consumed by 314bff34e3Sthurlow * the "smbutil" commands: login, logout, ... 324bff34e3Sthurlow * and by the SMBFS PAM module. 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow #include <sys/types.h> 364bff34e3Sthurlow 374bff34e3Sthurlow #include <errno.h> 384bff34e3Sthurlow #include <stdio.h> 39613a2f6bSGordon Ross #include <stdlib.h> 404bff34e3Sthurlow #include <string.h> 414bff34e3Sthurlow #include <unistd.h> 424bff34e3Sthurlow #include <libintl.h> 434bff34e3Sthurlow 44613a2f6bSGordon Ross #include <cflib.h> 454bff34e3Sthurlow #include <netsmb/smb_dev.h> 464bff34e3Sthurlow #include <netsmb/smb_lib.h> 474bff34e3Sthurlow #include <netsmb/smb_keychain.h> 484bff34e3Sthurlow 49613a2f6bSGordon Ross #include "charsets.h" 50613a2f6bSGordon Ross #include "private.h" 51613a2f6bSGordon Ross #include "ntlm.h" 524bff34e3Sthurlow 534bff34e3Sthurlow /* common func. for add/del/chk */ 544bff34e3Sthurlow static int 554bff34e3Sthurlow smbfs_keychain_cmn( 564bff34e3Sthurlow int cmd, 574bff34e3Sthurlow uid_t uid, 584bff34e3Sthurlow const char *dom, 594bff34e3Sthurlow const char *usr, 60613a2f6bSGordon Ross uchar_t *lmhash, 61613a2f6bSGordon Ross uchar_t *nthash) 624bff34e3Sthurlow { 634bff34e3Sthurlow smbioc_pk_t pk; 64613a2f6bSGordon Ross int err, fd, sz; 654bff34e3Sthurlow 664bff34e3Sthurlow memset(&pk, 0, sizeof (pk)); 674bff34e3Sthurlow pk.pk_uid = uid; 68613a2f6bSGordon Ross err = 0; 69613a2f6bSGordon Ross fd = -1; 704bff34e3Sthurlow 714bff34e3Sthurlow switch (cmd) { 724bff34e3Sthurlow 734bff34e3Sthurlow case SMBIOC_PK_ADD: 74613a2f6bSGordon Ross /* 75613a2f6bSGordon Ross * Add password hashes to the keychain. 76613a2f6bSGordon Ross */ 77613a2f6bSGordon Ross if (lmhash == NULL || nthash == NULL) { 78613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADPASSWD; 79613a2f6bSGordon Ross goto out; 80613a2f6bSGordon Ross } 81613a2f6bSGordon Ross memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ); 82613a2f6bSGordon Ross memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ); 834bff34e3Sthurlow /* FALLTHROUGH */ 844bff34e3Sthurlow 854bff34e3Sthurlow case SMBIOC_PK_CHK: 864bff34e3Sthurlow case SMBIOC_PK_DEL: 87613a2f6bSGordon Ross /* 88613a2f6bSGordon Ross * Copy domain and user. 89613a2f6bSGordon Ross */ 90613a2f6bSGordon Ross if (dom == NULL) { 91613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADDOMAIN; 92613a2f6bSGordon Ross goto out; 93613a2f6bSGordon Ross } 94613a2f6bSGordon Ross sz = sizeof (pk.pk_dom); 95613a2f6bSGordon Ross if (strlcpy(pk.pk_dom, dom, sz) >= sz) { 96613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADDOMAIN; 97613a2f6bSGordon Ross goto out; 98613a2f6bSGordon Ross } 99613a2f6bSGordon Ross if (usr == NULL) { 100613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADUSER; 101613a2f6bSGordon Ross goto out; 102613a2f6bSGordon Ross } 103613a2f6bSGordon Ross sz = sizeof (pk.pk_usr); 104613a2f6bSGordon Ross if (strlcpy(pk.pk_usr, usr, sz) >= sz) { 105613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADUSER; 106613a2f6bSGordon Ross goto out; 107613a2f6bSGordon Ross } 1084bff34e3Sthurlow break; 1094bff34e3Sthurlow 1104bff34e3Sthurlow case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */ 1114bff34e3Sthurlow case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */ 1124bff34e3Sthurlow /* 1134bff34e3Sthurlow * These two do not copyin any args, but we'll 114613a2f6bSGordon Ross * pass pk here anyway just so we can use the 1154bff34e3Sthurlow * common code path below. 1164bff34e3Sthurlow */ 1174bff34e3Sthurlow break; 1184bff34e3Sthurlow 1194bff34e3Sthurlow default: 120613a2f6bSGordon Ross err = SMB_KEYCHAIN_UNKNOWN; 121613a2f6bSGordon Ross goto out; 1224bff34e3Sthurlow } 1234bff34e3Sthurlow 1244bff34e3Sthurlow fd = smb_open_driver(); 1254bff34e3Sthurlow if (fd < 0) { 1264bff34e3Sthurlow err = SMB_KEYCHAIN_NODRIVER; 1274bff34e3Sthurlow goto out; 1284bff34e3Sthurlow } 1294bff34e3Sthurlow 1304bff34e3Sthurlow err = 0; 131613a2f6bSGordon Ross if (ioctl(fd, cmd, &pk) < 0) { 1324bff34e3Sthurlow err = errno; 133613a2f6bSGordon Ross goto out; 134613a2f6bSGordon Ross } 1354bff34e3Sthurlow 136613a2f6bSGordon Ross if (cmd == SMBIOC_PK_CHK) { 137613a2f6bSGordon Ross if (lmhash != NULL) 138613a2f6bSGordon Ross memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ); 139613a2f6bSGordon Ross if (nthash != NULL) 140613a2f6bSGordon Ross memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ); 141613a2f6bSGordon Ross } 142613a2f6bSGordon Ross 1434bff34e3Sthurlow out: 144613a2f6bSGordon Ross if (fd != -1) 145613a2f6bSGordon Ross close(fd); 146613a2f6bSGordon Ross 1474bff34e3Sthurlow return (err); 1484bff34e3Sthurlow } 1494bff34e3Sthurlow 150613a2f6bSGordon Ross /* 151613a2f6bSGordon Ross * Add a password to the keychain. 152613a2f6bSGordon Ross * 153613a2f6bSGordon Ross * Note: pass is a cleartext password. 154613a2f6bSGordon Ross * We use it here to compute the LM hash and NT hash, 155613a2f6bSGordon Ross * and then store ONLY the hashes. 156613a2f6bSGordon Ross */ 1574bff34e3Sthurlow int 1584bff34e3Sthurlow smbfs_keychain_add(uid_t uid, const char *dom, const char *usr, 1594bff34e3Sthurlow const char *pass) 1604bff34e3Sthurlow { 161613a2f6bSGordon Ross uchar_t lmhash[SMBIOC_HASH_SZ]; 162613a2f6bSGordon Ross uchar_t nthash[SMBIOC_HASH_SZ]; 163613a2f6bSGordon Ross int err, cmd = SMBIOC_PK_ADD; 164613a2f6bSGordon Ross 165613a2f6bSGordon Ross if (pass == NULL) 166613a2f6bSGordon Ross return (SMB_KEYCHAIN_BADPASSWD); 167613a2f6bSGordon Ross 168613a2f6bSGordon Ross if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0) 169613a2f6bSGordon Ross return (err); 170613a2f6bSGordon Ross if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0) 171613a2f6bSGordon Ross return (err); 172613a2f6bSGordon Ross 173613a2f6bSGordon Ross err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 174613a2f6bSGordon Ross return (err); 1754bff34e3Sthurlow } 1764bff34e3Sthurlow 177*430b4c46SGordon Ross /* Variant of the above that takes an NT hash. */ 178*430b4c46SGordon Ross int 179*430b4c46SGordon Ross smbfs_keychain_addhash(uid_t uid, const char *dom, const char *usr, 180*430b4c46SGordon Ross const uchar_t *nthash) 181*430b4c46SGordon Ross { 182*430b4c46SGordon Ross static const uchar_t lmhash[SMBIOC_HASH_SZ] = { 0 }; 183*430b4c46SGordon Ross int err, cmd = SMBIOC_PK_ADD; 184*430b4c46SGordon Ross err = smbfs_keychain_cmn(cmd, uid, dom, usr, 185*430b4c46SGordon Ross (uchar_t *)lmhash, (uchar_t *)nthash); 186*430b4c46SGordon Ross return (err); 187*430b4c46SGordon Ross } 188*430b4c46SGordon Ross 1894bff34e3Sthurlow /* Delete a password from the keychain. */ 1904bff34e3Sthurlow int 1914bff34e3Sthurlow smbfs_keychain_del(uid_t uid, const char *dom, const char *usr) 1924bff34e3Sthurlow { 193613a2f6bSGordon Ross return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL)); 1944bff34e3Sthurlow } 1954bff34e3Sthurlow 1964bff34e3Sthurlow /* 1974bff34e3Sthurlow * Check for existence of a keychain entry. 1984bff34e3Sthurlow * Returns 0 if it exists, else ENOENT. 1994bff34e3Sthurlow */ 2004bff34e3Sthurlow int 2014bff34e3Sthurlow smbfs_keychain_chk(const char *dom, const char *usr) 2024bff34e3Sthurlow { 203613a2f6bSGordon Ross uid_t uid = (uid_t)-1; 204613a2f6bSGordon Ross return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL)); 205613a2f6bSGordon Ross } 206613a2f6bSGordon Ross 207613a2f6bSGordon Ross /* 208613a2f6bSGordon Ross * Get the stored hashes 209613a2f6bSGordon Ross */ 210613a2f6bSGordon Ross int 211613a2f6bSGordon Ross smbfs_keychain_get(const char *dom, const char *usr, 212613a2f6bSGordon Ross uchar_t *lmhash, uchar_t *nthash) 213613a2f6bSGordon Ross { 214613a2f6bSGordon Ross uid_t uid = (uid_t)-1; 215613a2f6bSGordon Ross int err, cmd = SMBIOC_PK_CHK; 216613a2f6bSGordon Ross 217613a2f6bSGordon Ross err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 218613a2f6bSGordon Ross return (err); 2194bff34e3Sthurlow } 2204bff34e3Sthurlow 2214bff34e3Sthurlow /* 2224bff34e3Sthurlow * Delete all keychain entries owned by the caller. 2234bff34e3Sthurlow */ 2244bff34e3Sthurlow int 2254bff34e3Sthurlow smbfs_keychain_del_owner() 2264bff34e3Sthurlow { 227613a2f6bSGordon Ross int cmd = SMBIOC_PK_DEL_OWNER; 228613a2f6bSGordon Ross uid_t uid = getuid(); 229613a2f6bSGordon Ross return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 2304bff34e3Sthurlow } 2314bff34e3Sthurlow 2324bff34e3Sthurlow /* 2334bff34e3Sthurlow * Delete all keychain entries (regardless of onwer). 2344bff34e3Sthurlow * Requires super-user privliege. 2354bff34e3Sthurlow */ 2364bff34e3Sthurlow int 2374bff34e3Sthurlow smbfs_keychain_del_everyone() 2384bff34e3Sthurlow { 239613a2f6bSGordon Ross int cmd = SMBIOC_PK_DEL_EVERYONE; 240613a2f6bSGordon Ross uid_t uid = getuid(); 241613a2f6bSGordon Ross return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 242613a2f6bSGordon Ross } 243613a2f6bSGordon Ross 244613a2f6bSGordon Ross /* 245613a2f6bSGordon Ross * Private function to get keychain p/w hashes. 246613a2f6bSGordon Ross */ 247613a2f6bSGordon Ross int 248613a2f6bSGordon Ross smb_get_keychain(struct smb_ctx *ctx) 249613a2f6bSGordon Ross { 250613a2f6bSGordon Ross int err; 251613a2f6bSGordon Ross 252613a2f6bSGordon Ross if (ctx->ct_fullserver == NULL) { 253613a2f6bSGordon Ross DPRINT("ct_fullserver == NULL"); 254613a2f6bSGordon Ross return (EINVAL); 255613a2f6bSGordon Ross } 256613a2f6bSGordon Ross 257613a2f6bSGordon Ross /* 258613a2f6bSGordon Ross * 1st: try lookup using system name 259613a2f6bSGordon Ross */ 260613a2f6bSGordon Ross err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user, 261613a2f6bSGordon Ross ctx->ct_lmhash, ctx->ct_nthash); 262613a2f6bSGordon Ross if (!err) { 263613a2f6bSGordon Ross ctx->ct_flags |= SMBCF_KCFOUND; 264613a2f6bSGordon Ross DPRINT("found keychain entry for" 265613a2f6bSGordon Ross " server/user: %s/%s\n", 266613a2f6bSGordon Ross ctx->ct_fullserver, ctx->ct_user); 267613a2f6bSGordon Ross return (0); 268613a2f6bSGordon Ross } 269613a2f6bSGordon Ross 270613a2f6bSGordon Ross /* 271613a2f6bSGordon Ross * 2nd: try lookup using domain name 272613a2f6bSGordon Ross */ 273613a2f6bSGordon Ross err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user, 274613a2f6bSGordon Ross ctx->ct_lmhash, ctx->ct_nthash); 275613a2f6bSGordon Ross if (!err) { 276613a2f6bSGordon Ross ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN); 277613a2f6bSGordon Ross DPRINT("found keychain entry for" 278613a2f6bSGordon Ross " domain/user: %s/%s\n", 279613a2f6bSGordon Ross ctx->ct_domain, ctx->ct_user); 280613a2f6bSGordon Ross return (0); 281613a2f6bSGordon Ross } 282613a2f6bSGordon Ross 283613a2f6bSGordon Ross return (err); 2844bff34e3Sthurlow } 2854bff34e3Sthurlow 2864bff34e3Sthurlow 2874bff34e3Sthurlow /* 2884bff34e3Sthurlow * This is not really part of the keychain library, 2894bff34e3Sthurlow * but is typically needed in code that wants to 2904bff34e3Sthurlow * provide (editable) defaults for domain/user 2914bff34e3Sthurlow * 2924bff34e3Sthurlow * Get default domain and user names 2934bff34e3Sthurlow * Server name is optional. 2944bff34e3Sthurlow */ 2954bff34e3Sthurlow int 2964bff34e3Sthurlow smbfs_default_dom_usr(const char *home, const char *server, 2974bff34e3Sthurlow char *dom, int maxdom, char *usr, int maxusr) 2984bff34e3Sthurlow { 299613a2f6bSGordon Ross struct smb_ctx *ctx; 3004bff34e3Sthurlow int err; 3014bff34e3Sthurlow 302613a2f6bSGordon Ross err = smb_ctx_alloc(&ctx); 3034bff34e3Sthurlow if (err) 3044bff34e3Sthurlow return (err); 305613a2f6bSGordon Ross 30602d09e03SGordon Ross if (server) { 30702d09e03SGordon Ross err = smb_ctx_setfullserver(ctx, server); 30802d09e03SGordon Ross if (err != 0) 30902d09e03SGordon Ross goto out; 31002d09e03SGordon Ross } 311613a2f6bSGordon Ross 312613a2f6bSGordon Ross if (home && *home) { 313613a2f6bSGordon Ross if (ctx->ct_home) 314613a2f6bSGordon Ross free(ctx->ct_home); 315613a2f6bSGordon Ross ctx->ct_home = strdup(home); 316613a2f6bSGordon Ross } 317613a2f6bSGordon Ross 3184bff34e3Sthurlow err = smb_ctx_readrc(ctx); 3194bff34e3Sthurlow if (err) 320613a2f6bSGordon Ross goto out; 3214bff34e3Sthurlow 3224bff34e3Sthurlow if (dom) 323613a2f6bSGordon Ross strlcpy(dom, ctx->ct_domain, maxdom); 3244bff34e3Sthurlow 3254bff34e3Sthurlow if (usr) 326613a2f6bSGordon Ross strlcpy(usr, ctx->ct_user, maxusr); 3274bff34e3Sthurlow 328613a2f6bSGordon Ross out: 329613a2f6bSGordon Ross smb_ctx_free(ctx); 330613a2f6bSGordon Ross return (err); 3314bff34e3Sthurlow } 332