Hi,

this is the last diff of the series.  It allows users to start or stop
VMs and to access the console accordingly.  In order to make it work,
VMs have to be pre-configured with the new "owner" option in vm.conf
or an included file.

1. Add a "owner user[:group]" in your vm block of vm.conf, eg.

        vm "foo" {
                owner :wheel
        }

        $ vmctl status 
           ID   PID VCPUS  MAXMEM  CURMEM     TTY        OWNER NAME
            -     -     1    1.0G       -       -       :wheel foo

2. You can now start, stop and attach to it as a matching user:

        $ vmctl start foo
        $ vmctl status
           ID   PID VCPUS  MAXMEM  CURMEM     TTY        OWNER NAME
            1 82712     1    1.0G    169M   ttyp6   reyk:wheel foo
        $ vmctl console foo
        $ vmctl stop foo

It doesn't let you do any template/user-config yet, but this would be
another step.  The tty handling is inspired by sshd, maybe a bit
tricky, and needs extra pledges in the parent process.

OK?

Reyk

    Add "owner" option to set a user/group ownership for pre-configured VMs
    
    This allows matching users to start or stop VMs that they "own" and to
    access the console accordingly.

diff --git usr.sbin/vmctl/main.c usr.sbin/vmctl/main.c
index f0007c9..20227ac 100644
--- usr.sbin/vmctl/main.c
+++ usr.sbin/vmctl/main.c
@@ -151,7 +151,7 @@ parse(int argc, char *argv[])
 
        if (!ctl->has_pledge) {
                /* pledge(2) default if command doesn't have its own pledge */
-               if (pledge("stdio rpath exec unix", NULL) == -1)
+               if (pledge("stdio rpath exec unix getpw", NULL) == -1)
                        err(1, "pledge");
        }
        if (ctl->main(&res, argc, argv) != 0)
diff --git usr.sbin/vmctl/vmctl.c usr.sbin/vmctl/vmctl.c
index ca2da8a..01f2617 100644
--- usr.sbin/vmctl/vmctl.c
+++ usr.sbin/vmctl/vmctl.c
@@ -16,7 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/queue.h>
 #include <sys/uio.h>
 #include <sys/stat.h>
@@ -35,6 +35,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <util.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include "vmd.h"
 #include "vmctl.h"
@@ -369,14 +371,36 @@ print_vm_info(struct vmop_info_result *list, size_t ct)
        char *vcpu_state, *tty;
        char curmem[FMT_SCALED_STRSIZE];
        char maxmem[FMT_SCALED_STRSIZE];
+       char user[16];
+       struct passwd *pw;
+       struct group *gr;
 
-       printf("%5s %5s %5s %7s %7s %7s %s\n", "ID", "PID", "VCPUS",
-           "MAXMEM", "CURMEM", "TTY", "NAME");
+       printf("%5s %5s %5s %7s %7s %7s %12s %s\n", "ID", "PID", "VCPUS",
+           "MAXMEM", "CURMEM", "TTY", "OWNER", "NAME");
 
        for (i = 0; i < ct; i++) {
                vmi = &list[i];
                vir = &vmi->vir_info;
                if (check_info_id(vir->vir_name, vir->vir_id)) {
+                       /* get user name */
+                       if ((pw = getpwuid(vmi->vir_uid)) == NULL)
+                               (void)snprintf(user, sizeof(user),
+                                   "%d", vmi->vir_uid);
+                       else
+                               (void)strlcpy(user, pw->pw_name,
+                                   sizeof(user));
+                       /* get group name */
+                       if (vmi->vir_gid != -1) {
+                               if (vmi->vir_uid == 0)
+                                       *user = '\0';
+                               if ((gr = getgrgid(vmi->vir_gid)) == NULL)
+                                       (void)snprintf(user, sizeof(user),
+                                           "%s:%lld", user, vmi->vir_gid);
+                               else
+                                       (void)snprintf(user, sizeof(user),
+                                           "%s:%s", user, gr->gr_name);
+                       }
+
                        (void)strlcpy(curmem, "-", sizeof(curmem));
                        (void)strlcpy(maxmem, "-", sizeof(maxmem));
 
@@ -392,16 +416,16 @@ print_vm_info(struct vmop_info_result *list, size_t ct)
                                (void)fmt_scaled(vir->vir_used_size, curmem);
 
                                /* running vm */
-                               printf("%5u %5u %5zd %7s %7s %7s %s\n",
+                               printf("%5u %5u %5zd %7s %7s %7s %12s %s\n",
                                    vir->vir_id, vir->vir_creator_pid,
                                    vir->vir_ncpus, maxmem, curmem,
-                                   tty, vir->vir_name);
+                                   tty, user, vir->vir_name);
                        } else {
                                /* disabled vm */
-                               printf("%5s %5s %5zd %7s %7s %7s %s\n",
+                               printf("%5s %5s %5zd %7s %7s %7s %12s %s\n",
                                    "-", "-",
                                    vir->vir_ncpus, maxmem, curmem,
-                                   "-", vir->vir_name);
+                                   "-", user, vir->vir_name);
                        }
                }
                if (check_info_id(vir->vir_name, vir->vir_id) > 0) {
diff --git usr.sbin/vmd/config.c usr.sbin/vmd/config.c
index a16c143..72c151a 100644
--- usr.sbin/vmd/config.c
+++ usr.sbin/vmd/config.c
@@ -120,7 +120,7 @@ config_getreset(struct vmd *env, struct imsg *imsg)
 }
 
 int
-config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid)
+config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid)
 {
        struct vmd_if           *vif;
        struct vmop_create_params *vmc = &vm->vm_params;
@@ -158,6 +158,7 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, 
uint32_t peerid)
                tapfds[i] = -1;
 
        vm->vm_peerid = peerid;
+       vm->vm_uid = uid;
 
        /* Open external kernel for child */
        if (strlen(vcp->vcp_kernel) &&
@@ -309,7 +310,7 @@ config_getvm(struct privsep *ps, struct imsg *imsg)
        memcpy(&vmc, imsg->data, sizeof(vmc));
 
        errno = 0;
-       if (vm_register(ps, &vmc, &vm, imsg->hdr.peerid) == -1)
+       if (vm_register(ps, &vmc, &vm, imsg->hdr.peerid, 0) == -1)
                goto fail;
 
        /* If the fd is -1, the kernel will be searched on the disk */
diff --git usr.sbin/vmd/control.c usr.sbin/vmd/control.c
index cda7df9..0bdf90e 100644
--- usr.sbin/vmd/control.c
+++ usr.sbin/vmd/control.c
@@ -324,6 +324,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
 
                switch (imsg.hdr.type) {
                case IMSG_VMDOP_GET_INFO_VM_REQUEST:
+               case IMSG_VMDOP_TERMINATE_VM_REQUEST:
+               case IMSG_VMDOP_START_VM_REQUEST:
                        break;
                default:
                        if (c->peercred.uid != 0) {
@@ -351,7 +353,6 @@ control_dispatch_imsg(int fd, short event, void *arg)
                case IMSG_CTL_VERBOSE:
                        if (IMSG_DATA_SIZE(&imsg) < sizeof(v))
                                goto fail;
-
                        memcpy(&v, imsg.data, sizeof(v));
                        log_setverbose(v);
 
@@ -360,9 +361,12 @@ control_dispatch_imsg(int fd, short event, void *arg)
                case IMSG_VMDOP_START_VM_REQUEST:
                        if (IMSG_DATA_SIZE(&imsg) < sizeof(vmc))
                                goto fail;
+                       memcpy(&vmc, imsg.data, sizeof(vmc));
+                       vmc.vmc_uid = c->peercred.uid;
+                       vmc.vmc_gid = -1;
+
                        if (proc_compose_imsg(ps, PROC_PARENT, -1,
-                           imsg.hdr.type, fd, -1,
-                           imsg.data, IMSG_DATA_SIZE(&imsg)) == -1) {
+                           imsg.hdr.type, fd, -1, &vmc, sizeof(vmc)) == -1) {
                                control_close(fd, cs);
                                return;
                        }
@@ -370,9 +374,11 @@ control_dispatch_imsg(int fd, short event, void *arg)
                case IMSG_VMDOP_TERMINATE_VM_REQUEST:
                        if (IMSG_DATA_SIZE(&imsg) < sizeof(vid))
                                goto fail;
+                       memcpy(&vid, imsg.data, sizeof(vid));
+                       vid.vid_uid = c->peercred.uid;
+
                        if (proc_compose_imsg(ps, PROC_PARENT, -1,
-                           imsg.hdr.type, fd, -1,
-                           imsg.data, IMSG_DATA_SIZE(&imsg)) == -1) {
+                           imsg.hdr.type, fd, -1, &vid, sizeof(vid)) == -1) {
                                control_close(fd, cs);
                                return;
                        }
diff --git usr.sbin/vmd/parse.y usr.sbin/vmd/parse.y
index 30f002f..062146b 100644
--- usr.sbin/vmd/parse.y
+++ usr.sbin/vmd/parse.y
@@ -44,6 +44,8 @@
 #include <util.h>
 #include <errno.h>
 #include <err.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include "proc.h"
 #include "vmd.h"
@@ -101,6 +103,10 @@ typedef struct {
                uint8_t          lladdr[ETHER_ADDR_LEN];
                int64_t          number;
                char            *string;
+               struct {
+                       uid_t    uid;
+                       int64_t  gid;
+               }                owner;
        } v;
        int lineno;
 } YYSTYPE;
@@ -110,7 +116,7 @@ typedef struct {
 
 %token INCLUDE ERROR
 %token ADD DISK DOWN GROUP INTERFACE NIFS PATH SIZE SWITCH UP VMID
-%token ENABLE DISABLE VM KERNEL LLADDR MEMORY
+%token ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
 %type  <v.number>      disable
@@ -118,6 +124,7 @@ typedef struct {
 %type  <v.lladdr>      lladdr
 %type  <v.string>      string
 %type  <v.string>      optstring
+%type  <v.owner>       owner_id
 
 %%
 
@@ -260,6 +267,10 @@ vm         : VM string                     {
                                yyerror("vm name too long");
                                YYERROR;
                        }
+
+                       /* set default user/group permissions */
+                       vmc.vmc_uid = 0;
+                       vmc.vmc_gid = -1;
                } '{' optnl vm_opts_l '}'       {
                        int ret;
 
@@ -268,7 +279,8 @@ vm          : VM string                     {
                                vcp->vcp_nnics = vcp_nnics;
 
                        if (!env->vmd_noaction) {
-                               ret = vm_register(&env->vmd_ps, &vmc, &vm, 0);
+                               ret = vm_register(&env->vmd_ps, &vmc,
+                                   &vm, 0, 0);
                                if (ret == -1 && errno == EALREADY) {
                                        log_debug("%s:%d: vm \"%s\""
                                            " skipped (%s)",
@@ -398,6 +410,57 @@ vm_opts            : disable                       {
                        vcp->vcp_memranges[0].vmr_size = (size_t)res;
                        vmc.vmc_flags |= VMOP_CREATE_MEMORY;
                }
+               | OWNER owner_id                {
+                       vmc.vmc_uid = $2.uid;
+                       vmc.vmc_gid = $2.gid;
+               }
+               ;
+
+owner_id       : /* none */            {
+                       $$.uid = 0;
+                       $$.gid = -1;
+               }
+               | NUMBER                {
+                       $$.uid = $1;
+                       $$.gid = -1;
+               }
+               | STRING                {
+                       char            *user, *group;
+                       struct passwd   *pw;
+                       struct group    *gr;
+
+                       $$.uid = 0;
+                       $$.gid = -1;
+
+                       user = $1;
+                       if ((group = strchr(user, ':')) != NULL) {
+                               if (group == user)
+                                       user = NULL;
+                               *group++ = '\0';
+                       }
+
+                       if (user != NULL && *user) {
+                               if ((pw = getpwnam(user)) == NULL) {
+                                       yyerror("failed to get user: %s",
+                                           user);
+                                       free($1);
+                                       YYERROR;
+                               }
+                               $$.uid = pw->pw_uid;
+                       }
+
+                       if (group != NULL && *group) {
+                               if ((gr = getgrnam(group)) == NULL) {
+                                       yyerror("failed to get group: %s",
+                                           group);
+                                       free($1);
+                                       YYERROR;
+                               }
+                               $$.gid = gr->gr_gid;
+                       }
+
+                       free($1);
+               }
                ;
 
 iface_opts_o   : '{' optnl iface_opts_l '}'
@@ -544,6 +607,7 @@ lookup(char *s)
                { "kernel",             KERNEL },
                { "lladdr",             LLADDR },
                { "memory",             MEMORY },
+               { "owner",              OWNER },
                { "size",               SIZE },
                { "switch",             SWITCH },
                { "up",                 UP },
diff --git usr.sbin/vmd/vm.conf.5 usr.sbin/vmd/vm.conf.5
index 9a48a51..c1401ec 100644
--- usr.sbin/vmd/vm.conf.5
+++ usr.sbin/vmd/vm.conf.5
@@ -161,6 +161,12 @@ Kernel to load when booting the VM.
 .It Cm memory Ar bytes
 Memory size of the VM, in bytes, rounded to megabytes.
 The default is 512M.
+.It Cm owner Ar user Ns Op : Ns Ar group
+Set the owner of the VM to the specified user or group.
+The owner will be allowed to start or stop the VM and get the
+permissions to open the VM's console.
+.It Cm owner Pf : Ar group
+Set the owner to the specified group.
 .El
 .Sh SWITCH CONFIGURATION
 A virtual switch allows VMs to communicate with other network interfaces on the
diff --git usr.sbin/vmd/vmd.c usr.sbin/vmd/vmd.c
index ed678ee..6152c4f 100644
--- usr.sbin/vmd/vmd.c
+++ usr.sbin/vmd/vmd.c
@@ -20,6 +20,7 @@
 #include <sys/queue.h>
 #include <sys/wait.h>
 #include <sys/cdefs.h>
+#include <sys/stat.h>
 #include <sys/tty.h>
 #include <sys/ioctl.h>
 
@@ -35,6 +36,8 @@
 #include <syslog.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include "proc.h"
 #include "vmd.h"
@@ -80,7 +83,7 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct 
imsg *imsg)
        case IMSG_VMDOP_START_VM_REQUEST:
                IMSG_SIZE_CHECK(imsg, &vmc);
                memcpy(&vmc, imsg->data, sizeof(vmc));
-               ret = vm_register(ps, &vmc, &vm, 0);
+               ret = vm_register(ps, &vmc, &vm, 0, vmc.vmc_uid);
                if (vmc.vmc_flags == 0) {
                        /* start an existing VM with pre-configured options */
                        if (!(ret == -1 && errno == EALREADY)) {
@@ -92,7 +95,7 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct 
imsg *imsg)
                        cmd = IMSG_VMDOP_START_VM_RESPONSE;
                }
                if (res == 0 &&
-                   config_setvm(ps, vm, imsg->hdr.peerid) == -1) {
+                   config_setvm(ps, vm, imsg->hdr.peerid, vmc.vmc_uid) == -1) {
                        res = errno;
                        cmd = IMSG_VMDOP_START_VM_RESPONSE;
                }
@@ -108,6 +111,12 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, 
struct imsg *imsg)
                                break;
                        }
                        id = vm->vm_params.vmc_params.vcp_id;
+               } else
+                       vm = vm_getbyid(id);
+               if (vm_checkperm(vm, vid.vid_uid) != 0) {
+                       res = EPERM;
+                       cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
+                       break;
                }
                memset(&vtp, 0, sizeof(vtp));
                vtp.vtp_vm_id = id;
@@ -247,7 +256,7 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct 
imsg *imsg)
                } else if (vmr.vmr_result == EAGAIN) {
                        /* Stop VM instance but keep the tty open */
                        vm_stop(vm, 1);
-                       config_setvm(ps, vm, (uint32_t)-1);
+                       config_setvm(ps, vm, (uint32_t)-1, 0);
                }
                break;
        case IMSG_VMDOP_GET_INFO_VM_DATA:
@@ -256,6 +265,9 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct 
imsg *imsg)
                if ((vm = vm_getbyid(vir.vir_info.vir_id)) != NULL) {
                        (void)strlcpy(vir.vir_ttyname, vm->vm_ttyname,
                            sizeof(vir.vir_ttyname));
+                       /* get the user id who started the vm */
+                       vir.vir_uid = vm->vm_uid;
+                       vir.vir_gid = vm->vm_params.vmc_gid;
                }
                if (proc_compose_imsg(ps, PROC_CONTROL, -1, imsg->hdr.type,
                    imsg->hdr.peerid, -1, &vir, sizeof(vir)) == -1) {
@@ -280,6 +292,9 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct 
imsg *imsg)
                                    
vm->vm_params.vmc_params.vcp_memranges[0].vmr_size;
                                vir.vir_info.vir_ncpus =
                                    vm->vm_params.vmc_params.vcp_ncpus;
+                               /* get the configured user id for this vm */
+                               vir.vir_uid = vm->vm_params.vmc_uid;
+                               vir.vir_gid = vm->vm_params.vmc_gid;
                                if (proc_compose_imsg(ps, PROC_CONTROL, -1,
                                    IMSG_VMDOP_GET_INFO_VM_DATA,
                                    imsg->hdr.peerid, -1, &vir,
@@ -496,8 +511,11 @@ vmd_configure(void)
         * tty - for openpty.
         * proc - run kill to terminate its children safely.
         * sendfd - for disks, interfaces and other fds.
+        * getpw - lookup user or group id by name.
+        * chown, fattr - change tty ownership
         */
-       if (pledge("stdio rpath wpath proc tty sendfd", NULL) == -1)
+       if (pledge("stdio rpath wpath proc tty sendfd getpw"
+           " chown fattr", NULL) == -1)
                fatal("pledge");
 
        if (parse_config(env->vmd_conffile) == -1) {
@@ -529,7 +547,7 @@ vmd_configure(void)
                            vm->vm_params.vmc_params.vcp_name);
                        continue;
                }
-               if (config_setvm(&env->vmd_ps, vm, -1) == -1)
+               if (config_setvm(&env->vmd_ps, vm, -1, 0) == -1)
                        return (-1);
        }
 
@@ -595,7 +613,7 @@ vmd_reload(unsigned int reset, const char *filename)
                                            vm->vm_params.vmc_params.vcp_name);
                                        continue;
                                }
-                               if (config_setvm(&env->vmd_ps, vm, -1) == -1)
+                               if (config_setvm(&env->vmd_ps, vm, -1, 0) == -1)
                                        return;
                        } else {
                                log_debug("%s: not creating vm \"%s\": "
@@ -712,6 +730,7 @@ vm_stop(struct vmd_vm *vm, int keeptty)
                close(vm->vm_kernel);
                vm->vm_kernel = -1;
        }
+       vm->vm_uid = 0;
        if (!keeptty)
                vm_closetty(vm);
 }
@@ -729,7 +748,7 @@ vm_remove(struct vmd_vm *vm)
 
 int
 vm_register(struct privsep *ps, struct vmop_create_params *vmc,
-    struct vmd_vm **ret_vm, uint32_t id)
+    struct vmd_vm **ret_vm, uint32_t id, uid_t uid)
 {
        struct vmd_vm           *vm = NULL;
        struct vm_create_params *vcp = &vmc->vmc_params;
@@ -739,11 +758,23 @@ vm_register(struct privsep *ps, struct vmop_create_params 
*vmc,
        *ret_vm = NULL;
 
        if ((vm = vm_getbyname(vcp->vcp_name)) != NULL) {
+               if (vm_checkperm(vm, uid) != 0 || vmc->vmc_flags != 0) {
+                       errno = EPERM;
+                       goto fail;
+               }
                *ret_vm = vm;
                errno = EALREADY;
                goto fail;
        }
 
+       /*
+        * non-root users can only start existing VMs
+        * XXX there could be a mechanism to allow overwriting some options
+        */
+       if (vm_checkperm(NULL, uid) != 0) {
+               errno = EPERM;
+               goto fail;
+       }
        if (vmc->vmc_flags == 0) {
                errno = ENOENT;
                goto fail;
@@ -797,9 +828,45 @@ vm_register(struct privsep *ps, struct vmop_create_params 
*vmc,
 }
 
 int
+vm_checkperm(struct vmd_vm *vm, uid_t uid)
+{
+       struct group    *gr;
+       struct passwd   *pw;
+       char            **grmem;
+
+       /* root has no restrictions */
+       if (uid == 0)
+               return (0);
+
+       if (vm == NULL)
+               return (-1);
+
+       /* check supplementary groups */
+       if (vm->vm_params.vmc_gid != -1 &&
+           (pw = getpwuid(uid)) != NULL &&
+           (gr = getgrgid(vm->vm_params.vmc_gid)) != NULL) {
+               for (grmem = gr->gr_mem; *grmem; grmem++)
+                       if (strcmp(*grmem, pw->pw_name) == 0)
+                               return (0);
+       }
+
+       /* check user */
+       if ((vm->vm_running && vm->vm_uid == uid) ||
+           (!vm->vm_running && vm->vm_params.vmc_uid == uid))
+               return (0);
+
+       return (-1);
+}
+
+int
 vm_opentty(struct vmd_vm *vm)
 {
        struct ptmget            ptm;
+       struct stat              st;
+       struct group            *gr;
+       uid_t                    uid;
+       gid_t                    gid;
+       mode_t                   mode;
 
        /*
         * Open tty with pre-opened PTM fd
@@ -812,6 +879,54 @@ vm_opentty(struct vmd_vm *vm)
        if ((vm->vm_ttyname = strdup(ptm.sn)) == NULL)
                goto fail;
 
+       uid = vm->vm_uid;
+       gid = vm->vm_params.vmc_gid;
+
+       if (vm->vm_params.vmc_gid != -1) {
+               mode = 0660;
+       } else if ((gr = getgrnam("tty")) != NULL) {
+               gid = gr->gr_gid;
+               mode = 0620;
+       } else {
+               mode = 0600;
+               gid = 0;
+       }
+
+       log_debug("%s: vm %s tty %s uid %d gid %d mode %o",
+           __func__, vm->vm_params.vmc_params.vcp_name,
+           vm->vm_ttyname, uid, gid, mode);
+
+       /*
+        * Change ownership and mode of the tty as required.
+        * Loosely based on the implementation of sshpty.c
+        */
+       if (stat(vm->vm_ttyname, &st) == -1)
+               goto fail;
+
+       if (st.st_uid != uid || st.st_gid != gid) {
+               if (chown(vm->vm_ttyname, uid, gid) == -1) {
+                       log_warn("chown %s %d %d failed, uid %d",
+                           vm->vm_ttyname, uid, gid, getuid());
+
+                       /* Ignore failure on read-only filesystems */
+                       if (!((errno == EROFS) &&
+                           (st.st_uid == uid || st.st_uid == 0)))
+                               goto fail;
+               }
+       }
+
+       if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
+               if (chmod(vm->vm_ttyname, mode) == -1) {
+                       log_warn("chmod %s %o failed, uid %d",
+                           vm->vm_ttyname, mode, getuid());
+
+                       /* Ignore failure on read-only filesystems */
+                       if (!((errno == EROFS) &&
+                           (st.st_uid == uid || st.st_uid == 0)))
+                               goto fail;
+               }
+       }
+
        return (0);
  fail:
        vm_closetty(vm);
@@ -822,6 +937,11 @@ void
 vm_closetty(struct vmd_vm *vm)
 {
        if (vm->vm_tty != -1) {
+               /* Release and close the tty */
+               if (fchown(vm->vm_tty, 0, 0) == -1)
+                       log_warn("chown %s 0 0 failed", vm->vm_ttyname);
+               if (fchmod(vm->vm_tty, 0666) == -1)
+                       log_warn("chmod %s 0666 failed", vm->vm_ttyname);
                close(vm->vm_tty);
                vm->vm_tty = -1;
        }
diff --git usr.sbin/vmd/vmd.h usr.sbin/vmd/vmd.h
index 26d345c..af31349 100644
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -87,11 +87,14 @@ struct vmop_result {
 struct vmop_info_result {
        struct vm_info_result    vir_info;
        char                     vir_ttyname[VM_TTYNAME_MAX];
+       uid_t                    vir_uid;
+       int64_t                  vir_gid;
 };
 
 struct vmop_id {
        uint32_t                 vid_id;
        char                     vid_name[VMM_MAX_NAME_LEN];
+       uid_t                    vid_uid;
 };
 
 struct vmop_ifreq {
@@ -113,6 +116,8 @@ struct vmop_create_params {
        char                     vmc_ifnames[VMM_MAX_NICS_PER_VM][IF_NAMESIZE];
        char                     vmc_ifswitch[VMM_MAX_NICS_PER_VM][VM_NAME_MAX];
        char                     vmc_ifgroup[VMM_MAX_NICS_PER_VM][IF_NAMESIZE];
+       uid_t                    vmc_uid;
+       int64_t                  vmc_gid;
 };
 
 struct vmboot_params {
@@ -166,6 +171,8 @@ struct vmd_vm {
        int                      vm_from_config;
        struct imsgev            vm_iev;
        int                      vm_shutdown;
+       uid_t                    vm_uid;
+
        TAILQ_ENTRY(vmd_vm)      vm_entry;
 };
 TAILQ_HEAD(vmlist, vmd_vm);
@@ -197,7 +204,8 @@ struct vmd_vm *vm_getbypid(pid_t);
 void    vm_stop(struct vmd_vm *, int);
 void    vm_remove(struct vmd_vm *);
 int     vm_register(struct privsep *, struct vmop_create_params *,
-           struct vmd_vm **, uint32_t);
+           struct vmd_vm **, uint32_t, uid_t);
+int     vm_checkperm(struct vmd_vm *, uid_t);
 int     vm_opentty(struct vmd_vm *);
 void    vm_closetty(struct vmd_vm *);
 void    switch_remove(struct vmd_switch *);
@@ -227,7 +235,7 @@ int  config_init(struct vmd *);
 void    config_purge(struct vmd *, unsigned int);
 int     config_setreset(struct vmd *, unsigned int);
 int     config_getreset(struct vmd *, struct imsg *);
-int     config_setvm(struct privsep *, struct vmd_vm *, uint32_t);
+int     config_setvm(struct privsep *, struct vmd_vm *, uint32_t, uid_t);
 int     config_getvm(struct privsep *, struct imsg *);
 int     config_getdisk(struct privsep *, struct imsg *);
 int     config_getif(struct privsep *, struct imsg *);

Reply via email to