/* * smb_pathname_preprocess_quota * * There is a special file required by windows so that the quota * tab will be displayed by windows clients. This is created in * a special directory, $EXTEND, at the root of the shared file * system. To hide this directory prepend a '.' (dot). */ static void smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn) { char *name = "$EXTEND"; char *new_name = ".$EXTEND"; char *p, *slash; int len; if (!smb_node_is_vfsroot(sr->tid_tree->t_snode)) return; p = pn->pn_path; /* ignore any initial "\\" */ p += strspn(p, "\\"); if (smb_strcasecmp(p, name, strlen(name)) != 0) return; p += strlen(name); if ((*p != ':') && (*p != '\\') && (*p != '\0')) return; slash = (pn->pn_path[0] == '\\') ? "\\" : ""; len = strlen(pn->pn_path) + 2; pn->pn_path = smb_srm_alloc(sr, len); (void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p); (void) smb_strupr(pn->pn_path); }
/* * smb_transfer_write_raw_data * * Handles the second transfer phase of SMB_COM_WRITE_RAW. smb_com_write_raw() * will process the parameters and data from the SMB and send the initial * SMB response. This function reads the remaining data from the socket * as it arrives from the client. * * Clients may send KEEP_ALIVE messages (when using NBT) between the first * and second parts of write raw requests. The only session transport * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE. * * Returns 0 for success, non-zero for failure */ int smb_transfer_write_raw_data(smb_request_t *sr, smb_rw_param_t *param) { smb_session_t *session = sr->session; smb_xprt_t hdr; void *pbuf; do { if (smb_session_xprt_gethdr(session, &hdr) != 0) return (-1); if ((hdr.xh_type == SESSION_MESSAGE) || (hdr.xh_type == SESSION_KEEP_ALIVE)) { session->keep_alive = smb_keep_alive; } else { return (-1); } } while (hdr.xh_type == SESSION_KEEP_ALIVE); if (hdr.xh_length < param->rw_vdb.vdb_uio.uio_resid) return (-1); /* Less data than we were expecting. */ pbuf = smb_srm_alloc(sr, hdr.xh_length); if (smb_sorecv(session->sock, pbuf, hdr.xh_length) != 0) return (-1); param->rw_vdb.vdb_iovec[0].iov_base = pbuf; param->rw_vdb.vdb_uio.uio_iovcnt = 1; param->rw_vdb.vdb_uio.uio_segflg = UIO_SYSSPACE; param->rw_vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT; return (0); }
char * smb_srm_strdup(smb_request_t *sr, const char *s) { char *p; size_t size; size = strlen(s) + 1; p = smb_srm_alloc(sr, size); bcopy(s, p, size); return (p); }
/* * sr - the request info, used to find root of dataset, * unicode or ascii, where the share is rooted in the * dataset * root_node - root of the share * cur_node - where in the share for the command * buf - is the path for the command to be processed * returned without @GMT if processed * vss_cur_node - returned value for the snapshot version * of the cur_node * vss_root_node - returned value for the snapshot version * of the root_node * * This routine is the processing for handling the * SMB_FLAGS2_REPARSE_PATH bit being set in the smb header. * * By using the cur_node passed in, a new node is found or * created that is the same place in the directory tree, but * in the snapshot. We also use root_node to do the same for * the root. * Once the new smb node is found, the path is modified by * removing the @GMT token from the path in the buf. */ int smb_vss_lookup_nodes(smb_request_t *sr, smb_node_t *root_node, smb_node_t *cur_node, char *buf, smb_node_t **vss_cur_node, smb_node_t **vss_root_node) { smb_arg_open_t *op = &sr->arg.open; smb_node_t *tnode; char *snapname, *path; char *gmttoken; char gmttok_buf[SMB_VSS_GMT_SIZE]; vnode_t *fsrootvp = NULL; time_t toktime; int err = 0; boolean_t smb1; if (sr->tid_tree == NULL) return (ESTALE); tnode = sr->tid_tree->t_snode; ASSERT(tnode); ASSERT(tnode->vp); ASSERT(tnode->vp->v_vfsp); smb1 = (sr->session->dialect < 0x200); if (smb1) { const char *p; /* get gmttoken from buf */ if ((p = smb_vss_find_gmttoken(buf)) == NULL) return (ENOENT); bcopy(p, gmttok_buf, SMB_VSS_GMT_SIZE); gmttok_buf[SMB_VSS_GMT_SIZE - 1] = '\0'; gmttoken = gmttok_buf; toktime = 0; } else { /* SMB2 and later */ gmttoken = NULL; toktime = op->timewarp.tv_sec; } path = smb_srm_alloc(sr, MAXPATHLEN); snapname = smb_srm_alloc(sr, MAXPATHLEN); err = smb_node_getmntpath(tnode, path, MAXPATHLEN); if (err != 0) return (err); /* * Find the corresponding snapshot name. If snapname is * empty after the map call, no such snapshot was found. */ *snapname = '\0'; smb_vss_map_gmttoken(sr->tid_tree, path, gmttoken, toktime, snapname); if (*snapname == '\0') return (ENOENT); /* find snapshot nodes */ err = VFS_ROOT(tnode->vp->v_vfsp, &fsrootvp); if (err != 0) return (err); /* find snapshot node corresponding to root_node */ err = smb_vss_lookup_node(sr, root_node, fsrootvp, snapname, cur_node, vss_root_node); if (err == 0) { /* find snapshot node corresponding to cur_node */ err = smb_vss_lookup_node(sr, cur_node, fsrootvp, snapname, cur_node, vss_cur_node); if (err != 0) smb_node_release(*vss_root_node); } VN_RELE(fsrootvp); if (smb1) smb_vss_remove_first_token_from_path(buf); return (err); }
/* * Handle new-style (extended security) session setup. * Returns zero: success, non-zero: error (value not used) * * Note that this style uses a sequence of session setup requests, * where the first has SMB UID=0, and subsequent requests in the * same authentication sequence have the SMB UID returned for that * first request. We allocate a USER object when the first request * in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that * to maintain state between requests in this sequence. The state * for one sequence includes an AF_UNIX "authsock" connection to the * user-space smbd. The neat part of this is: in smbd, the handler * for the server-side of one authsock gets only request specific to * one authentication sequence, simplifying it's work immensely. * When the authentication sequence is finished, with either success * or failure, the local side of the authsock is closed. * * As with the old-style authentication, if we succeed, then the * last message from smbd will be an smb_token_t encoding the * information about the new user. * * Outline: * (a) On the first request (UID==0) create a USER object, * and on subsequent requests, find USER by SMB UID. * (b) Send message / recv. response as above, * (c) If response says "we're done", close authsock * (both success and failure must close authsock) */ int smb_authenticate_ext(smb_request_t *sr) { smb_lsa_msg_hdr_t msg_hdr; smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; smb_user_t *user = NULL; void *rbuf = NULL; uint32_t rlen = 0; uint32_t status; ASSERT(sr->uid_user == NULL); /* * On the first request (UID==0) create a USER object. * On subsequent requests (UID!=0) find the USER object. * Either way, sr->uid_user is set, so our ref. on the * user object is dropped during normal cleanup work * for the smb_request (sr). Ditto u_authsock. */ if (sr->smb_uid == 0) { user = smb_user_new(sr->session); if (user == NULL) return (NT_STATUS_TOO_MANY_SESSIONS); /* user cleanup in smb_request_free */ sr->uid_user = user; sr->smb_uid = user->u_uid; /* * Open a connection to the local logon service. * If we can't, it may be busy, or not running. * Don't log here - this may be frequent. */ if ((status = smb_authsock_open(user)) != 0) goto errout; /* * Tell the auth. svc who this client is. */ if ((status = smb_auth_do_clinfo(sr)) != 0) goto errout; msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST; } else { user = smb_session_lookup_uid_st(sr->session, sr->smb_uid, SMB_USER_STATE_LOGGING_ON); if (user == NULL) return (NT_STATUS_USER_SESSION_DELETED); /* user cleanup in smb_request_free */ sr->uid_user = user; msg_hdr.lmh_msgtype = LSA_MTYPE_ESNEXT; } /* * Wrap the "security blob" with our header * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT) * and send it up the authsock with either */ msg_hdr.lmh_msglen = sinfo->ssi_iseclen; status = smb_authsock_sendrecv(user, &msg_hdr, sinfo->ssi_isecblob, &rbuf); if (status != 0) goto errout; rlen = msg_hdr.lmh_msglen; /* * Decode the response message. * Note: allocated rbuf */ switch (msg_hdr.lmh_msgtype) { case LSA_MTYPE_ES_CONT: sinfo->ssi_oseclen = (uint16_t)rlen; sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen); bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen); /* * This is not really an error, but tells the client * it should send another session setup request. */ status = NT_STATUS_MORE_PROCESSING_REQUIRED; break; case LSA_MTYPE_ES_DONE: sinfo->ssi_oseclen = (uint16_t)rlen; sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen); bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen); sinfo->ssi_ntpwlen = 0; /* * Get the final auth. token. */ status = smb_auth_get_token(sr); break; case LSA_MTYPE_ERROR: /* * Authentication failed. Return the error * provided in the reply message. */ if (rlen == sizeof (smb_lsa_eresp_t)) { smb_lsa_eresp_t *ler = rbuf; status = ler->ler_ntstatus; goto errout; } /* FALLTHROUGH */ default: /* Bogus message type */ status = NT_STATUS_INTERNAL_ERROR; goto errout; } if (status != 0 && status != NT_STATUS_MORE_PROCESSING_REQUIRED) { errout: smb_user_logoff(user); } if (rbuf != NULL) kmem_free(rbuf, rlen); return (status); }