xref: /titanic_51/usr/src/lib/libsmbfs/smb/keychain.c (revision 02d09e03eb27f3a2dc299de704e45dae5173f43f)
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