xmsh.c
author terom@yzzrt-hyper.lan
Sun, 19 Oct 2008 22:33:43 +0300
changeset 0 e88b62deaec4
permissions -rw-r--r--
initial code
0
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     1
#include <stdlib.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     2
#include <unistd.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     3
#include <sys/types.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     4
#include <stdio.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     5
#include <string.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     6
#include <err.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     7
#include <ctype.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     8
#include <pwd.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
     9
#include <errno.h>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    10
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    11
#ifndef XMSH_PATH
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    12
#error must define XMSH_PATH
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    13
#endif
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    14
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    15
#define STRINGIFY(x) XSTRINGIFY(x)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    16
#define XSTRINGIFY(x) #x
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    17
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    18
#define USERNAME_MAX 64
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    19
#define VMNAME_MAX 64
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    20
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    21
#define USERFILE_PATH_FMT (STRINGIFY(XMSH_PATH) "/users/%s")
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    22
#define USERFILE_PATH_MAX 64 + USERNAME_MAX
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    23
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    24
#define XM_PATH "/usr/sbin/xm"
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    25
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    26
/*
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    27
 * Parse command:
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    28
 *  xmsh <cmd>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    29
 *  xmsh -c <cmd>
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    30
 */
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    31
char *parse_command (int argc, char **argv) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    32
    if (argc == 2)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    33
        return argv[1];
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    34
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    35
    else if (argc == 3 && strcmp(argv[1], "-c") == 0)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    36
        return argv[2];
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    37
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    38
    // fail
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    39
    errx(EXIT_FAILURE, "usage: ssh [-t] <dom0> (list|reboot|console)");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    40
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    41
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    42
/*
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    43
 * Validate that the given command is legal
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    44
 */
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    45
void validate_command (const char *command) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    46
    // strcmp against whitelist of commands
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    47
    if (0
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    48
        ||  (strcmp(command, "list") == 0)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    49
        ||  (strcmp(command, "reboot") == 0)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    50
        ||  (strcmp(command, "console") == 0)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    51
    )
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    52
        return;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    53
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    54
    // else fail
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    55
    err(EXIT_FAILURE, "invalid command: %s", command);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    56
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    57
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    58
/*
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    59
 * Validate that the username is sane
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    60
 */
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    61
void validate_username (const char *c) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    62
    if (!(*c))
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    63
        errx(EXIT_FAILURE, "username length");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    64
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    65
    for (; *c; c++) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    66
        if (!isalpha(*c) && *c != '-') {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    67
            break;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    68
        }
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    69
    }
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    70
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    71
    if (*c)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    72
        errx(EXIT_FAILURE, "username non-alpha");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    73
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    74
}   
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    75
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    76
void validate_vmname (const char *c) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    77
    if (!(*c))
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    78
        errx(EXIT_FAILURE, "vmname length");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    79
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    80
    for (; *c; c++) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    81
        if (!isprint(*c) || isspace(*c)) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    82
            break;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    83
        }
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    84
    }
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    85
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    86
    if (*c)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    87
        errx(EXIT_FAILURE, "vmname non-print/space");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    88
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    89
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    90
/*
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    91
 * Get the real uid's username - i.e. the user who executed this file.
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    92
 */
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    93
void get_username (char buf[USERNAME_MAX]) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    94
    uid_t uid;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    95
    struct passwd *passwd;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    96
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    97
    // get the real uid
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    98
    uid = getuid();
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
    99
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   100
    // get the passwd entry
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   101
    if ((passwd = getpwuid(uid)) == NULL)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   102
        err(EXIT_FAILURE, "getpwuid");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   103
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   104
    if (passwd->pw_name == NULL)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   105
        errx(EXIT_FAILURE, "passwd->pw_name");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   106
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   107
    // fail too-long usernames
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   108
    if (strlen(passwd->pw_name) >= USERNAME_MAX)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   109
        errx(EXIT_FAILURE, "strlen(passwd->pw_name) >= USERNAME_MAX");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   110
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   111
    // copy the username to buf
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   112
    strncpy(buf, passwd->pw_name, USERNAME_MAX);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   113
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   114
    // force zero-terminate
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   115
    buf[USERNAME_MAX - 1] = '\0';
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   116
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   117
    // sanity-check username to be all-alpha
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   118
    validate_username(buf);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   119
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   120
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   121
/*
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   122
 * Get the virtual machine name for the current user
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   123
 */
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   124
void get_vmname (const char *username, char buf[VMNAME_MAX]) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   125
    // the path to the userfile
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   126
    char path[USERFILE_PATH_MAX], *nl;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   127
    FILE *fh;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   128
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   129
    // format the userfile path
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   130
    if (snprintf(path, USERFILE_PATH_MAX, USERFILE_PATH_FMT, username) >= USERFILE_PATH_MAX)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   131
        errx(EXIT_FAILURE, "USERFILE_PATH_MAX");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   132
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   133
    // open the userfile
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   134
    if ((fh = fopen(path, "r")) == NULL) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   135
        if (errno == ENOENT)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   136
            errx(EXIT_FAILURE, "no vm defined for user: %s", username);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   137
        else
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   138
            err(EXIT_FAILURE, "fopen: %s", path);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   139
    }
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   140
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   141
    // read the vmname
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   142
    if (fgets(buf, VMNAME_MAX, fh) == NULL)
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   143
        err(EXIT_FAILURE, "fgets: %s", path);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   144
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   145
    // kill the newline
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   146
    if ((nl = index(buf, '\n')))
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   147
        *nl = '\0';
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   148
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   149
    // sanity-check the vmname
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   150
    validate_vmname(buf);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   151
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   152
    // good
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   153
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   154
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   155
void __attribute__ ((noreturn)) xm_exec (const char *vmname, const char *command) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   156
    const char *env[] = { NULL };
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   157
    
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   158
    // setuid to root
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   159
    if (setuid(0))
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   160
        err(EXIT_FAILURE, "setuid: 0");
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   161
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   162
    // exec
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   163
    execle(XM_PATH, "xm", command, vmname, NULL, env);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   164
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   165
    // if we're still here, an error has occured
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   166
    err(EXIT_FAILURE, "%s: %s %s", XM_PATH, command, vmname);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   167
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   168
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   169
int main (int argc, char **argv) {
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   170
    char username[USERNAME_MAX], vmname[VMNAME_MAX], *command;
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   171
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   172
    // get command
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   173
    command = parse_command(argc, argv);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   174
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   175
    // get username
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   176
    get_username(username);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   177
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   178
    // get vmname
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   179
    get_vmname(username, vmname);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   180
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   181
    // execute xm
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   182
    xm_exec(vmname, command);
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   183
}
e88b62deaec4 initial code
terom@yzzrt-hyper.lan
parents:
diff changeset
   184