diff options
author | Gordon Ross <Gordon.Ross@Sun.COM> | 2010-04-12 18:46:28 -0400 |
---|---|---|
committer | Gordon Ross <Gordon.Ross@Sun.COM> | 2010-04-12 18:46:28 -0400 |
commit | 15359501f7d4b9abebd7b7bf6efd5982a8e7eb27 (patch) | |
tree | d9163de03299c4d225afcbec58ee9b2f7615ce6f /usr/src/lib/libsmbfs | |
parent | 046cfe5c17cdf5694e6d0d26efdc0e95ad2a1fbc (diff) | |
download | illumos-joyent-15359501f7d4b9abebd7b7bf6efd5982a8e7eb27.tar.gz |
6935517 NTLMSSP Type 3 message header is missing two fields
6936620 should preserve the username case in session setup
6939738 Need a way to specify authentication types for testing
6939914 avoid fragmenting session setup
6939297 krb5 AP_REQ checksum is incorrect
6939356 system/filesystem-smb lacks dependency on system/library/iconv/utf-8
Diffstat (limited to 'usr/src/lib/libsmbfs')
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ctx.c | 110 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/krb5ssp.c | 35 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/mbuf.c | 9 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/nb_ssn.c | 44 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlm.c | 19 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlmssp.c | 50 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ssnsetup.c | 5 |
7 files changed, 170 insertions, 102 deletions
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c index d29ec7bf0b..be97571321 100644 --- a/usr/src/lib/libsmbfs/smb/ctx.c +++ b/usr/src/lib/libsmbfs/smb/ctx.c @@ -33,8 +33,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -77,6 +76,10 @@ #define TRUE 1 #endif +struct nv { + char *name; + int value; +}; /* These two may be set by commands. */ int smb_debug, smb_verbose; @@ -485,7 +488,6 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, const char *p = unc; char *p1, *colon; char tmp[1024]; - char tmp2[1024]; int error; /* @@ -512,7 +514,6 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, error = EINVAL; goto out; } - nls_str_upper(tmp, tmp); error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE); if (error) goto out; @@ -564,17 +565,6 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, } /* - * It's safe to uppercase this string, which - * consists of ascii characters that should - * be uppercased, %s, and ascii characters representing - * hex digits 0-9 and A-F (already uppercased, and - * if not uppercased they need to be). However, - * it is NOT safe to uppercase after it has been - * "unpercent" converted, below! - */ - nls_str_upper(tmp2, tmp); - - /* * Save ct_fullserver without case conversion. */ if (strchr(tmp, '%')) @@ -683,11 +673,9 @@ smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) return (0); } -/* this routine does not uppercase the server name */ int smb_ctx_setserver(struct smb_ctx *ctx, const char *name) { - /* don't uppercase the server name */ strlcpy(ctx->ct_srvname, name, sizeof (ctx->ct_srvname)); return (0); @@ -710,7 +698,6 @@ smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) return (0); - /* don't uppercase the username, just copy it. */ strlcpy(ctx->ct_user, name, sizeof (ctx->ct_user)); @@ -722,10 +709,6 @@ smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) } /* - * Never uppercase the workgroup - * name here, because it might come - * from a Windows codepage encoding. - * * Don't overwrite a domain name from the * command line with one from anywhere else. * See smb_ctx_init() for notes about this. @@ -907,6 +890,66 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) } /* + * Suport a securty options arg, i.e. -S noext,lm,ntlm + * for testing various type of authenticators. + */ +static struct nv +sectype_table[] = { + /* noext - handled below */ + { "anon", SMB_AT_ANON }, + { "lm", SMB_AT_LM1 }, + { "ntlm", SMB_AT_NTLM1 }, + { "ntlm2", SMB_AT_NTLM2 }, + { "krb5", SMB_AT_KRB5 }, + { NULL, 0 }, +}; +int +smb_parse_secopts(struct smb_ctx *ctx, const char *arg) +{ + const char *sep = ":;,"; + const char *p = arg; + struct nv *nv; + int nlen, tlen; + int authflags = 0; + + for (;;) { + /* skip separators */ + tlen = strspn(p, sep); + p += tlen; + + nlen = strcspn(p, sep); + if (nlen == 0) + break; + + if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) { + /* Don't offer extended security. */ + ctx->ct_vopt &= ~SMBVOPT_EXT_SEC; + p += nlen; + continue; + } + + /* This is rarely called, so not optimized. */ + for (nv = sectype_table; nv->name; nv++) { + tlen = strlen(nv->name); + if (tlen == nlen && 0 == strncmp(p, nv->name, tlen)) + break; + } + if (nv->name == NULL) { + smb_error(dgettext(TEXT_DOMAIN, + "%s: invalid security options"), 0, p); + return (EINVAL); + } + authflags |= nv->value; + p += nlen; + } + + if (authflags) + ctx->ct_authflags = authflags; + + return (0); +} + +/* * Commands use this with getopt. See: * STDPARAM_OPT, STDPARAM_ARGS * Called after smb_ctx_readrc(). @@ -947,12 +990,15 @@ smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) case 'R': /* retry count - ignored */ break; + case 'S': + /* Security options (undocumented, just for tests) */ + error = smb_parse_secopts(ctx, arg); + break; case 'T': /* timeout - ignored */ break; case 'D': /* domain */ case 'W': /* workgroup (legacy alias) */ - nls_str_upper(tmp, arg); error = smb_ctx_setdomain(ctx, tmp, TRUE); break; } @@ -996,6 +1042,9 @@ smb_ctx_resolve(struct smb_ctx *ctx) uint_t i; #endif + if (smb_debug) + dump_ctx("before smb_ctx_resolve", ctx); + ctx->ct_flags &= ~SMBCF_RESOLVED; if (ctx->ct_fullserver == NULL) { @@ -1077,12 +1126,6 @@ smb_ctx_resolve(struct smb_ctx *ctx) if (ctx->ct_password[0] == '\0') (void) smb_get_keychain(ctx); /* - * If we're doing p/w based auth, - * that means not using Kerberos. - */ - if (ctx->ct_password[0] != '\0') - ctx->ct_authflags &= ~SMB_AT_KRB5; - /* * Mask out disallowed auth types. */ ctx->ct_authflags &= ctx->ct_minauth; @@ -1327,15 +1370,12 @@ smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len) return (0); } - /* * RC file parsing stuff */ -struct nv { - char *name; - int value; -} minauth_table[] = { +static struct nv +minauth_table[] = { /* Allowed auth. types */ { "kerberos", SMB_AT_KRB5 }, { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 }, @@ -1432,7 +1472,6 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) */ rc_getstringptr(smb_rc, sname, "workgroup", &p); if (p) { - nls_str_upper(p, p); error = smb_ctx_setdomain(ctx, p, 0); if (error) smb_error(dgettext(TEXT_DOMAIN, @@ -1441,7 +1480,6 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) } rc_getstringptr(smb_rc, sname, "domain", &p); if (p) { - nls_str_upper(p, p); error = smb_ctx_setdomain(ctx, p, 0); if (error) smb_error(dgettext(TEXT_DOMAIN, diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c index 190a755499..208ec6d0a4 100644 --- a/usr/src/lib/libsmbfs/smb/krb5ssp.c +++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c @@ -31,8 +31,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -75,6 +74,11 @@ #include <kerberosv5/krb5.h> #include <kerberosv5/com_err.h> +#include <gssapi/gssapi.h> +#include <gssapi/mechs/krb5/include/auth_con.h> + +/* RFC 4121 checksum type ID. */ +#define CKSUM_TYPE_RFC4121 0x8003 /* RFC 1964 token ID codes */ #define KRB_AP_REQ 1 @@ -179,8 +183,28 @@ krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server, goto out; } - /* Override the krb5 library default. */ - indata.data = ""; + /* Get ss_auth now so we can set req_chsumtype. */ + kerr = krb5_auth_con_init(kctx, &ss->ss_auth); + if (kerr != 0) { + fn = "krb5_auth_con_init"; + goto out; + } + /* Missing krb5_auth_con_set_req_cksumtype(), so inline. */ + ss->ss_auth->req_cksumtype = CKSUM_TYPE_RFC4121; + + /* + * Build an RFC 4121 "checksum" with NULL channel bindings, + * like make_gss_checksum(). Numbers here from the RFC. + */ + indata.length = 24; + if ((indata.data = calloc(1, indata.length)) == NULL) { + kerr = ENOMEM; + fn = "malloc checksum"; + goto out; + } + indata.data[0] = 16; /* length of "Bnd" field. */ + indata.data[20] = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG; + /* Done building the "checksum". */ kerr = krb5_mk_req(kctx, &ss->ss_auth, rq_opts, "cifs", server, &indata, kcc, &outdata); @@ -210,6 +234,9 @@ out: if (outdata.data) krb5_free_data_contents(kctx, &outdata); + if (indata.data) + free(indata.data); + /* Free kctx in krb5ssp_destroy */ return (kerr); } diff --git a/usr/src/lib/libsmbfs/smb/mbuf.c b/usr/src/lib/libsmbfs/smb/mbuf.c index 86710f3f94..79da0209c1 100644 --- a/usr/src/lib/libsmbfs/smb/mbuf.c +++ b/usr/src/lib/libsmbfs/smb/mbuf.c @@ -33,8 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -121,14 +120,15 @@ m_lineup(struct mbuf *m0, struct mbuf **mpp) { struct mbuf *nm, *m; char *dp; - size_t len; + size_t len, totlen; int error; if (m0->m_next == NULL) { *mpp = m0; return (0); } - if ((error = m_get(m_totlen(m0), &nm)) != 0) + totlen = m_totlen(m0); + if ((error = m_get(totlen, &nm)) != 0) return (error); dp = mtod(nm, char *); while (m0) { @@ -139,6 +139,7 @@ m_lineup(struct mbuf *m0, struct mbuf **mpp) m_free(m0); m0 = m; } + nm->m_len = totlen; *mpp = nm; return (0); } diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c index 44d5a48120..319e250296 100644 --- a/usr/src/lib/libsmbfs/smb/nb_ssn.c +++ b/usr/src/lib/libsmbfs/smb/nb_ssn.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -70,18 +69,17 @@ static int nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp, int mtype, int mlen) { - mbuf_t *m = mbp->mb_top; - int fd = ctx->ct_tran_fd; - int err, flags; + mbuf_t *m; uint32_t hdr, hdrbuf; + int err; + m = mbp->mb_top; if (m == NULL) return (EINVAL); /* * Prepend the NetBIOS header. - * Using mbuf trickery to ensure it's - * not separated from the body. + * Our mbufs leave space for this. */ hdr = (mtype << 24) | mlen; hdrbuf = htonl(hdr); @@ -89,19 +87,27 @@ nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp, m->m_len += 4; bcopy(&hdrbuf, m->m_data, 4); - /* Send it. */ - while (m) { - flags = (m->m_next) ? T_MORE : T_PUSH; - if (t_snd(fd, m->m_data, m->m_len, flags) < 0) { - if (t_errno == TSYSERR) - err = errno; - else - err = EPROTO; - DPRINT("t_snd: t_errno %d, err %d", t_errno, err); - return (err); - } - m = m->m_next; + /* + * Get contiguous data (so TCP won't fragment) + * Note: replaces mb_top. + */ + err = m_lineup(mbp->mb_top, &mbp->mb_top); + if (err) + return (err); + m = mbp->mb_top; + + /* + * Send it. + */ + if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) { + if (t_errno == TSYSERR) + err = errno; + else + err = EPROTO; + DPRINT("t_snd: t_errno %d, err %d", t_errno, err); + return (err); } + return (0); } diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c index ffd9ff3d41..bee189561e 100644 --- a/usr/src/lib/libsmbfs/smb/ntlm.c +++ b/usr/src/lib/libsmbfs/smb/ntlm.c @@ -33,8 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -407,8 +406,7 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, { uchar_t *lmresp, *ntresp; int err; - char *ucdom = NULL; /* user's domain */ - char *ucuser = NULL; /* account name */ + char *ucuser = NULL; /* upper-case user name */ uchar_t v2hash[NTLM_HASH_SZ]; struct mbuf *tim = ti_mbp->mb_top; @@ -420,20 +418,20 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, /* * Convert the user name to upper-case, as * that's what's used when computing LMv2 - * and NTLMv2 responses. Also the domain. + * and NTLMv2 responses. Note that the + * domain name is NOT upper-cased! */ - ucdom = utf8_str_toupper(ctx->ct_domain); ucuser = utf8_str_toupper(ctx->ct_user); - if (ucdom == NULL || ucuser == NULL) { + if (ucuser == NULL) { err = ENOMEM; goto out; } /* - * Compute the NTLMv2 hash (see above) - * Needs upper-case user, domain. + * Compute the NTLMv2 hash */ - err = ntlm_v2_hash(v2hash, ctx->ct_nthash, ucuser, ucdom); + err = ntlm_v2_hash(v2hash, ctx->ct_nthash, + ucuser, ctx->ct_domain); if (err) goto out; @@ -483,7 +481,6 @@ out: mb_done(lm_mbp); mb_done(nt_mbp); } - free(ucdom); free(ucuser); return (err); diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c index 535777b187..687d91b355 100644 --- a/usr/src/lib/libsmbfs/smb/ntlmssp.c +++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -394,34 +393,26 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) struct sec_buf h_domain; struct sec_buf h_user; struct sec_buf h_wksta; + struct sec_buf h_ssn_key; + uint32_t h_flags; } hdr; - struct mbdata lm_mbc, nt_mbc, ti_mbc; - struct mbdata mb2; /* 2nd part */ + struct mbdata lm_mbc; /* LM response */ + struct mbdata nt_mbc; /* NT response */ + struct mbdata ti_mbc; /* target info */ + struct mbdata mb2; /* payload */ int err, uc; - char *ucdom = NULL; /* user's domain */ - char *ucuser = NULL; /* user name */ - char *ucwksta = NULL; /* workstation */ struct smb_ctx *ctx = sp->smb_ctx; ntlmssp_state_t *ssp_st = sp->sp_private; + bzero(&hdr, sizeof (hdr)); bzero(&lm_mbc, sizeof (lm_mbc)); bzero(&nt_mbc, sizeof (nt_mbc)); bzero(&ti_mbc, sizeof (ti_mbc)); bzero(&mb2, sizeof (mb2)); /* - * Convert the user name to upper-case, as that's what's - * used when computing LMv2 and NTLMv2 responses. Also - * domain, workstation + * Fill in the NTLMSSP header, etc. */ - ucdom = utf8_str_toupper(ctx->ct_domain); - ucuser = utf8_str_toupper(ctx->ct_user); - ucwksta = utf8_str_toupper(ctx->ct_locname); - if (ucdom == NULL || ucuser == NULL || ucwksta == NULL) { - err = ENOMEM; - goto out; - } - if ((err = mb_init(&mb2)) != 0) goto out; mb2.mb_count = sizeof (hdr); @@ -429,6 +420,7 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); hdr.h_type = 3; /* Type 3 */ + hdr.h_flags = ssp_st->ss_flags; /* * Put the LMv2,NTLMv2 responses, or @@ -461,17 +453,25 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) /* * Put the "target" (domain), user, workstation */ - err = mb_put_sb_string(&mb2, &hdr.h_domain, ucdom, uc); + err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc); if (err) goto out; - err = mb_put_sb_string(&mb2, &hdr.h_user, ucuser, uc); + err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc); if (err) goto out; - err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwksta, uc); + err = mb_put_sb_string(&mb2, &hdr.h_wksta, ctx->ct_locname, uc); if (err) goto out; /* + * Put the "Random Session Key". We don't set + * NTLMSSP_NEGOTIATE_KEY_EXCH, so it's empty. + * (In-line mb_put_sb_data here.) + */ + hdr.h_ssn_key.sb_maxlen = hdr.h_ssn_key.sb_length = 0; + hdr.h_ssn_key.sb_offset = mb2.mb_count; + + /* * Marshal the header (in LE order) * then concatenate the 2nd part. */ @@ -485,17 +485,17 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) (void) mb_put_sb_hdr(out_mb, &hdr.h_user); (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta); + (void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key); + (void) mb_put_uint32le(out_mb, hdr.h_flags); + err = mb_put_mbuf(out_mb, mb2.mb_top); mb2.mb_top = NULL; /* consumed */ out: - free(ucdom); - free(ucuser); - free(ucwksta); - mb_done(&mb2); mb_done(&lm_mbc); mb_done(&nt_mbc); + mb_done(&ti_mbc); return (err); } diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c index 712a71f34c..c8234c8040 100644 --- a/usr/src/lib/libsmbfs/smb/ssnsetup.c +++ b/usr/src/lib/libsmbfs/smb/ssnsetup.c @@ -31,8 +31,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -287,7 +286,7 @@ smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) break; /* normal loop termination */ if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) { err = EAUTH; - break; + goto out; } /* middle calls get both in, out */ |