TError TContainerHolder::RestoreId(const kv::TNode &node, int &id) { std::string value = ""; TError error = Storage->Get(node, P_RAW_ID, value); if (error) { // FIXME before v1.0 we didn't store id for meta or stopped containers; // don't try to recover, just assign new safe one error = IdMap.Get(id); if (error) return error; L_WRN() << "Couldn't restore container id, using " << id << std::endl; } else { error = StringToInt(value, id); if (error) return error; error = IdMap.GetAt(id); if (error) { // FIXME before v1.0 there was a possibility for two containers // to use the same id, allocate new one upon restore we see this error = IdMap.Get(id); if (error) return error; L_WRN() << "Container ids clashed, using new " << id << std::endl; } return error; } return TError::Success(); }
void InitCred() { TError error; error = GroupId(PORTO_GROUP_NAME, PortoGroup); if (error) L_WRN() << "Cannot find group porto: " << error << std::endl; if (TPath("/proc/sys/kernel/cap_last_cap").ReadInt(LastCapability)) { L_WRN() << "Can't read /proc/sys/kernel/cap_last_cap, assuming 36" << std::endl; LastCapability = 36; //FIXME } }
TError TClient::IdentifyClient(TContainerHolder &holder, bool initial) { std::shared_ptr<TContainer> ct; struct ucred cr; socklen_t len = sizeof(cr); TError error; if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len)) return TError(EError::Unknown, errno, "Cannot identify client: getsockopt() failed"); /* check that request from the same pid and container is still here */ if (!initial && Pid == cr.pid && TaskCred.Uid == cr.uid && TaskCred.Gid == cr.gid && !ClientContainer.expired()) return TError::Success(); TaskCred.Uid = cr.uid; TaskCred.Gid = cr.gid; Pid = cr.pid; error = holder.FindTaskContainer(Pid, ct); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot identify container of pid " << Pid << " : " << error << std::endl; if (error) return error; if (!ct->IsPortoEnabled()) return TError(EError::Permission, "Porto disabled in container " + ct->GetName()); ClientContainer = ct; error = TPath("/proc/" + std::to_string(Pid) + "/comm").ReadAll(Comm, 64); if (error) Comm = "<unknown process>"; else Comm.resize(Comm.length() - 1); /* cut \n at the end */ if (ct->IsRoot()) { Cred.Uid = cr.uid; Cred.Gid = cr.gid; error = LoadGroups(); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot load supplementary group list" << Pid << " : " << error << std::endl; } else { /* requests from containers are executed in behalf of their owners */ Cred = ct->OwnerCred; } ReadOnlyAccess = !Cred.IsPortoUser(); return TError::Success(); }
TError TClient::AcceptConnection(TContext &context, int listenFd) { struct sockaddr_un peer_addr; socklen_t peer_addr_size; TError error; peer_addr_size = sizeof(struct sockaddr_un); Fd = accept4(listenFd, (struct sockaddr *) &peer_addr, &peer_addr_size, SOCK_NONBLOCK | SOCK_CLOEXEC); if (Fd < 0) { error = TError(EError::Unknown, errno, "accept4()"); if (error.GetErrno() != EAGAIN) L_WRN() << "Cannot accept client: " << error << std::endl; return error; } error = IdentifyClient(*context.Cholder, true); if (error) { close(Fd); Fd = -1; return error; } if (Verbose) L() << "Client connected: " << *this << std::endl; return TError::Success(); }
TError TClient::IdentifyClient(TContainerHolder &holder, bool initial) { struct ucred cr; socklen_t len = sizeof(cr); TError error; if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len)) return TError(EError::Unknown, errno, "Cannot identify client: getsockopt() failed"); if (!initial && Pid == cr.pid && Cred.Uid == cr.uid && Cred.Gid == cr.gid && !ClientContainer.expired()) return TError::Success(); Cred.Uid = cr.uid; Cred.Gid = cr.gid; Pid = cr.pid; error = TPath("/proc/" + std::to_string(Pid) + "/comm").ReadAll(Comm, 64); if (error) Comm = "<unknown process>"; else Comm.resize(Comm.length() - 1); /* cut \n at the end */ error = LoadGroups(); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot load supplementary group list" << Pid << " : " << error << std::endl; ReadOnlyAccess = !Cred.IsPortoUser(); std::shared_ptr<TContainer> container; error = holder.FindTaskContainer(Pid, container); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot identify container of pid " << Pid << " : " << error << std::endl; if (error) return error; if (!container->Prop->Get<bool>(P_ENABLE_PORTO)) return TError(EError::Permission, "Porto disabled in container " + container->GetName()); ClientContainer = container; return TError::Success(); }
TError TClient::Identify(TContainerHolder &holder, bool full) { struct ucred cr; socklen_t len = sizeof(cr); if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len) == 0) { if (full) { TFile f("/proc/" + std::to_string(cr.pid) + "/comm"); std::string comm; if (f.AsString(comm)) comm = "unknown process"; comm.erase(std::remove(comm.begin(), comm.end(), '\n'), comm.end()); Pid = cr.pid; Comm = comm; TError err = LoadGroups(); if (err) { L_WRN() << "Can't load supplementary group list" << cr.pid << " : " << err << std::endl; } err = IdentifyContainer(holder); if (err) { L_WRN() << "Can't identify container of pid " << cr.pid << " : " << err << std::endl; return err; } } else { if (Container.expired()) return TError(EError::Unknown, "Can't identify client (container is dead)"); } Cred.Uid = cr.uid; Cred.Gid = cr.gid; return TError::Success(); } else { return TError(EError::Unknown, "Can't identify client (getsockopt() failed)"); } }
TError TClient::ReadRequest(rpc::TContainerRequest &request) { TScopedLock lock(Mutex); if (Processing) { L_WRN() << "Client request before response: " << *this << std::endl; return TError::Success(); } if (Fd < 0) return TError(EError::Unknown, "Connection closed"); if (Offset >= Buffer.size()) Buffer.resize(Offset + 4096); ssize_t len = recv(Fd, &Buffer[Offset], Buffer.size() - Offset, MSG_DONTWAIT); if (len > 0) Offset += len; else if (len == 0) return TError(EError::Unknown, "recv return zero"); else if (errno != EAGAIN && errno != EWOULDBLOCK) return TError(EError::Unknown, errno, "recv request failed"); if (Length && Offset < Length) return TError::Queued(); google::protobuf::io::CodedInputStream input(&Buffer[0], Offset); uint32_t length; if (!input.ReadVarint32(&length)) return TError::Queued(); if (!Length) { if (length > config().daemon().max_msg_len()) return TError(EError::Unknown, "oversized request: " + std::to_string(length)); Length = length + google::protobuf::io::CodedOutputStream::VarintSize32(length); if (Buffer.size() < Length) Buffer.resize(Length + 4096); if (Offset < Length) return TError::Queued(); } if (!request.ParseFromCodedStream(&input)) return TError(EError::Unknown, "cannot parse request"); if (Offset > Length) return TError(EError::Unknown, "garbage after request"); Processing = true; return EpollLoop->StopInput(Fd); }