diff options
Diffstat (limited to 'usr/src/lib/libsmbfs/smb/keychain.c')
-rw-r--r-- | usr/src/lib/libsmbfs/smb/keychain.c | 204 |
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); } |