ntfs-3g/ntfsprogs/ntfsusermap.c

1133 lines
26 KiB
C

/*
* Windows to Linux user mapping for ntfs-3g
*
*
* Copyright (c) 2007-2016 Jean-Pierre Andre
*
* A quick'n dirty program scanning owners of files in
* "c:\Documents and Settings" (and "c:\Users")
* and asking user to map them to Linux accounts
*
* History
*
* Sep 2007
* - first version, limited to Win32
*
* Oct 2007
* - ported to Linux (rewritten would be more correct)
*
* Nov 2007 Version 1.0.0
* - added more defaults
*
* Nov 2007 Version 1.0.1
* - avoided examining files whose name begin with a '$'
*
* Jan 2008 Version 1.0.2
* - moved user mapping file to directory .NTFS-3G (hidden for Linux)
* - fixed an error case in Windows version
*
* Nov 2008 Version 1.1.0
* - fixed recursions for account in Linux version
* - searched owner in c:\Users (standard location for Vista)
*
* May 2009 Version 1.1.1
* - reordered mapping records to limit usage of same SID for user and group
* - fixed decoding SIDs on 64-bit systems
* - fixed a pointer to dynamic data in mapping tables
* - fixed default mapping on Windows
* - fixed bug for renaming UserMapping on Windows
*
* May 2009 Version 1.1.2
* - avoided selecting DOS names on Linux
*
* Nov 2009 Version 1.1.3
* - silenced compiler warnings for unused parameters
*
* Jan 2010 Version 1.1.4
* - fixed compilation problems for Mac OSX (Erik Larsson)
*
* Apr 2014 Version 1.1.5
* - displayed the parent directory of selected files
*
* May 2014 Version 1.1.6
* - fixed a wrong function header
*
* Mar 2016 Version 1.2.0
* - reorganized to rely on libntfs-3g even on Windows
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* General parameters which may have to be adapted to needs
*/
#define USERMAPVERSION "1.2.0"
#define MAPDIR ".NTFS-3G"
#define MAPFILE "UserMapping"
#define MAXATTRSZ 2048
#define MAXSIDSZ 80
#define MAXNAMESZ 256
#define OWNERS1 "Documents and Settings"
#define OWNERS2 "Users"
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include "types.h"
#include "endians.h"
#include "support.h"
#include "layout.h"
#include "param.h"
#include "ntfstime.h"
#include "device_io.h"
#include "device.h"
#include "logging.h"
#include "runlist.h"
#include "mft.h"
#include "inode.h"
#include "attrib.h"
#include "bitmap.h"
#include "index.h"
#include "volume.h"
#include "unistr.h"
#include "mst.h"
#include "security.h"
#include "utils.h"
#include "misc.h"
#ifdef HAVE_WINDOWS_H
/*
* Including <windows.h> leads to numerous conflicts with layout.h
* so define a few needed Windows calls unrelated to ntfs-3g
*/
BOOL WINAPI LookupAccountNameA(const char*, const char*, void*,
u32*, char*, u32*, s32*);
BOOL WINAPI GetUserNameA(char*, u32*);
#endif
#ifdef HAVE_WINDOWS_H
#define DIRSEP "\\"
#else
#define DIRSEP "/"
#endif
#ifdef HAVE_WINDOWS_H
#define BANNER "Generated by ntfsusermap for Windows, v " USERMAPVERSION
#else
#define BANNER "Generated by ntfsusermap for Linux, v " USERMAPVERSION
#endif
typedef enum { DENIED, AGREED } boolean;
enum STATES { STATE_USERS, STATE_HOMES, STATE_BASE } ;
struct CALLBACK {
const char *accname;
const char *dir;
int levels;
enum STATES docset;
} ;
typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname,
int length, int type, long long pos, unsigned long long mft_ref,
unsigned int dt_type);
struct USERMAPPING {
struct USERMAPPING *next;
const char *uidstr;
const char *gidstr;
const char *sidstr;
const unsigned char *sid;
const char *login;
boolean defined;
};
struct USERMAPPING *firstmapping;
struct USERMAPPING *lastmapping;
#ifdef HAVE_WINDOWS_H
char *currentwinname;
char *currentdomain;
unsigned char *currentsid;
#endif
void *ntfs_handle;
void *ntfs_context = (void*)NULL;
/*
* Open and close a volume in read-only mode
* assuming a single volume needs to be opened at any time
*/
static boolean open_volume(const char *volume)
{
boolean ok;
ok = DENIED;
if (!ntfs_context) {
ntfs_context = ntfs_initialize_file_security(volume,
NTFS_MNT_RDONLY);
if (ntfs_context) {
fprintf(stderr,"\"%s\" opened\n",volume);
ok = AGREED;
} else {
fprintf(stderr,"Could not open \"%s\"\n",volume);
#ifdef HAVE_WINDOWS_H
if (errno == EACCES)
fprintf(stderr,"Make sure you have"
" Administrator rights\n");
#else
fprintf(stderr,"Make sure \"%s\" is not mounted\n",
volume);
#endif
}
} else
fprintf(stderr,"A volume is already open\n");
return (ok);
}
static boolean close_volume(const char *volume)
{
boolean r;
r = ntfs_leave_file_security(ntfs_context) ? AGREED : DENIED;
if (r)
fprintf(stderr,"\"%s\" closed\n",volume);
else
fprintf(stderr,"Could not close \"%s\"\n",volume);
ntfs_context = (void*)NULL;
return (r);
}
/*
* A poor man's conversion of Unicode to UTF8
* We are assuming outputs to terminal expect UTF8
*/
static void to_utf8(char *dst, const char *src, unsigned int cnt)
{
unsigned int ch;
unsigned int i;
for (i=0; i<cnt; i++) {
ch = *src++ & 255;
ch += (*src++ & 255) << 8;
if (ch < 0x80)
*dst++ = ch;
else
if (ch < 0x1000) {
*dst++ = 0xc0 + (ch >> 6);
*dst++ = 0x80 + (ch & 63);
} else {
*dst++ = 0xe0 + (ch >> 12);
*dst++ = 0x80 + ((ch >> 6) & 63);
*dst++ = 0x80 + (ch & 63);
}
}
*dst = 0;
}
static int utf8_size(const char *src, unsigned int cnt)
{
unsigned int ch;
unsigned int i;
int size;
size = 0;
for (i=0; i<cnt; i++) {
ch = *src++ & 255;
ch += (*src++ & 255) << 8;
if (ch < 0x80)
size++;
else
if (ch < 0x1000)
size += 2;
else
size += 3;
}
return (size);
}
static void welcome(void)
{
printf("\nThis tool will help you to build a mapping of"
" Windows users\n");
printf("to Linux users.\n");
printf("Be prepared to give Linux user id (uid) and group id (gid)\n");
printf("for owners of files which will be selected.\n");
}
static unsigned int get2l(const unsigned char *attr, int p)
{
int i;
unsigned int v;
v = 0;
for (i = 0; i < 2; i++)
v += (attr[p + i] & 255) << (8 * i);
return (v);
}
static unsigned long get4l(const unsigned char *attr, int p)
{
int i;
unsigned long v;
v = 0;
for (i = 0; i < 4; i++)
v += (attr[p + i] & 255L) << (8 * i);
return (v);
}
static unsigned long long get6h(const unsigned char *attr, int p)
{
int i;
unsigned long long v;
v = 0;
for (i = 0; i < 6; i++)
v = (v << 8) + (attr[p + i] & 255L);
return (v);
}
static char *decodesid(const unsigned char *sid)
{
char *str;
int i;
unsigned long long auth;
unsigned long subauth;
str = (char *)malloc(MAXSIDSZ);
if (str) {
strcpy(str, "S");
/* revision */
sprintf(&str[strlen(str)], "-%d", sid[0]);
/* main authority */
auth = get6h(sid, 2);
#ifdef HAVE_WINDOWS_H
sprintf(&str[strlen(str)], "-%I64u", auth);
#else
sprintf(&str[strlen(str)], "-%llu", auth);
#endif
for (i = 0; (i < 8) && (i < sid[1]); i++) {
/* sub-authority */
subauth = get4l(sid, 8 + 4 * i);
sprintf(&str[strlen(str)], "-%lu", subauth);
}
}
return (str);
}
/*
* Test whether a generic group (S-1-5-21- ... -513)
*/
static boolean isgenericgroup(const char *sid)
{
boolean yes;
yes = !strncmp(sid,"S-1-5-21-",9)
&& !strcmp(strrchr(sid,'-'),"-513");
return (yes);
}
static unsigned char *makegroupsid(const unsigned char *sid)
{
static unsigned char groupsid[MAXSIDSZ];
int size;
size = 8 + 4*sid[1];
memcpy(groupsid, sid, size);
/* replace last level by 513 */
groupsid[size - 4] = 1;
groupsid[size - 3] = 2;
groupsid[size - 2] = 0;
groupsid[size - 1] = 0;
return (groupsid);
}
static void askmapping(const char *accname, const char *filename,
const char *dir, const unsigned char *sid, int type,
struct USERMAPPING *mapping, char *sidstr)
{
char buf[81];
char *idstr;
char *login;
int sidsz;
boolean reject;
char *p;
do {
reject = DENIED;
printf("\n");
if (accname)
printf("Under Windows login \"%s\"\n", accname);
if (dir) {
#ifdef HAVE_WINDOWS_H
char *wdir;
wdir = strdup(dir);
if (wdir) {
for (p=wdir; *p; p++)
if (*p == '/')
*p = '\\';
printf(" in directory \"%s\"\n",wdir);
free(wdir);
}
#else
printf(" in directory \"%s\"\n",dir);
#endif
}
printf(" file \"%s\" has no mapped %s\n",
filename,(type ? "group" : "owner"));
printf("By which Linux login should this file be owned ?\n");
printf("Enter %s of login, or just press \"enter\" if"
" this file\n", (type ? "gid" : "uid"));
printf("does not belong to a user, or you do not know"
" to whom\n");
printf("\n");
if (type)
printf("Group : ");
else
printf("User : ");
p = fgets(buf, 80, stdin);
if (p && p[0] && (p[strlen(p) - 1] == '\n'))
p[strlen(p) - 1] = '\0';
if (p && p[0]
&& ((p[0] == '0') || !strcmp(p, "root"))) {
printf("Please do not map users to root\n");
printf("Administrators will be mapped automatically\n");
reject = AGREED;
}
if (reject)
printf("Please retry\n");
} while (reject);
if (!mapping) {
mapping =
(struct USERMAPPING *)
malloc(sizeof(struct USERMAPPING));
mapping->next = (struct USERMAPPING *)NULL;
mapping->defined = DENIED;
if (lastmapping)
lastmapping->next = mapping;
else
firstmapping = mapping;
lastmapping = mapping;
}
if (mapping) {
if (p && p[0]) {
idstr = (char *)malloc(strlen(p) + 1);
if (idstr) {
strcpy(idstr, p);
if (type) {
mapping->uidstr = "";
mapping->gidstr = idstr;
} else {
mapping->uidstr = idstr;
mapping->gidstr = idstr;
}
mapping->defined = AGREED;
}
}
mapping->sidstr = sidstr;
if (accname) {
login = (char*)malloc(strlen(accname) + 1);
if (login)
strcpy(login,accname);
mapping->login = login;
} else
mapping->login = (char*)NULL;
sidsz = 8 + sid[1]*4;
p = (char*)malloc(sidsz);
if (p) {
memcpy(p, sid, sidsz);
}
mapping->sid = (unsigned char*)p;
}
}
static void domapping(const char *accname, const char *filename,
const char *dir, const unsigned char *sid, int type)
{
char *sidstr;
struct USERMAPPING *mapping;
if ((get6h(sid, 2) == 5) && (get4l(sid, 8) == 21)) {
sidstr = decodesid(sid);
mapping = firstmapping;
while (mapping && strcmp(mapping->sidstr, sidstr))
mapping = mapping->next;
if (mapping
&& (mapping->defined
|| !accname
|| !strcmp(mapping->login, accname)))
free(sidstr); /* decision already known */
else {
askmapping(accname, filename, dir, sid, type,
mapping, sidstr);
}
}
}
static void listaclusers(const char *accname, const unsigned char *attr,
int off)
{
int i;
int cnt;
int x;
cnt = get2l(attr, off + 4);
x = 8;
for (i = 0; i < cnt; i++) {
domapping(accname, (char *)NULL, (char*)NULL,
&attr[off + x + 8], 2);
x += get2l(attr, off + x + 2);
}
}
static void account(const char *accname, const char *dir,
const char *name, int type)
{
unsigned char attr[MAXATTRSZ];
u32 attrsz;
char *fullname;
fullname = (char *)malloc(strlen(dir) + strlen(name) + 2);
if (fullname) {
strcpy(fullname, dir);
strcat(fullname, "/");
strcat(fullname, name);
if (ntfs_get_file_security(ntfs_context,
fullname, OWNER_SECURITY_INFORMATION,
(char*)attr, MAXATTRSZ, &attrsz)) {
domapping(accname, name, dir, &attr[20], 0);
attrsz = 0;
if (ntfs_get_file_security(ntfs_context,
fullname, GROUP_SECURITY_INFORMATION,
(char*)attr, MAXATTRSZ, &attrsz))
domapping(accname, name, dir, &attr[20], 1);
else
printf(" No group SID\n");
attrsz = 0;
if (ntfs_get_file_security(ntfs_context,
fullname, DACL_SECURITY_INFORMATION,
(char*)attr, MAXATTRSZ, &attrsz)) {
if (type == 0)
listaclusers(accname, attr, 20);
} else
printf(" No discretionary access control"
" list for %s !\n", dir);
}
free(fullname);
}
}
/*
* recursive search of file owners and groups in a directory
*/
static boolean recurse(const char *accname, const char *dir,
int levels, enum STATES docset);
static int callback(void *ctx, const ntfschar *ntfsname,
const int length, const int type,
const s64 pos __attribute__((unused)),
const MFT_REF mft_ref __attribute__((unused)),
const unsigned int dt_type __attribute__((unused)))
{
struct CALLBACK *context;
char *fullname;
char *accname;
char *name;
context = (struct CALLBACK*)ctx;
fullname = (char *)malloc(strlen(context->dir)
+ utf8_size((const char*)ntfsname, length) + 2);
if (fullname) {
/* No "\\" when interfacing libntfs-3g */
if (strcmp(context->dir,"/")) {
strcpy(fullname, context->dir);
strcat(fullname, "/");
} else
strcpy(fullname,"/");
/* Unicode to ascii conversion by a lazy man */
name = &fullname[strlen(fullname)];
to_utf8(name, (const char*)ntfsname, length);
/* ignore special files and DOS names */
if ((type != 2)
&& strcmp(name,".")
&& strcmp(name,"..")
&& (name[0] != '$')) {
switch (context->docset) {
case STATE_USERS :
/*
* only "Documents and Settings"
* or "Users"
*/
if (!strcmp(name,OWNERS1)
|| !strcmp(name,OWNERS2)) {
recurse((char*)NULL, fullname, 2,
STATE_HOMES);
}
break;
/*
* within "Documents and Settings"
* or "Users"
*/
case STATE_HOMES :
accname = (char*)malloc(strlen(name) + 1);
if (accname) {
strcpy(accname, name);
if (context->levels > 0)
recurse(name, fullname,
context->levels - 1,
STATE_BASE);
}
break;
/*
* not related to "Documents and
* Settings" or "Users"
*/
case STATE_BASE :
account(context->accname, context->dir,
name, 1);
if (context->levels > 0)
recurse(context->accname, fullname,
context->levels - 1,
STATE_BASE);
break;
}
}
free(fullname);
}
/* check expected return value */
return (0);
}
static boolean recurse(const char *accname, const char *dir,
int levels, enum STATES docset)
{
struct CALLBACK context;
boolean err;
err = DENIED;
context.dir = dir;
context.accname = accname;
context.levels = levels;
context.docset = docset;
ntfs_read_directory(ntfs_context,dir,callback,&context);
return (!err);
}
/*
* Search directory "Documents and Settings" for user accounts
*/
static boolean getusers(const char *dir, int levels)
{
boolean err;
struct CALLBACK context;
printf("* Search for \"" OWNERS1 "\" and \"" OWNERS2 "\"\n");
err = DENIED;
context.dir = dir;
context.accname = (const char*)NULL;
context.levels = levels;
context.docset = STATE_USERS;
ntfs_read_directory(ntfs_context,dir,callback,&context);
printf("* Search for other directories %s\n",dir);
context.docset = STATE_BASE;
ntfs_read_directory(ntfs_context,dir,callback,&context);
return (!err);
}
#ifdef HAVE_WINDOWS_H
/*
* Get the current login name (Win32 only)
*/
static void loginname(boolean silent)
{
char *winname;
char *domain;
unsigned char *sid;
u32 namesz;
u32 sidsz;
u32 domainsz;
s32 nametype;
boolean ok;
int r;
ok = FALSE;
winname = (char*)malloc(MAXNAMESZ);
domain = (char*)malloc(MAXNAMESZ);
sid = (char*)malloc(MAXSIDSZ);
namesz = MAXNAMESZ;
domainsz = MAXNAMESZ;
sidsz = MAXSIDSZ;
if (winname
&& domain
&& sid
&& GetUserNameA(winname,&namesz)) {
winname[namesz] = '\0';
if (!silent)
printf("Your current user name is %s\n",winname);
nametype = 1;
r = LookupAccountNameA((char*)NULL,winname,sid,&sidsz,
domain,&domainsz,&nametype);
if (r) {
domain[domainsz] = '\0';
if (!silent)
printf("Your account domain is %s\n",domain);
ok = AGREED;
}
}
if (ok) {
currentwinname = winname;
currentdomain = domain;
currentsid = sid;
} else {
currentwinname = (char*)NULL;
currentdomain = (char*)NULL;
currentsid = (unsigned char*)NULL;
}
}
/*
* Minimal output on stdout
*/
static boolean minimal(unsigned char *sid)
{
const unsigned char *groupsid;
boolean ok;
ok = DENIED;
if (sid) {
groupsid = makegroupsid(sid);
printf("# %s\n",BANNER);
printf("# For Windows account \"%s\" in domain \"%s\"\n",
currentwinname, currentdomain);
printf("# Replace \"user\" and \"group\" hereafter by"
" matching Linux login\n");
printf("user::%s\n",decodesid(sid));
printf(":group:%s\n",decodesid(groupsid));
ok = AGREED;
}
return (ok);
}
#endif
/*
* Create a user mapping file
*
* From now on, partitions which were opened through ntfs-3g
* are closed, and we use the system drivers to create the file.
* On Windows, we can write on a partition which was analyzed.
*/
static boolean outputmap(const char *volume, const char *dir)
{
char buf[256];
int fn;
char *fullname;
char *backup;
struct USERMAPPING *mapping;
boolean done;
boolean err;
boolean undecided;
struct stat st;
int s;
done = DENIED;
fullname = (char *)malloc(strlen(MAPFILE) + 1
+ strlen(volume) + 1
+ (dir ? strlen(dir) + 1 : 0));
if (fullname) {
#ifdef HAVE_WINDOWS_H
strcpy(fullname, volume);
if (dir && dir[0]) {
strcat(fullname, DIRSEP);
strcat(fullname,dir);
}
/* build directory, if not present */
if (stat(fullname,&st) && (errno == ENOENT)) {
printf("* Creating directory %s\n", fullname);
mkdir(fullname);
}
strcat(fullname, DIRSEP);
strcat(fullname, MAPFILE);
printf("\n");
#else
strcpy(fullname, MAPFILE);
printf("\n");
#endif
s = stat(fullname,&st);
if (!s) {
backup = (char*)malloc(strlen(fullname + 5));
strcpy(backup,fullname);
strcat(backup,".bak");
#ifdef HAVE_WINDOWS_H
unlink(backup);
#endif
if (rename(fullname,backup))
printf("* Old mapping file moved to %s\n",
backup);
}
printf("* Creating file %s\n", fullname);
err = DENIED;
#ifdef HAVE_WINDOWS_H
fn = open(fullname,O_CREAT + O_TRUNC + O_WRONLY + O_BINARY,
S_IREAD + S_IWRITE);
#else
fn = open(fullname,O_CREAT + O_TRUNC + O_WRONLY,
S_IREAD + S_IWRITE);
#endif
if (fn > 0) {
sprintf(buf,"# %s\n",BANNER);
if (!write(fn,buf,strlen(buf)))
err = AGREED;
printf("%s",buf);
undecided = DENIED;
/* records for owner only or group only */
for (mapping = firstmapping; mapping && !err;
mapping = mapping->next)
if (mapping->defined
&& (!mapping->uidstr[0]
|| !mapping->gidstr[0])) {
sprintf(buf,"%s:%s:%s\n",
mapping->uidstr,
mapping->gidstr,
mapping->sidstr);
if (!write(fn,buf,strlen(buf)))
err = AGREED;
printf("%s",buf);
} else
undecided = AGREED;
/* records for both owner and group */
for (mapping = firstmapping; mapping && !err;
mapping = mapping->next)
if (mapping->defined
&& mapping->uidstr[0]
&& mapping->gidstr[0]) {
sprintf(buf,"%s:%s:%s\n",
mapping->uidstr,
mapping->gidstr,
mapping->sidstr);
if (!write(fn,buf,strlen(buf)))
err = AGREED;
printf("%s",buf);
} else
undecided = AGREED;
done = !err;
close(fn);
if (undecided) {
printf("Undecided :\n");
for (mapping = firstmapping; mapping;
mapping = mapping->next)
if (!mapping->defined) {
printf(" %s\n",
mapping->sidstr);
}
}
#ifndef HAVE_WINDOWS_H
printf("\n* You will have to move the file \""
MAPFILE "\"\n");
printf(" to directory \"" MAPDIR "\" after"
" mounting\n");
#endif
}
}
if (!done)
fprintf(stderr, "* Could not create mapping file \"%s\"\n",
fullname);
return (done);
}
static boolean sanitize(void)
{
char buf[81];
boolean ok;
int ownercnt;
int groupcnt;
struct USERMAPPING *mapping;
struct USERMAPPING *firstowner;
struct USERMAPPING *genericgroup;
struct USERMAPPING *group;
char *sidstr;
/* count owners and groups */
/* and find first user, and a generic group */
ownercnt = 0;
groupcnt = 0;
firstowner = (struct USERMAPPING*)NULL;
genericgroup = (struct USERMAPPING*)NULL;
for (mapping=firstmapping; mapping; mapping=mapping->next) {
if (mapping->defined && mapping->uidstr[0]) {
if (!ownercnt)
firstowner = mapping;
ownercnt++;
}
if (mapping->defined && mapping->gidstr[0]
&& !mapping->uidstr[0]) {
groupcnt++;
}
if (!mapping->defined && isgenericgroup(mapping->sidstr)) {
genericgroup = mapping;
}
}
#ifdef HAVE_WINDOWS_H
/* no user defined, on Windows, suggest a mapping */
/* based on account currently used */
if (!ownercnt && currentwinname && currentsid) {
char *owner;
char *p;
printf("\nYou have defined no file owner,\n");
printf(" please enter the Linux login which should"
" be mapped\n");
printf(" to account you are currently using\n");
printf(" Linux user ? ");
p = fgets(buf, 80, stdin);
if (p && p[0] && (p[strlen(p) - 1] == '\n'))
p[strlen(p) - 1] = '\0';
if (p && p[0]) {
firstowner = (struct USERMAPPING*)malloc(
sizeof(struct USERMAPPING));
owner = (char*)malloc(strlen(p) + 1);
if (firstowner && owner) {
strcpy(owner, p);
firstowner->next = firstmapping;
firstowner->uidstr = owner;
firstowner->gidstr = "";
firstowner->sidstr = decodesid(currentsid);
firstowner->sid = currentsid;
firstmapping = firstowner;
ownercnt++;
/* prefer a generic group with the same
* authorities */
for (mapping=firstmapping; mapping;
mapping=mapping->next)
if (!mapping->defined
&& isgenericgroup(mapping->sidstr)
&& !memcmp(firstowner->sidstr,
mapping->sidstr,
strlen(mapping
->sidstr)-3))
genericgroup = mapping;
}
}
}
#endif
if (ownercnt) {
/*
* No group was selected, but there were a generic
* group, insist in using it, associated to the
* first user
*/
if (!groupcnt) {
printf("\nYou have defined no group,"
" this can cause problems\n");
printf("Do you accept defining a standard group ?\n");
if (!fgets(buf,80,stdin)
|| ((buf[0] != 'n')
&& (buf[0] != 'N'))) {
if (genericgroup) {
genericgroup->uidstr = "";
genericgroup->gidstr =
firstowner->uidstr;
genericgroup->defined = AGREED;
} else {
group = (struct USERMAPPING*)
malloc(sizeof(
struct USERMAPPING));
sidstr = decodesid(
makegroupsid(firstowner->sid));
if (group && sidstr) {
group->uidstr = "";
group->gidstr = firstowner->
uidstr;
group->sidstr = sidstr;
group->defined = AGREED;
group->next = firstmapping;
firstmapping = group;
}
}
}
}
ok = AGREED;
} else {
printf("\nYou have defined no user, no mapping can be built\n");
ok = DENIED;
}
return (ok);
}
static boolean checkoptions(int argc, char *argv[] __attribute__((unused)),
boolean silent __attribute__((unused)))
{
boolean err;
#ifdef HAVE_WINDOWS_H
int xarg;
const char *pvol;
if (silent) {
err = (argc != 1);
} else {
err = (argc < 2);
for (xarg=1; (xarg<argc) && !err; xarg++) {
pvol = argv[xarg];
if (pvol[0] && (pvol[1] == ':') && !pvol[2]) {
err = !(((pvol[0] >= 'A') && (pvol[0] <= 'Z'))
|| ((pvol[0] >= 'a')
&& (pvol[0] <= 'z')));
}
}
}
if (err) {
fprintf(stderr, "Usage : ntfsusermap [vol1: [vol2: ...]]\n");
fprintf(stderr, " \"voln\" are the letters of the partition"
" to share with Linux\n");
fprintf(stderr, " eg C:\n");
fprintf(stderr, " the Windows system partition should be"
" named first\n");
if (silent) {
fprintf(stderr, "When outputting to file, a minimal"
" user mapping proposal\n");
fprintf(stderr, "is written to the file, and no"
" partition should be mentioned\n");
}
}
#else
err = (argc < 2);
if (err) {
fprintf(stderr, "Usage : ntfsusermap dev1 [dev2 ...]\n");
fprintf(stderr, " \"dev.\" are the devices to share"
" with Windows\n");
fprintf(stderr, " eg /dev/sdb1\n");
fprintf(stderr, " the devices should not be mounted, and\n");
fprintf(stderr, " the Windows system partition should"
" be named first\n");
} else
if (getuid()) {
fprintf(stderr, "\nSorry, only root can start"
" ntfsusermap\n");
err = AGREED;
}
#endif
return (!err);
}
static boolean process(int argc, char *argv[])
{
boolean ok;
int xarg;
int targ;
firstmapping = (struct USERMAPPING *)NULL;
lastmapping = (struct USERMAPPING *)NULL;
ok = AGREED;
for (xarg=1; (xarg<argc) && ok; xarg++)
if (open_volume(argv[xarg])) {
printf("\n* Scanning \"%s\" (two levels)\n",argv[xarg]);
ok = getusers("/",2);
close_volume(argv[xarg]);
} else
ok = DENIED;
if (ok && sanitize()) {
targ = (argc > 2 ? 2 : 1);
if (!outputmap(argv[targ],MAPDIR)) {
printf("Trying to write file on root directory\n");
if (outputmap(argv[targ],(const char*)NULL)) {
printf("\nNote : you will have to move the"
" file to directory \"%s\" on Linux\n",
MAPDIR);
} else
ok = DENIED;
} else
ok = DENIED;
} else
ok = DENIED;
return (ok);
}
int main(int argc, char *argv[])
{
boolean ok;
boolean silent;
silent = !isatty(1);
if (!silent)
welcome();
if (checkoptions(argc, argv, silent)) {
#ifdef HAVE_WINDOWS_H
loginname(silent);
if (silent)
ok = minimal(currentsid);
else
ok = process(argc,argv);
#else
ok = process(argc,argv);
#endif
} else
ok = DENIED;
if (!ok)
exit(1);
return (0);
}