summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsmbfs/smb/keychain.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libsmbfs/smb/keychain.c')
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c204
1 files changed, 160 insertions, 44 deletions
diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c
index 72a979022f..da19fd4d0b 100644
--- a/usr/src/lib/libsmbfs/smb/keychain.c
+++ b/usr/src/lib/libsmbfs/smb/keychain.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* External interface to the libsmbfs/netsmb keychain
* storage mechanism. This interface is consumed by
@@ -37,15 +35,19 @@
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
+#include <cflib.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_lib.h>
#include <netsmb/smb_keychain.h>
-#include <cflib.h>
+#include "charsets.h"
+#include "private.h"
+#include "ntlm.h"
/* common func. for add/del/chk */
static int
@@ -54,50 +56,68 @@ smbfs_keychain_cmn(
uid_t uid,
const char *dom,
const char *usr,
- const char *pass)
+ uchar_t *lmhash,
+ uchar_t *nthash)
{
smbioc_pk_t pk;
- int err, fd;
+ int err, fd, sz;
memset(&pk, 0, sizeof (pk));
-
pk.pk_uid = uid;
+ err = 0;
+ fd = -1;
switch (cmd) {
case SMBIOC_PK_ADD:
- if (pass == NULL)
- return (SMB_KEYCHAIN_BADPASSWD);
- if (strlcpy(pk.pk_pass, pass, sizeof (pk.pk_pass)) >=
- sizeof (pk.pk_pass))
- return (SMB_KEYCHAIN_BADPASSWD);
+ /*
+ * Add password hashes to the keychain.
+ */
+ if (lmhash == NULL || nthash == NULL) {
+ err = SMB_KEYCHAIN_BADPASSWD;
+ goto out;
+ }
+ memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ);
+ memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ);
/* FALLTHROUGH */
case SMBIOC_PK_CHK:
case SMBIOC_PK_DEL:
- if (dom == NULL)
- return (SMB_KEYCHAIN_BADDOMAIN);
- if (strlcpy(pk.pk_dom, dom, sizeof (pk.pk_dom)) >=
- sizeof (pk.pk_dom))
- return (SMB_KEYCHAIN_BADDOMAIN);
- if (usr == NULL)
- return (SMB_KEYCHAIN_BADUSER);
- if (strlcpy(pk.pk_usr, usr, sizeof (pk.pk_usr)) >=
- sizeof (pk.pk_usr))
- return (SMB_KEYCHAIN_BADUSER);
+ /*
+ * Copy domain and user.
+ */
+ if (dom == NULL) {
+ err = SMB_KEYCHAIN_BADDOMAIN;
+ goto out;
+ }
+ sz = sizeof (pk.pk_dom);
+ if (strlcpy(pk.pk_dom, dom, sz) >= sz) {
+ err = SMB_KEYCHAIN_BADDOMAIN;
+ goto out;
+ }
+ if (usr == NULL) {
+ err = SMB_KEYCHAIN_BADUSER;
+ goto out;
+ }
+ sz = sizeof (pk.pk_usr);
+ if (strlcpy(pk.pk_usr, usr, sz) >= sz) {
+ err = SMB_KEYCHAIN_BADUSER;
+ goto out;
+ }
break;
case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */
case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */
/*
* These two do not copyin any args, but we'll
- * pass &pk here anyway just so we can use the
+ * pass pk here anyway just so we can use the
* common code path below.
*/
break;
default:
- return (SMB_KEYCHAIN_UNKNOWN);
+ err = SMB_KEYCHAIN_UNKNOWN;
+ goto out;
}
fd = smb_open_driver();
@@ -107,28 +127,57 @@ smbfs_keychain_cmn(
}
err = 0;
- if (ioctl(fd, cmd, &pk) < 0)
+ if (ioctl(fd, cmd, &pk) < 0) {
err = errno;
+ goto out;
+ }
+
+ if (cmd == SMBIOC_PK_CHK) {
+ if (lmhash != NULL)
+ memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ);
+ if (nthash != NULL)
+ memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ);
+ }
- close(fd);
out:
- memset(&pk, 0, sizeof (pk));
+ if (fd != -1)
+ close(fd);
+
return (err);
}
-/* Add a password to the keychain. */
+/*
+ * Add a password to the keychain.
+ *
+ * Note: pass is a cleartext password.
+ * We use it here to compute the LM hash and NT hash,
+ * and then store ONLY the hashes.
+ */
int
smbfs_keychain_add(uid_t uid, const char *dom, const char *usr,
const char *pass)
{
- return (smbfs_keychain_cmn(SMBIOC_PK_ADD, uid, dom, usr, pass));
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
+ int err, cmd = SMBIOC_PK_ADD;
+
+ if (pass == NULL)
+ return (SMB_KEYCHAIN_BADPASSWD);
+
+ if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0)
+ return (err);
+ if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0)
+ return (err);
+
+ err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
+ return (err);
}
/* Delete a password from the keychain. */
int
smbfs_keychain_del(uid_t uid, const char *dom, const char *usr)
{
- return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL));
+ return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL));
}
/*
@@ -138,7 +187,22 @@ smbfs_keychain_del(uid_t uid, const char *dom, const char *usr)
int
smbfs_keychain_chk(const char *dom, const char *usr)
{
- return (smbfs_keychain_cmn(SMBIOC_PK_CHK, (uid_t)-1, dom, usr, NULL));
+ uid_t uid = (uid_t)-1;
+ return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL));
+}
+
+/*
+ * Get the stored hashes
+ */
+int
+smbfs_keychain_get(const char *dom, const char *usr,
+ uchar_t *lmhash, uchar_t *nthash)
+{
+ uid_t uid = (uid_t)-1;
+ int err, cmd = SMBIOC_PK_CHK;
+
+ err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
+ return (err);
}
/*
@@ -147,7 +211,9 @@ smbfs_keychain_chk(const char *dom, const char *usr)
int
smbfs_keychain_del_owner()
{
- return (smbfs_keychain_cmn(SMBIOC_PK_DEL_OWNER, getuid(), 0, 0, 0));
+ int cmd = SMBIOC_PK_DEL_OWNER;
+ uid_t uid = getuid();
+ return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
}
/*
@@ -157,7 +223,51 @@ smbfs_keychain_del_owner()
int
smbfs_keychain_del_everyone()
{
- return (smbfs_keychain_cmn(SMBIOC_PK_DEL_EVERYONE, getuid(), 0, 0, 0));
+ int cmd = SMBIOC_PK_DEL_EVERYONE;
+ uid_t uid = getuid();
+ return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * Private function to get keychain p/w hashes.
+ */
+int
+smb_get_keychain(struct smb_ctx *ctx)
+{
+ int err;
+
+ if (ctx->ct_fullserver == NULL) {
+ DPRINT("ct_fullserver == NULL");
+ return (EINVAL);
+ }
+
+ /*
+ * 1st: try lookup using system name
+ */
+ err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user,
+ ctx->ct_lmhash, ctx->ct_nthash);
+ if (!err) {
+ ctx->ct_flags |= SMBCF_KCFOUND;
+ DPRINT("found keychain entry for"
+ " server/user: %s/%s\n",
+ ctx->ct_fullserver, ctx->ct_user);
+ return (0);
+ }
+
+ /*
+ * 2nd: try lookup using domain name
+ */
+ err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user,
+ ctx->ct_lmhash, ctx->ct_nthash);
+ if (!err) {
+ ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN);
+ DPRINT("found keychain entry for"
+ " domain/user: %s/%s\n",
+ ctx->ct_domain, ctx->ct_user);
+ return (0);
+ }
+
+ return (err);
}
@@ -173,27 +283,33 @@ int
smbfs_default_dom_usr(const char *home, const char *server,
char *dom, int maxdom, char *usr, int maxusr)
{
- struct smb_ctx sctx, *ctx = &sctx;
+ struct smb_ctx *ctx;
int err;
- err = smb_ctx_init(ctx, 0, NULL, SMBL_VC, SMBL_VC, SMB_ST_ANY);
+ err = smb_ctx_alloc(&ctx);
if (err)
return (err);
+
if (server)
- smb_ctx_setserver(ctx, server);
- if (home && *home)
- ctx->ct_home = (char *)home;
+ smb_ctx_setfullserver(ctx, server);
+
+ if (home && *home) {
+ if (ctx->ct_home)
+ free(ctx->ct_home);
+ ctx->ct_home = strdup(home);
+ }
+
err = smb_ctx_readrc(ctx);
if (err)
- return (err);
- if (smb_rc)
- rc_close(smb_rc);
+ goto out;
if (dom)
- strlcpy(dom, ctx->ct_ssn.ioc_workgroup, maxdom);
+ strlcpy(dom, ctx->ct_domain, maxdom);
if (usr)
- strlcpy(usr, ctx->ct_ssn.ioc_user, maxusr);
+ strlcpy(usr, ctx->ct_user, maxusr);
- return (0);
+out:
+ smb_ctx_free(ctx);
+ return (err);
}