xref: /illumos-gate/usr/src/lib/libsmbfs/smb/keychain.c (revision 8329232e)
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*8329232eSGordon Ross  * Copyright 2017 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
smbfs_keychain_cmn(int cmd,uid_t uid,const char * dom,const char * usr,uchar_t * lmhash,uchar_t * nthash)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;
131*8329232eSGordon Ross 	if (nsmb_ioctl(fd, cmd, &pk) < 0) {
1324bff34e3Sthurlow 		err = errno;
133613a2f6bSGordon Ross 		goto out;
134613a2f6bSGordon Ross 	}
135613a2f6bSGordon Ross 
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 	}
1424bff34e3Sthurlow 
1434bff34e3Sthurlow out:
144613a2f6bSGordon Ross 	if (fd != -1)
145*8329232eSGordon Ross 		nsmb_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
smbfs_keychain_add(uid_t uid,const char * dom,const char * usr,const char * pass)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 
177430b4c46SGordon Ross /* Variant of the above that takes an NT hash. */
178430b4c46SGordon Ross int
smbfs_keychain_addhash(uid_t uid,const char * dom,const char * usr,const uchar_t * nthash)179430b4c46SGordon Ross smbfs_keychain_addhash(uid_t uid, const char *dom, const char *usr,
180430b4c46SGordon Ross 	const uchar_t *nthash)
181430b4c46SGordon Ross {
182430b4c46SGordon Ross 	static const uchar_t lmhash[SMBIOC_HASH_SZ] = { 0 };
183430b4c46SGordon Ross 	int err, cmd = SMBIOC_PK_ADD;
184430b4c46SGordon Ross 	err = smbfs_keychain_cmn(cmd, uid, dom, usr,
185430b4c46SGordon Ross 	    (uchar_t *)lmhash, (uchar_t *)nthash);
186430b4c46SGordon Ross 	return (err);
187430b4c46SGordon Ross }
188430b4c46SGordon Ross 
1894bff34e3Sthurlow /* Delete a password from the keychain. */
1904bff34e3Sthurlow int
smbfs_keychain_del(uid_t uid,const char * dom,const char * usr)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
smbfs_keychain_chk(const char * dom,const char * usr)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
smbfs_keychain_get(const char * dom,const char * usr,uchar_t * lmhash,uchar_t * nthash)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
smbfs_keychain_del_owner()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
smbfs_keychain_del_everyone()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
smb_get_keychain(struct smb_ctx * ctx)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
smbfs_default_dom_usr(const char * home,const char * server,char * dom,int maxdom,char * usr,int maxusr)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