Goto sanos source index

//
// userdb.c
//
// User database functions
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <os.h>
#include <stdlib.h>
#include <string.h>

#include <pwd.h>
#include <grp.h>

static char *passwd;
static int passwd_len;
static struct passwd *passwdtab;
static int passwd_cnt;

static char *group;
static int group_len;
static struct group *grouptab;
static int group_cnt;

static struct passwd defpasswd = {"root", "", 0, 0, "root", "/", "/bin/sh.exe"};
static char *defgrpmem[] = {"root", NULL};
static struct group defgroup = {"root", "", 0, defgrpmem};

static char *skip(char *p, int c) {
  while (*p && *p != c) p++;
  if (*p) *p++ = 0;
  return p;
}

static char *nextline(char *p) {
  while (*p && *p != '\r' && *p != '\n') p++;
  if (*p == '\r') *p++ = 0;
  if (*p) *p++ = 0;
  return p;
}

static int linecount(char *data) {
  int cnt = 0;
  char *p = data;
  while (*p) if (*p++ == '\n') cnt++;
  if (p > data && *(p - 1) != '\n') cnt++;
  return cnt;
}

static char *read_file(char *name, int *size) {
  int f;
  struct stat st;
  char *data;
  int len;

  // Determine size of file
  if (stat(name, &st) < 0) return NULL;
  len = (int) st.st_size;

  // Allocate memory for file image
  data = vmalloc(NULL, len + 1, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE, 'UDB');
  if (!data) return NULL;

  // Read file into memory
  f = open(name, 0);
  if (f < 0)  {
    vmfree(data, len + 1, MEM_RELEASE);
    return NULL;
  }

  if (read(f, data, len) != len) {
    vmfree(data, len + 1, MEM_RELEASE);
    return NULL;
  }

  data[len] = 0;
  close(f);

  *size = len;
  return data;
}

static int read_passwd() {
  char *p;
  int n;
  int passwdtab_len;

  // Read password file into memory
  passwd = read_file("/etc/passwd", &passwd_len);
  if (!passwd) return -1;

  // Calculate the number of entries in password file
  n = linecount(passwd);

  // Allocate memory for password table
  passwdtab_len = n * sizeof(struct passwd);
  passwdtab = vmalloc(NULL, passwdtab_len, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE, 'UDB');
  if (!passwdtab) return -1;

  // Build password table entries
  p = passwd;
  n = 0;
  while (*p) {
    char *next = nextline(p);

    passwdtab[n].pw_name = p;
    p = skip(p, ':');
    passwdtab[n].pw_passwd = p;
    p = skip(p, ':');
    passwdtab[n].pw_uid = atoi(p);
    p = skip(p, ':');
    passwdtab[n].pw_gid = atoi(p);
    p = skip(p, ':');
    passwdtab[n].pw_gecos = p;
    p = skip(p, ':');
    passwdtab[n].pw_dir = p;
    p = skip(p, ':');
    passwdtab[n].pw_shell = p;

    p = next;
    n++;
  }

  // Protect password memory
  if (vmprotect(passwd, passwd_len, PAGE_READONLY) < 0) return -1;
  if (vmprotect(passwdtab, passwdtab_len, PAGE_READONLY) < 0) return -1;
  passwd_cnt = n;

  return 0;
}

static int read_group() {
  char *p;
  int n, m;
  int grouptab_len;
  int commas;
  char **grmem;

  // Read user group file into memory
  group = read_file("/etc/group", &group_len);
  if (!group) return -1;

  // Calculate the number of entries in user group file
  n = linecount(group);

  // The total number of group members entries is at most the number of commas
  // plus the number of lines
  commas = 0;
  p = group;
  while (*p) if (*p++ == ',') commas++;

  // Allocate memory for user group table
  grouptab_len = n * sizeof(struct group) + (commas + n * 2) * sizeof(char *);
  grouptab = vmalloc(NULL, grouptab_len, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE, 'UDB');
  if (!grouptab) return -1;
  grmem = (char **) (grouptab + n * sizeof(struct group));

  // Build user group table entries
  p = group;
  n = 0;
  m = 0;
  while (*p) {
    char *next = nextline(p);

    grouptab[n].gr_name = p;
    p = skip(p, ':');
    grouptab[n].gr_passwd = p;
    p = skip(p, ':');
    grouptab[n].gr_gid = atoi(p);
    p = skip(p, ':');
    grouptab[n].gr_mem = &grmem[m];
    while (*p) {
      grmem[m++] = p;
      p = skip(p, ',');
    }
    grmem[m++] = NULL;

    p = next;
    n++;
  }

  // Protect group memory
  if (vmprotect(group, passwd_len, PAGE_READONLY) < 0) return -1;
  if (vmprotect(grouptab, grouptab_len, PAGE_READONLY) < 0) return -1;
  group_cnt = n;

  return 0;
}

void init_userdb() {
  read_passwd();
  if (passwd_cnt == 0) {
    passwdtab = &defpasswd;
    passwd_cnt = 1;
  }

  read_group();
  if (group_cnt == 0) {
    grouptab = &defgroup;
    group_cnt = 1;
  }
}

struct passwd *getpwnam(const char *name) {
  int i;

  for (i = 0; i < passwd_cnt; i++) {
    if (strcmp(name, passwdtab[i].pw_name) == 0)  return &passwdtab[i];
  }
  return NULL;
}

struct passwd *getpwuid(uid_t uid) {
  int i;

  for (i = 0; i < passwd_cnt; i++) {
    if (uid == passwdtab[i].pw_uid) return &passwdtab[i];
  }
  return NULL;
}

struct group *getgrnam(const char *name) {
  int i;

  for (i = 0; i < group_cnt; i++) {
    if (strcmp(name, grouptab[i].gr_name) == 0)  return &grouptab[i];
  }
  return NULL;
}

struct group *getgrgid(gid_t gid) {
  int i;

  for (i = 0; i < group_cnt; i++) {
    if (gid == grouptab[i].gr_gid) return &grouptab[i];
  }
  return NULL;
}

int initgroups(const char *user, gid_t basegid) {
  gid_t groups[NGROUPS_MAX];
  int ngroups = 0;
  int i;
  char **mem;

  groups[ngroups++] = basegid;
  for (i = 0; i < group_cnt; i++) {
    if (grouptab[i].gr_gid == basegid) continue;
    mem = grouptab[i].gr_mem;
    while (*mem && strcmp(*mem, user) != 0) mem++;
    if (*mem && ngroups < NGROUPS_MAX) groups[ngroups++] = grouptab[i].gr_gid;
  }

  return setgroups(ngroups, groups);
}