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 /* 23613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 244bff34e3Sthurlow * Use is subject to license terms. 254bff34e3Sthurlow */ 264bff34e3Sthurlow 274bff34e3Sthurlow /* 284bff34e3Sthurlow * External interface to the libsmbfs/netsmb keychain 294bff34e3Sthurlow * storage mechanism. This interface is consumed by 304bff34e3Sthurlow * the "smbutil" commands: login, logout, ... 314bff34e3Sthurlow * and by the SMBFS PAM module. 324bff34e3Sthurlow */ 334bff34e3Sthurlow 344bff34e3Sthurlow #include <sys/types.h> 354bff34e3Sthurlow 364bff34e3Sthurlow #include <errno.h> 374bff34e3Sthurlow #include <stdio.h> 38613a2f6bSGordon Ross #include <stdlib.h> 394bff34e3Sthurlow #include <string.h> 404bff34e3Sthurlow #include <unistd.h> 414bff34e3Sthurlow #include <libintl.h> 424bff34e3Sthurlow 43613a2f6bSGordon Ross #include <cflib.h> 444bff34e3Sthurlow #include <netsmb/smb_dev.h> 454bff34e3Sthurlow #include <netsmb/smb_lib.h> 464bff34e3Sthurlow #include <netsmb/smb_keychain.h> 474bff34e3Sthurlow 48613a2f6bSGordon Ross #include "charsets.h" 49613a2f6bSGordon Ross #include "private.h" 50613a2f6bSGordon Ross #include "ntlm.h" 514bff34e3Sthurlow 524bff34e3Sthurlow /* common func. for add/del/chk */ 534bff34e3Sthurlow static int 544bff34e3Sthurlow smbfs_keychain_cmn( 554bff34e3Sthurlow int cmd, 564bff34e3Sthurlow uid_t uid, 574bff34e3Sthurlow const char *dom, 584bff34e3Sthurlow const char *usr, 59613a2f6bSGordon Ross uchar_t *lmhash, 60613a2f6bSGordon Ross uchar_t *nthash) 614bff34e3Sthurlow { 624bff34e3Sthurlow smbioc_pk_t pk; 63613a2f6bSGordon Ross int err, fd, sz; 644bff34e3Sthurlow 654bff34e3Sthurlow memset(&pk, 0, sizeof (pk)); 664bff34e3Sthurlow pk.pk_uid = uid; 67613a2f6bSGordon Ross err = 0; 68613a2f6bSGordon Ross fd = -1; 694bff34e3Sthurlow 704bff34e3Sthurlow switch (cmd) { 714bff34e3Sthurlow 724bff34e3Sthurlow case SMBIOC_PK_ADD: 73613a2f6bSGordon Ross /* 74613a2f6bSGordon Ross * Add password hashes to the keychain. 75613a2f6bSGordon Ross */ 76613a2f6bSGordon Ross if (lmhash == NULL || nthash == NULL) { 77613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADPASSWD; 78613a2f6bSGordon Ross goto out; 79613a2f6bSGordon Ross } 80613a2f6bSGordon Ross memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ); 81613a2f6bSGordon Ross memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ); 824bff34e3Sthurlow /* FALLTHROUGH */ 834bff34e3Sthurlow 844bff34e3Sthurlow case SMBIOC_PK_CHK: 854bff34e3Sthurlow case SMBIOC_PK_DEL: 86613a2f6bSGordon Ross /* 87613a2f6bSGordon Ross * Copy domain and user. 88613a2f6bSGordon Ross */ 89613a2f6bSGordon Ross if (dom == NULL) { 90613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADDOMAIN; 91613a2f6bSGordon Ross goto out; 92613a2f6bSGordon Ross } 93613a2f6bSGordon Ross sz = sizeof (pk.pk_dom); 94613a2f6bSGordon Ross if (strlcpy(pk.pk_dom, dom, sz) >= sz) { 95613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADDOMAIN; 96613a2f6bSGordon Ross goto out; 97613a2f6bSGordon Ross } 98613a2f6bSGordon Ross if (usr == NULL) { 99613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADUSER; 100613a2f6bSGordon Ross goto out; 101613a2f6bSGordon Ross } 102613a2f6bSGordon Ross sz = sizeof (pk.pk_usr); 103613a2f6bSGordon Ross if (strlcpy(pk.pk_usr, usr, sz) >= sz) { 104613a2f6bSGordon Ross err = SMB_KEYCHAIN_BADUSER; 105613a2f6bSGordon Ross goto out; 106613a2f6bSGordon Ross } 1074bff34e3Sthurlow break; 1084bff34e3Sthurlow 1094bff34e3Sthurlow case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */ 1104bff34e3Sthurlow case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */ 1114bff34e3Sthurlow /* 1124bff34e3Sthurlow * These two do not copyin any args, but we'll 113613a2f6bSGordon Ross * pass pk here anyway just so we can use the 1144bff34e3Sthurlow * common code path below. 1154bff34e3Sthurlow */ 1164bff34e3Sthurlow break; 1174bff34e3Sthurlow 1184bff34e3Sthurlow default: 119613a2f6bSGordon Ross err = SMB_KEYCHAIN_UNKNOWN; 120613a2f6bSGordon Ross goto out; 1214bff34e3Sthurlow } 1224bff34e3Sthurlow 1234bff34e3Sthurlow fd = smb_open_driver(); 1244bff34e3Sthurlow if (fd < 0) { 1254bff34e3Sthurlow err = SMB_KEYCHAIN_NODRIVER; 1264bff34e3Sthurlow goto out; 1274bff34e3Sthurlow } 1284bff34e3Sthurlow 1294bff34e3Sthurlow err = 0; 130613a2f6bSGordon Ross if (ioctl(fd, cmd, &pk) < 0) { 1314bff34e3Sthurlow err = errno; 132613a2f6bSGordon Ross goto out; 133613a2f6bSGordon Ross } 1344bff34e3Sthurlow 135613a2f6bSGordon Ross if (cmd == SMBIOC_PK_CHK) { 136613a2f6bSGordon Ross if (lmhash != NULL) 137613a2f6bSGordon Ross memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ); 138613a2f6bSGordon Ross if (nthash != NULL) 139613a2f6bSGordon Ross memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ); 140613a2f6bSGordon Ross } 141613a2f6bSGordon Ross 1424bff34e3Sthurlow out: 143613a2f6bSGordon Ross if (fd != -1) 144613a2f6bSGordon Ross close(fd); 145613a2f6bSGordon Ross 1464bff34e3Sthurlow return (err); 1474bff34e3Sthurlow } 1484bff34e3Sthurlow 149613a2f6bSGordon Ross /* 150613a2f6bSGordon Ross * Add a password to the keychain. 151613a2f6bSGordon Ross * 152613a2f6bSGordon Ross * Note: pass is a cleartext password. 153613a2f6bSGordon Ross * We use it here to compute the LM hash and NT hash, 154613a2f6bSGordon Ross * and then store ONLY the hashes. 155613a2f6bSGordon Ross */ 1564bff34e3Sthurlow int 1574bff34e3Sthurlow smbfs_keychain_add(uid_t uid, const char *dom, const char *usr, 1584bff34e3Sthurlow const char *pass) 1594bff34e3Sthurlow { 160613a2f6bSGordon Ross uchar_t lmhash[SMBIOC_HASH_SZ]; 161613a2f6bSGordon Ross uchar_t nthash[SMBIOC_HASH_SZ]; 162613a2f6bSGordon Ross int err, cmd = SMBIOC_PK_ADD; 163613a2f6bSGordon Ross 164613a2f6bSGordon Ross if (pass == NULL) 165613a2f6bSGordon Ross return (SMB_KEYCHAIN_BADPASSWD); 166613a2f6bSGordon Ross 167613a2f6bSGordon Ross if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0) 168613a2f6bSGordon Ross return (err); 169613a2f6bSGordon Ross if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0) 170613a2f6bSGordon Ross return (err); 171613a2f6bSGordon Ross 172613a2f6bSGordon Ross err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 173613a2f6bSGordon Ross return (err); 1744bff34e3Sthurlow } 1754bff34e3Sthurlow 1764bff34e3Sthurlow /* Delete a password from the keychain. */ 1774bff34e3Sthurlow int 1784bff34e3Sthurlow smbfs_keychain_del(uid_t uid, const char *dom, const char *usr) 1794bff34e3Sthurlow { 180613a2f6bSGordon Ross return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL)); 1814bff34e3Sthurlow } 1824bff34e3Sthurlow 1834bff34e3Sthurlow /* 1844bff34e3Sthurlow * Check for existence of a keychain entry. 1854bff34e3Sthurlow * Returns 0 if it exists, else ENOENT. 1864bff34e3Sthurlow */ 1874bff34e3Sthurlow int 1884bff34e3Sthurlow smbfs_keychain_chk(const char *dom, const char *usr) 1894bff34e3Sthurlow { 190613a2f6bSGordon Ross uid_t uid = (uid_t)-1; 191613a2f6bSGordon Ross return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL)); 192613a2f6bSGordon Ross } 193613a2f6bSGordon Ross 194613a2f6bSGordon Ross /* 195613a2f6bSGordon Ross * Get the stored hashes 196613a2f6bSGordon Ross */ 197613a2f6bSGordon Ross int 198613a2f6bSGordon Ross smbfs_keychain_get(const char *dom, const char *usr, 199613a2f6bSGordon Ross uchar_t *lmhash, uchar_t *nthash) 200613a2f6bSGordon Ross { 201613a2f6bSGordon Ross uid_t uid = (uid_t)-1; 202613a2f6bSGordon Ross int err, cmd = SMBIOC_PK_CHK; 203613a2f6bSGordon Ross 204613a2f6bSGordon Ross err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 205613a2f6bSGordon Ross return (err); 2064bff34e3Sthurlow } 2074bff34e3Sthurlow 2084bff34e3Sthurlow /* 2094bff34e3Sthurlow * Delete all keychain entries owned by the caller. 2104bff34e3Sthurlow */ 2114bff34e3Sthurlow int 2124bff34e3Sthurlow smbfs_keychain_del_owner() 2134bff34e3Sthurlow { 214613a2f6bSGordon Ross int cmd = SMBIOC_PK_DEL_OWNER; 215613a2f6bSGordon Ross uid_t uid = getuid(); 216613a2f6bSGordon Ross return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 2174bff34e3Sthurlow } 2184bff34e3Sthurlow 2194bff34e3Sthurlow /* 2204bff34e3Sthurlow * Delete all keychain entries (regardless of onwer). 2214bff34e3Sthurlow * Requires super-user privliege. 2224bff34e3Sthurlow */ 2234bff34e3Sthurlow int 2244bff34e3Sthurlow smbfs_keychain_del_everyone() 2254bff34e3Sthurlow { 226613a2f6bSGordon Ross int cmd = SMBIOC_PK_DEL_EVERYONE; 227613a2f6bSGordon Ross uid_t uid = getuid(); 228613a2f6bSGordon Ross return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 229613a2f6bSGordon Ross } 230613a2f6bSGordon Ross 231613a2f6bSGordon Ross /* 232613a2f6bSGordon Ross * Private function to get keychain p/w hashes. 233613a2f6bSGordon Ross */ 234613a2f6bSGordon Ross int 235613a2f6bSGordon Ross smb_get_keychain(struct smb_ctx *ctx) 236613a2f6bSGordon Ross { 237613a2f6bSGordon Ross int err; 238613a2f6bSGordon Ross 239613a2f6bSGordon Ross if (ctx->ct_fullserver == NULL) { 240613a2f6bSGordon Ross DPRINT("ct_fullserver == NULL"); 241613a2f6bSGordon Ross return (EINVAL); 242613a2f6bSGordon Ross } 243613a2f6bSGordon Ross 244613a2f6bSGordon Ross /* 245613a2f6bSGordon Ross * 1st: try lookup using system name 246613a2f6bSGordon Ross */ 247613a2f6bSGordon Ross err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user, 248613a2f6bSGordon Ross ctx->ct_lmhash, ctx->ct_nthash); 249613a2f6bSGordon Ross if (!err) { 250613a2f6bSGordon Ross ctx->ct_flags |= SMBCF_KCFOUND; 251613a2f6bSGordon Ross DPRINT("found keychain entry for" 252613a2f6bSGordon Ross " server/user: %s/%s\n", 253613a2f6bSGordon Ross ctx->ct_fullserver, ctx->ct_user); 254613a2f6bSGordon Ross return (0); 255613a2f6bSGordon Ross } 256613a2f6bSGordon Ross 257613a2f6bSGordon Ross /* 258613a2f6bSGordon Ross * 2nd: try lookup using domain name 259613a2f6bSGordon Ross */ 260613a2f6bSGordon Ross err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user, 261613a2f6bSGordon Ross ctx->ct_lmhash, ctx->ct_nthash); 262613a2f6bSGordon Ross if (!err) { 263613a2f6bSGordon Ross ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN); 264613a2f6bSGordon Ross DPRINT("found keychain entry for" 265613a2f6bSGordon Ross " domain/user: %s/%s\n", 266613a2f6bSGordon Ross ctx->ct_domain, ctx->ct_user); 267613a2f6bSGordon Ross return (0); 268613a2f6bSGordon Ross } 269613a2f6bSGordon Ross 270613a2f6bSGordon Ross return (err); 2714bff34e3Sthurlow } 2724bff34e3Sthurlow 2734bff34e3Sthurlow 2744bff34e3Sthurlow /* 2754bff34e3Sthurlow * This is not really part of the keychain library, 2764bff34e3Sthurlow * but is typically needed in code that wants to 2774bff34e3Sthurlow * provide (editable) defaults for domain/user 2784bff34e3Sthurlow * 2794bff34e3Sthurlow * Get default domain and user names 2804bff34e3Sthurlow * Server name is optional. 2814bff34e3Sthurlow */ 2824bff34e3Sthurlow int 2834bff34e3Sthurlow smbfs_default_dom_usr(const char *home, const char *server, 2844bff34e3Sthurlow char *dom, int maxdom, char *usr, int maxusr) 2854bff34e3Sthurlow { 286613a2f6bSGordon Ross struct smb_ctx *ctx; 2874bff34e3Sthurlow int err; 2884bff34e3Sthurlow 289613a2f6bSGordon Ross err = smb_ctx_alloc(&ctx); 2904bff34e3Sthurlow if (err) 2914bff34e3Sthurlow return (err); 292613a2f6bSGordon Ross 293*02d09e03SGordon Ross if (server) { 294*02d09e03SGordon Ross err = smb_ctx_setfullserver(ctx, server); 295*02d09e03SGordon Ross if (err != 0) 296*02d09e03SGordon Ross goto out; 297*02d09e03SGordon Ross } 298613a2f6bSGordon Ross 299613a2f6bSGordon Ross if (home && *home) { 300613a2f6bSGordon Ross if (ctx->ct_home) 301613a2f6bSGordon Ross free(ctx->ct_home); 302613a2f6bSGordon Ross ctx->ct_home = strdup(home); 303613a2f6bSGordon Ross } 304613a2f6bSGordon Ross 3054bff34e3Sthurlow err = smb_ctx_readrc(ctx); 3064bff34e3Sthurlow if (err) 307613a2f6bSGordon Ross goto out; 3084bff34e3Sthurlow 3094bff34e3Sthurlow if (dom) 310613a2f6bSGordon Ross strlcpy(dom, ctx->ct_domain, maxdom); 3114bff34e3Sthurlow 3124bff34e3Sthurlow if (usr) 313613a2f6bSGordon Ross strlcpy(usr, ctx->ct_user, maxusr); 3144bff34e3Sthurlow 315613a2f6bSGordon Ross out: 316613a2f6bSGordon Ross smb_ctx_free(ctx); 317613a2f6bSGordon Ross return (err); 3184bff34e3Sthurlow } 319