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
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;
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
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
177*430b4c46SGordon Ross /* Variant of the above that takes an NT hash. */
178*430b4c46SGordon Ross int
smbfs_keychain_addhash(uid_t uid,const char * dom,const char * usr,const uchar_t * nthash)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
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