static int _send(struct socket *sock, const void *buff, int len) { struct iovec iov; struct msghdr msg; struct scm_cookie scm; int err; iov.iov_base = (void *) buff; iov.iov_len = len; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; err = scm_send(sock, &msg, &scm); if (err < 0) { return err; } err = sock->ops->sendmsg(sock, &msg, len, &scm); scm_destroy(&scm); return err; }
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) { struct cmsghdr *cmsg; int err; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { err = -EINVAL; /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ /* The first check was omitted in <= 2.2.5. The reasoning was that parser checks cmsg_len in any case, so that additional check would be work duplication. But if cmsg_level is not SOL_SOCKET, we do not check for too short ancillary data object at all! Oops. OK, let's add it... */ if (cmsg->cmsg_len < sizeof(struct cmsghdr) || (unsigned long)(((char*)cmsg - (char*)msg->msg_control) + cmsg->cmsg_len) > msg->msg_controllen) goto error; if (cmsg->cmsg_level != SOL_SOCKET) continue; switch (cmsg->cmsg_type) { case SCM_RIGHTS: err=scm_fp_copy(cmsg, &p->fp); if (err<0) goto error; break; case SCM_CREDENTIALS: if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) goto error; memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); err = scm_check_creds(&p->creds); if (err) goto error; break; default: goto error; } } if (p->fp && !p->fp->count) { kfree(p->fp); p->fp = NULL; } return 0; error: scm_destroy(p); return err; }
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) { struct cmsghdr *cmsg; int err; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { err = -EINVAL; /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ /* The first check was omitted in <= 2.2.5. The reasoning was that parser checks cmsg_len in any case, so that additional check would be work duplication. But if cmsg_level is not SOL_SOCKET, we do not check for too short ancillary data object at all! Oops. OK, let's add it... */ if (!CMSG_OK(msg, cmsg)) goto error; if (cmsg->cmsg_level != SOL_SOCKET) continue; switch (cmsg->cmsg_type) { case SCM_RIGHTS: if (!sock->ops || sock->ops->family != PF_UNIX) goto error; err=scm_fp_copy(cmsg, &p->fp); if (err<0) goto error; break; case SCM_CREDENTIALS: if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) goto error; memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); err = scm_check_creds(&p->creds); if (err) goto error; if (pid_vnr(p->pid) != p->creds.pid) { struct pid *pid; err = -ESRCH; pid = find_get_pid(p->creds.pid); if (!pid) goto error; put_pid(p->pid); p->pid = pid; } if ((p->cred->euid != p->creds.uid) || (p->cred->egid != p->creds.gid)) { struct cred *cred; err = -ENOMEM; cred = prepare_creds(); if (!cred) goto error; cred->uid = cred->euid = p->creds.uid; cred->gid = cred->egid = p->creds.uid; put_cred(p->cred); p->cred = cred; } break; default: goto error; } } if (p->fp && !p->fp->count) { kfree(p->fp); p->fp = NULL; } return 0; error: scm_destroy(p); return err; }
static int do_ncp_tcp_rpc_call(struct ncp_server *server, int size, struct ncp_reply_header* reply_buf, int max_reply_size) { struct file *file; struct socket *sock; int result; struct iovec iov[2]; struct msghdr msg; struct scm_cookie scm; __u32 ncptcp_rcvd_hdr[2]; __u32 ncptcp_xmit_hdr[4]; int datalen; /* We have to check the result, so store the complete header */ struct ncp_request_header request = *((struct ncp_request_header *) (server->packet)); file = server->ncp_filp; sock = &file->f_dentry->d_inode->u.socket_i; ncptcp_xmit_hdr[0] = htonl(NCP_TCP_XMIT_MAGIC); ncptcp_xmit_hdr[1] = htonl(size + 16); ncptcp_xmit_hdr[2] = htonl(NCP_TCP_XMIT_VERSION); ncptcp_xmit_hdr[3] = htonl(max_reply_size + 8); DDPRINTK("ncpfs: req.typ: %04X, con: %d, " "seq: %d", request.type, (request.conn_high << 8) + request.conn_low, request.sequence); DDPRINTK(" func: %d\n", request.function); iov[1].iov_base = (void *) server->packet; iov[1].iov_len = size; iov[0].iov_base = ncptcp_xmit_hdr; iov[0].iov_len = 16; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_flags = MSG_NOSIGNAL; result = scm_send(sock, &msg, &scm); if (result < 0) { return result; } result = sock->ops->sendmsg(sock, &msg, size + 16, &scm); scm_destroy(&scm); if (result < 0) { printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result); return result; } rstrcv: result = do_tcp_rcv(server, ncptcp_rcvd_hdr, 8); if (result) return result; if (ncptcp_rcvd_hdr[0] != htonl(NCP_TCP_RCVD_MAGIC)) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(ncptcp_rcvd_hdr[0])); return -EIO; } datalen = ntohl(ncptcp_rcvd_hdr[1]); if (datalen < 8 + sizeof(*reply_buf) || datalen > max_reply_size + 8) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen); return -EIO; } datalen -= 8; result = do_tcp_rcv(server, reply_buf, datalen); if (result) return result; if (reply_buf->type != NCP_REPLY) { DDPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", reply_buf->type); goto rstrcv; } if (request.type == NCP_ALLOC_SLOT_REQUEST) return datalen; if (reply_buf->sequence != request.sequence) { printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n"); return -EIO; } if ((reply_buf->conn_low != request.conn_low) || (reply_buf->conn_high != request.conn_high)) { printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n"); return -EIO; } return datalen; }
static int smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command, int ldata, unsigned char *data, int lparam, unsigned char *param) { struct socket *sock = server_sock(server); struct scm_cookie scm; int err; /* I know the following is very ugly, but I want to build the smb packet as efficiently as possible. */ const int smb_parameters = 15; const int oparam = ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3); const int odata = ROUND_UP(oparam + lparam); const int bcc = odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2); const int packet_length = SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2; unsigned char padding[4] = {0,}; char *p; struct iovec iov[4]; struct msghdr msg; /* N.B. This test isn't valid! packet_size may be < max_xmit */ if ((bcc + oparam) > server->opt.max_xmit) { return -ENOMEM; } p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc); WSET(server->packet, smb_tpscnt, lparam); WSET(server->packet, smb_tdscnt, ldata); /* N.B. these values should reflect out current packet size */ WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER); WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER); WSET(server->packet, smb_msrcnt, 0); WSET(server->packet, smb_flags, 0); DSET(server->packet, smb_timeout, 0); WSET(server->packet, smb_pscnt, lparam); WSET(server->packet, smb_psoff, oparam - 4); WSET(server->packet, smb_dscnt, ldata); WSET(server->packet, smb_dsoff, odata - 4); WSET(server->packet, smb_suwcnt, 1); WSET(server->packet, smb_setup0, trans2_command); *p++ = 0; /* null smb_name for trans2 */ *p++ = 'D'; /* this was added because OS/2 does it */ *p++ = ' '; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_iov = iov; msg.msg_iovlen = 4; msg.msg_flags = 0; iov[0].iov_base = (void *) server->packet; iov[0].iov_len = oparam; iov[1].iov_base = (param == NULL) ? padding : param; iov[1].iov_len = lparam; iov[2].iov_base = padding; iov[2].iov_len = odata - oparam - lparam; iov[3].iov_base = (data == NULL) ? padding : data; iov[3].iov_len = ldata; err = scm_send(sock, &msg, &scm); if (err >= 0) { err = sock->ops->sendmsg(sock, &msg, packet_length, &scm); scm_destroy(&scm); } return err; }