/* * Tries to authenticate the connected user. * * It first tries to see if the user has already been authenticated. * If a match is found, the user structure in the session is duplicated * and the function returns. Otherwise, user information is passed to * smbd for authentication. If smbd can authenticate the user an access * token structure is returned. A cred_t and user structure is created * based on the returned access token. */ static int smb_authenticate(smb_request_t *sr, smb_sessionsetup_info_t *sinfo, smb_session_key_t **session_key) { char *hostname = sr->sr_cfg->skc_hostname; int security = sr->sr_cfg->skc_secmode; smb_token_t *usr_token = NULL; smb_user_t *user = NULL; netr_client_t clnt_info; boolean_t need_lookup = B_FALSE; uint32_t privileges; cred_t *cr; char *buf = NULL; char *p; bzero(&clnt_info, sizeof (netr_client_t)); if ((sinfo->ssi_cspwlen == 0) && (sinfo->ssi_cipwlen == 0 || (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == 0))) { clnt_info.e_username = "******"; } else { clnt_info.e_username = sinfo->ssi_user; } clnt_info.e_domain = sinfo->ssi_domain; /* * Handle user@domain format. * * We need to extract the user and domain names but * should keep the request data as is. This is important * for some forms of authentication. */ if (*sinfo->ssi_domain == '\0') { buf = smb_strdup(sinfo->ssi_user); if ((p = strchr(buf, '@')) != NULL) { *p = '\0'; clnt_info.e_username = buf; clnt_info.e_domain = p + 1; } } /* * See if this user has already been authenticated. * * If no domain name is provided we cannot determine whether * this is a local or domain user when server is operating * in domain mode, so lookup will be done after authentication. */ if (security == SMB_SECMODE_WORKGRP) { user = smb_session_dup_user(sr->session, hostname, clnt_info.e_username); } else if (*clnt_info.e_domain != '\0') { user = smb_session_dup_user(sr->session, clnt_info.e_domain, clnt_info.e_username); } else { need_lookup = B_TRUE; } if (user != NULL) { sr->user_cr = user->u_cred; sr->smb_uid = user->u_uid; sr->uid_user = user; smb_mfree(buf); return ((user->u_flags & SMB_USER_FLAG_GUEST) ? SMB_AUTH_GUEST : SMB_AUTH_USER); } clnt_info.logon_level = NETR_NETWORK_LOGON; clnt_info.domain = sinfo->ssi_domain; clnt_info.username = sinfo->ssi_user; clnt_info.workstation = sr->session->workstation; clnt_info.ipaddr = sr->session->ipaddr; clnt_info.local_ipaddr = sr->session->local_ipaddr; clnt_info.challenge_key.challenge_key_val = sr->session->challenge_key; clnt_info.challenge_key.challenge_key_len = sr->session->challenge_len; clnt_info.nt_password.nt_password_val = sinfo->ssi_cspwd; clnt_info.nt_password.nt_password_len = sinfo->ssi_cspwlen; clnt_info.lm_password.lm_password_val = sinfo->ssi_cipwd; clnt_info.lm_password.lm_password_len = sinfo->ssi_cipwlen; clnt_info.native_os = sr->session->native_os; clnt_info.native_lm = smbnative_lm_value(sinfo->ssi_native_lm); clnt_info.local_port = sr->session->s_local_port; DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *, &clnt_info); usr_token = smb_get_token(&clnt_info); smb_mfree(buf); if (usr_token == NULL) { smbsr_error(sr, 0, ERRSRV, ERRbadpw); return (SMB_AUTH_FAILED); } if (need_lookup) { user = smb_session_dup_user(sr->session, usr_token->tkn_domain_name, usr_token->tkn_account_name); if (user != NULL) { sr->user_cr = user->u_cred; sr->smb_uid = user->u_uid; sr->uid_user = user; smb_token_free(usr_token); return ((user->u_flags & SMB_USER_FLAG_GUEST) ? SMB_AUTH_GUEST : SMB_AUTH_USER); } } if (usr_token->tkn_session_key) { *session_key = kmem_alloc(sizeof (smb_session_key_t), KM_SLEEP); (void) memcpy(*session_key, usr_token->tkn_session_key, sizeof (smb_session_key_t)); } if ((cr = smb_cred_create(usr_token, &privileges)) != NULL) { user = smb_user_login(sr->session, cr, usr_token->tkn_domain_name, usr_token->tkn_account_name, usr_token->tkn_flags, privileges, usr_token->tkn_audit_sid); smb_cred_rele(user->u_cred); if (user->u_privcred) smb_cred_rele(user->u_privcred); } smb_token_free(usr_token); if (user == NULL) { if (*session_key) kmem_free(*session_key, sizeof (smb_session_key_t)); smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); return (SMB_AUTH_FAILED); } sr->user_cr = user->u_cred; sr->smb_uid = user->u_uid; sr->uid_user = user; return ((user->u_flags & SMB_USER_FLAG_GUEST) ? SMB_AUTH_GUEST : SMB_AUTH_USER); }
/* * After a successful authentication, ask the authsvc to * send us the authentication token. */ static uint32_t smb_auth_get_token(smb_request_t *sr) { smb_lsa_msg_hdr_t msg_hdr; XDR xdrs; smb_user_t *user = sr->uid_user; smb_token_t *token = NULL; cred_t *cr = NULL; void *rbuf = NULL; uint32_t rlen = 0; uint32_t privileges; uint32_t status; int rc; bool_t ok; msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK; msg_hdr.lmh_msglen = 0; status = smb_authsock_sendrecv(user, &msg_hdr, NULL, &rbuf); if (status != 0) goto errout; rlen = msg_hdr.lmh_msglen; switch (msg_hdr.lmh_msgtype) { case LSA_MTYPE_TOKEN: status = 0; break; case LSA_MTYPE_ERROR: if (rlen == sizeof (smb_lsa_eresp_t)) { smb_lsa_eresp_t *ler = rbuf; status = ler->ler_ntstatus; goto errout; } /* FALLTHROUGH */ default: status = NT_STATUS_INTERNAL_ERROR; goto errout; } /* * Authenticated. Decode the LSA_MTYPE_TOKEN. */ xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE); token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP); ok = smb_token_xdr(&xdrs, token); xdr_destroy(&xdrs); if (!ok) { status = RPC_NT_BAD_STUB_DATA; goto errout; } kmem_free(rbuf, rlen); rbuf = NULL; /* * Setup the logon object. */ cr = smb_cred_create(token); if (cr == NULL) goto errout; privileges = smb_priv_xlate(token); (void) smb_user_logon(user, cr, token->tkn_domain_name, token->tkn_account_name, token->tkn_flags, privileges, token->tkn_audit_sid); crfree(cr); /* * Save the session key, and (maybe) enable signing, * but only for real logon (not ANON or GUEST). */ if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) { if (sr->session->dialect >= SMB_VERS_2_BASE) { rc = smb2_sign_begin(sr, token); } else { rc = smb_sign_begin(sr, token); } if (rc != 0) { status = NT_STATUS_INTERNAL_ERROR; goto errout; } } smb_token_free(token); sr->user_cr = user->u_cred; return (0); errout: if (rbuf != NULL) kmem_free(rbuf, rlen); if (token != NULL) smb_token_free(token); return (status); }