xref: /titanic_44/usr/src/lib/libsmbfs/smb/keychain.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
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*613a2f6bSGordon 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>
38*613a2f6bSGordon Ross #include <stdlib.h>
394bff34e3Sthurlow #include <string.h>
404bff34e3Sthurlow #include <unistd.h>
414bff34e3Sthurlow #include <libintl.h>
424bff34e3Sthurlow 
43*613a2f6bSGordon Ross #include <cflib.h>
444bff34e3Sthurlow #include <netsmb/smb_dev.h>
454bff34e3Sthurlow #include <netsmb/smb_lib.h>
464bff34e3Sthurlow #include <netsmb/smb_keychain.h>
474bff34e3Sthurlow 
48*613a2f6bSGordon Ross #include "charsets.h"
49*613a2f6bSGordon Ross #include "private.h"
50*613a2f6bSGordon 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,
59*613a2f6bSGordon Ross 	uchar_t *lmhash,
60*613a2f6bSGordon Ross 	uchar_t *nthash)
614bff34e3Sthurlow {
624bff34e3Sthurlow 	smbioc_pk_t pk;
63*613a2f6bSGordon Ross 	int err, fd, sz;
644bff34e3Sthurlow 
654bff34e3Sthurlow 	memset(&pk, 0, sizeof (pk));
664bff34e3Sthurlow 	pk.pk_uid = uid;
67*613a2f6bSGordon Ross 	err = 0;
68*613a2f6bSGordon Ross 	fd = -1;
694bff34e3Sthurlow 
704bff34e3Sthurlow 	switch (cmd) {
714bff34e3Sthurlow 
724bff34e3Sthurlow 	case SMBIOC_PK_ADD:
73*613a2f6bSGordon Ross 		/*
74*613a2f6bSGordon Ross 		 * Add password hashes to the keychain.
75*613a2f6bSGordon Ross 		 */
76*613a2f6bSGordon Ross 		if (lmhash == NULL || nthash == NULL) {
77*613a2f6bSGordon Ross 			err = SMB_KEYCHAIN_BADPASSWD;
78*613a2f6bSGordon Ross 			goto out;
79*613a2f6bSGordon Ross 		}
80*613a2f6bSGordon Ross 		memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ);
81*613a2f6bSGordon Ross 		memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ);
824bff34e3Sthurlow 		/* FALLTHROUGH */
834bff34e3Sthurlow 
844bff34e3Sthurlow 	case SMBIOC_PK_CHK:
854bff34e3Sthurlow 	case SMBIOC_PK_DEL:
86*613a2f6bSGordon Ross 		/*
87*613a2f6bSGordon Ross 		 * Copy domain and user.
88*613a2f6bSGordon Ross 		 */
89*613a2f6bSGordon Ross 		if (dom == NULL) {
90*613a2f6bSGordon Ross 			err = SMB_KEYCHAIN_BADDOMAIN;
91*613a2f6bSGordon Ross 			goto out;
92*613a2f6bSGordon Ross 		}
93*613a2f6bSGordon Ross 		sz = sizeof (pk.pk_dom);
94*613a2f6bSGordon Ross 		if (strlcpy(pk.pk_dom, dom, sz) >= sz) {
95*613a2f6bSGordon Ross 			err = SMB_KEYCHAIN_BADDOMAIN;
96*613a2f6bSGordon Ross 			goto out;
97*613a2f6bSGordon Ross 		}
98*613a2f6bSGordon Ross 		if (usr == NULL) {
99*613a2f6bSGordon Ross 			err = SMB_KEYCHAIN_BADUSER;
100*613a2f6bSGordon Ross 			goto out;
101*613a2f6bSGordon Ross 		}
102*613a2f6bSGordon Ross 		sz = sizeof (pk.pk_usr);
103*613a2f6bSGordon Ross 		if (strlcpy(pk.pk_usr, usr, sz) >= sz) {
104*613a2f6bSGordon Ross 			err = SMB_KEYCHAIN_BADUSER;
105*613a2f6bSGordon Ross 			goto out;
106*613a2f6bSGordon 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
113*613a2f6bSGordon Ross 		 * pass pk here anyway just so we can use the
1144bff34e3Sthurlow 		 * common code path below.
1154bff34e3Sthurlow 		 */
1164bff34e3Sthurlow 		break;
1174bff34e3Sthurlow 
1184bff34e3Sthurlow 	default:
119*613a2f6bSGordon Ross 		err = SMB_KEYCHAIN_UNKNOWN;
120*613a2f6bSGordon 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;
130*613a2f6bSGordon Ross 	if (ioctl(fd, cmd, &pk) < 0) {
1314bff34e3Sthurlow 		err = errno;
132*613a2f6bSGordon Ross 		goto out;
133*613a2f6bSGordon Ross 	}
1344bff34e3Sthurlow 
135*613a2f6bSGordon Ross 	if (cmd == SMBIOC_PK_CHK) {
136*613a2f6bSGordon Ross 		if (lmhash != NULL)
137*613a2f6bSGordon Ross 			memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ);
138*613a2f6bSGordon Ross 		if (nthash != NULL)
139*613a2f6bSGordon Ross 			memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ);
140*613a2f6bSGordon Ross 	}
141*613a2f6bSGordon Ross 
1424bff34e3Sthurlow out:
143*613a2f6bSGordon Ross 	if (fd != -1)
144*613a2f6bSGordon Ross 		close(fd);
145*613a2f6bSGordon Ross 
1464bff34e3Sthurlow 	return (err);
1474bff34e3Sthurlow }
1484bff34e3Sthurlow 
149*613a2f6bSGordon Ross /*
150*613a2f6bSGordon Ross  * Add a password to the keychain.
151*613a2f6bSGordon Ross  *
152*613a2f6bSGordon Ross  * Note: pass is a cleartext password.
153*613a2f6bSGordon Ross  * We use it here to compute the LM hash and NT hash,
154*613a2f6bSGordon Ross  * and then store ONLY the hashes.
155*613a2f6bSGordon Ross  */
1564bff34e3Sthurlow int
1574bff34e3Sthurlow smbfs_keychain_add(uid_t uid, const char *dom, const char *usr,
1584bff34e3Sthurlow 	const char *pass)
1594bff34e3Sthurlow {
160*613a2f6bSGordon Ross 	uchar_t lmhash[SMBIOC_HASH_SZ];
161*613a2f6bSGordon Ross 	uchar_t nthash[SMBIOC_HASH_SZ];
162*613a2f6bSGordon Ross 	int err, cmd = SMBIOC_PK_ADD;
163*613a2f6bSGordon Ross 
164*613a2f6bSGordon Ross 	if (pass == NULL)
165*613a2f6bSGordon Ross 		return (SMB_KEYCHAIN_BADPASSWD);
166*613a2f6bSGordon Ross 
167*613a2f6bSGordon Ross 	if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0)
168*613a2f6bSGordon Ross 		return (err);
169*613a2f6bSGordon Ross 	if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0)
170*613a2f6bSGordon Ross 		return (err);
171*613a2f6bSGordon Ross 
172*613a2f6bSGordon Ross 	err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
173*613a2f6bSGordon 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 {
180*613a2f6bSGordon 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 {
190*613a2f6bSGordon Ross 	uid_t uid = (uid_t)-1;
191*613a2f6bSGordon Ross 	return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL));
192*613a2f6bSGordon Ross }
193*613a2f6bSGordon Ross 
194*613a2f6bSGordon Ross /*
195*613a2f6bSGordon Ross  * Get the stored hashes
196*613a2f6bSGordon Ross  */
197*613a2f6bSGordon Ross int
198*613a2f6bSGordon Ross smbfs_keychain_get(const char *dom, const char *usr,
199*613a2f6bSGordon Ross 		uchar_t *lmhash, uchar_t *nthash)
200*613a2f6bSGordon Ross {
201*613a2f6bSGordon Ross 	uid_t uid = (uid_t)-1;
202*613a2f6bSGordon Ross 	int err, cmd = SMBIOC_PK_CHK;
203*613a2f6bSGordon Ross 
204*613a2f6bSGordon Ross 	err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
205*613a2f6bSGordon Ross 	return (err);
2064bff34e3Sthurlow }
2074bff34e3Sthurlow 
2084bff34e3Sthurlow /*
2094bff34e3Sthurlow  * Delete all keychain entries owned by the caller.
2104bff34e3Sthurlow  */
2114bff34e3Sthurlow int
2124bff34e3Sthurlow smbfs_keychain_del_owner()
2134bff34e3Sthurlow {
214*613a2f6bSGordon Ross 	int cmd = SMBIOC_PK_DEL_OWNER;
215*613a2f6bSGordon Ross 	uid_t uid = getuid();
216*613a2f6bSGordon 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 {
226*613a2f6bSGordon Ross 	int cmd = SMBIOC_PK_DEL_EVERYONE;
227*613a2f6bSGordon Ross 	uid_t uid = getuid();
228*613a2f6bSGordon Ross 	return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
229*613a2f6bSGordon Ross }
230*613a2f6bSGordon Ross 
231*613a2f6bSGordon Ross /*
232*613a2f6bSGordon Ross  * Private function to get keychain p/w hashes.
233*613a2f6bSGordon Ross  */
234*613a2f6bSGordon Ross int
235*613a2f6bSGordon Ross smb_get_keychain(struct smb_ctx *ctx)
236*613a2f6bSGordon Ross {
237*613a2f6bSGordon Ross 	int err;
238*613a2f6bSGordon Ross 
239*613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL) {
240*613a2f6bSGordon Ross 		DPRINT("ct_fullserver == NULL");
241*613a2f6bSGordon Ross 		return (EINVAL);
242*613a2f6bSGordon Ross 	}
243*613a2f6bSGordon Ross 
244*613a2f6bSGordon Ross 	/*
245*613a2f6bSGordon Ross 	 * 1st: try lookup using system name
246*613a2f6bSGordon Ross 	 */
247*613a2f6bSGordon Ross 	err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user,
248*613a2f6bSGordon Ross 	    ctx->ct_lmhash, ctx->ct_nthash);
249*613a2f6bSGordon Ross 	if (!err) {
250*613a2f6bSGordon Ross 		ctx->ct_flags |= SMBCF_KCFOUND;
251*613a2f6bSGordon Ross 		DPRINT("found keychain entry for"
252*613a2f6bSGordon Ross 		    " server/user: %s/%s\n",
253*613a2f6bSGordon Ross 		    ctx->ct_fullserver, ctx->ct_user);
254*613a2f6bSGordon Ross 		return (0);
255*613a2f6bSGordon Ross 	}
256*613a2f6bSGordon Ross 
257*613a2f6bSGordon Ross 	/*
258*613a2f6bSGordon Ross 	 * 2nd: try lookup using domain name
259*613a2f6bSGordon Ross 	 */
260*613a2f6bSGordon Ross 	err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user,
261*613a2f6bSGordon Ross 	    ctx->ct_lmhash, ctx->ct_nthash);
262*613a2f6bSGordon Ross 	if (!err) {
263*613a2f6bSGordon Ross 		ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN);
264*613a2f6bSGordon Ross 		DPRINT("found keychain entry for"
265*613a2f6bSGordon Ross 		    " domain/user: %s/%s\n",
266*613a2f6bSGordon Ross 		    ctx->ct_domain, ctx->ct_user);
267*613a2f6bSGordon Ross 		return (0);
268*613a2f6bSGordon Ross 	}
269*613a2f6bSGordon Ross 
270*613a2f6bSGordon 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 {
286*613a2f6bSGordon Ross 	struct smb_ctx  *ctx;
2874bff34e3Sthurlow 	int err;
2884bff34e3Sthurlow 
289*613a2f6bSGordon Ross 	err = smb_ctx_alloc(&ctx);
2904bff34e3Sthurlow 	if (err)
2914bff34e3Sthurlow 		return (err);
292*613a2f6bSGordon Ross 
2934bff34e3Sthurlow 	if (server)
294*613a2f6bSGordon Ross 		smb_ctx_setfullserver(ctx, server);
295*613a2f6bSGordon Ross 
296*613a2f6bSGordon Ross 	if (home && *home) {
297*613a2f6bSGordon Ross 		if (ctx->ct_home)
298*613a2f6bSGordon Ross 			free(ctx->ct_home);
299*613a2f6bSGordon Ross 		ctx->ct_home = strdup(home);
300*613a2f6bSGordon Ross 	}
301*613a2f6bSGordon Ross 
3024bff34e3Sthurlow 	err = smb_ctx_readrc(ctx);
3034bff34e3Sthurlow 	if (err)
304*613a2f6bSGordon Ross 		goto out;
3054bff34e3Sthurlow 
3064bff34e3Sthurlow 	if (dom)
307*613a2f6bSGordon Ross 		strlcpy(dom, ctx->ct_domain, maxdom);
3084bff34e3Sthurlow 
3094bff34e3Sthurlow 	if (usr)
310*613a2f6bSGordon Ross 		strlcpy(usr, ctx->ct_user, maxusr);
3114bff34e3Sthurlow 
312*613a2f6bSGordon Ross out:
313*613a2f6bSGordon Ross 	smb_ctx_free(ctx);
314*613a2f6bSGordon Ross 	return (err);
3154bff34e3Sthurlow }
316