summaryrefslogtreecommitdiff
path: root/src/usermap.c (plain)
blob: 3d8ce6d36c1471a2b7770bf2ec7b984dad31b28b
1/*
2 * Windows to Linux user mapping for ntfs-3g
3 *
4 *
5 * Copyright (c) 2007-2008 Jean-Pierre Andre
6 *
7 * A quick'n dirty program scanning owners of files in
8 * "c:\Documents and Settings" (and "c:\Users")
9 * and asking user to map them to Linux accounts
10 *
11 * History
12 *
13 * Sep 2007
14 * - first version, limited to Win32
15 *
16 * Oct 2007
17 * - ported to Linux (rewritten would be more correct)
18 *
19 * Nov 2007 Version 1.0.0
20 * - added more defaults
21 *
22 * Nov 2007 Version 1.0.1
23 * - avoided examining files whose name begin with a '$'
24 *
25 * Jan 2008 Version 1.0.2
26 * - moved user mapping file to directory .NTFS-3G (hidden for Linux)
27 * - fixed an error case in Windows version
28 *
29 * Nov 2008 Version 1.1.0
30 * - fixed recursions for account in Linux version
31 * - searched owner in c:\Users (standard location for Vista)
32 *
33 * May 2009 Version 1.1.1
34 * - reordered mapping records to limit usage of same SID for user and group
35 * - fixed decoding SIDs on 64-bit systems
36 * - fixed a pointer to dynamic data in mapping tables
37 * - fixed default mapping on Windows
38 * - fixed bug for renaming UserMapping on Windows
39 *
40 * May 2009 Version 1.1.2
41 * - avoided selecting DOS names on Linux
42 *
43 * Nov 2009 Version 1.1.3
44 * - shutdown compiler warnings for unused parameters
45 *
46 * Jan 2010 Version 1.1.4
47 * - fixed compilation problems for Mac OSX (Erik Larsson)
48 */
49
50/*
51 * This program is free software; you can redistribute it and/or modify
52 * it under the terms of the GNU General Public License as published by
53 * the Free Software Foundation; either version 2 of the License, or
54 * (at your option) any later version.
55 *
56 * This program is distributed in the hope that it will be useful,
57 * but WITHOUT ANY WARRANTY; without even the implied warranty of
58 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59 * GNU General Public License for more details.
60 *
61 * You should have received a copy of the GNU General Public License
62 * along with this program (in the main directory of the NTFS-3G
63 * distribution in the file COPYING); if not, write to the Free Software
64 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
65 */
66
67/*
68 * General parameters which may have to be adapted to needs
69 */
70
71#ifdef HAVE_CONFIG_H
72#define USESTUBS 1 /* API stubs generated at link time */
73#else
74#define USESTUBS 0 /* direct calls to API, based on following definitions */
75#define ENVNTFS3G "NTFS3G"
76#define LIBFILE64 "/lib64/libntfs-3g.so.491"
77#define LIBFILE "/lib/libntfs-3g.so.491"
78#endif
79
80#define GET_FILE_SECURITY "ntfs_get_file_security"
81#define SET_FILE_SECURITY "ntfs_set_file_security"
82#define READ_DIRECTORY "ntfs_read_directory"
83#define INIT_FILE_SECURITY "ntfs_initialize_file_security"
84#define LEAVE_FILE_SECURITY "ntfs_leave_file_security"
85
86#define VERSION "1.1.4"
87#define MAPDIR ".NTFS-3G"
88#define MAPFILE "UserMapping"
89#define MAXATTRSZ 2048
90#define MAXSIDSZ 80
91#define MAXNAMESZ 256
92#define OWNERS1 "Documents and Settings"
93#define OWNERS2 "Users"
94
95/*
96 * Define WIN32 for a Windows execution
97 * may have to be adapted to compiler or something else
98 */
99
100#ifndef WIN32
101#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC)
102#define WIN32 1
103#endif
104#endif
105
106#ifdef WIN32
107#define BANNER "Generated by usermap for Windows, v " VERSION
108#else
109#define BANNER "Generated by usermap for Linux, v " VERSION
110#endif
111
112
113#include <stdio.h>
114#include <string.h>
115#include <stdlib.h>
116#include <fcntl.h>
117#include <sys/types.h>
118#include <sys/stat.h>
119#include <errno.h>
120
121/*
122 * Define the security API according to platform
123 */
124
125#ifdef WIN32
126
127#include <fcntl.h>
128#include <windows.h>
129
130#define STATIC
131
132typedef enum { DENIED, AGREED } boolean;
133
134#else
135
136#include <unistd.h>
137#include <dlfcn.h>
138
139typedef enum { DENIED, AGREED } boolean, BOOL;
140typedef unsigned int DWORD; /* must be 32 bits whatever the platform */
141typedef DWORD *LPDWORD;
142
143enum { OWNER_SECURITY_INFORMATION = 1,
144 GROUP_SECURITY_INFORMATION = 2,
145 DACL_SECURITY_INFORMATION = 4,
146 SACL_SECURITY_INFORMATION = 8
147} ;
148
149struct CALLBACK {
150 const char *accname;
151 const char *dir;
152 int levels;
153 int docset;
154} ;
155
156typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname,
157 int length, int type, long long pos, unsigned long long mft_ref,
158 unsigned int dt_type);
159
160#if USESTUBS
161
162#define STATIC static
163
164BOOL ntfs_get_file_security(void *scapi,
165 const char *path, DWORD selection,
166 char *buf, DWORD buflen, LPDWORD psize);
167BOOL ntfs_set_file_security(void *scapi,
168 const char *path, DWORD selection, const char *attr);
169BOOL ntfs_read_directory(void *scapi,
170 const char *path, dircallback callback, void *context);
171void *ntfs_initialize_file_security(const char *device,
172 int flags);
173BOOL ntfs_leave_file_security(void *scapi);
174
175#else
176
177#define STATIC
178
179BOOL (*ntfs_get_file_security)(void *scapi,
180 const char *path, DWORD selection,
181 char *buf, DWORD buflen, LPDWORD psize);
182BOOL (*ntfs_set_file_security)(void *scapi,
183 const char *path, DWORD selection, const char *attr);
184BOOL (*ntfs_read_directory)(void *scapi,
185 const char *path, dircallback callback, void *context);
186void *(*ntfs_initialize_file_security)(const char *device,
187 int flags);
188BOOL (*ntfs_leave_file_security)(void *scapi);
189
190#endif
191
192STATIC boolean open_security_api(void);
193STATIC boolean close_security_api(void);
194STATIC boolean open_volume(const char *volume);
195STATIC boolean close_volume(const char *volume);
196
197#endif
198
199struct MAPPING {
200 struct MAPPING *next;
201 const char *uidstr;
202 const char *gidstr;
203 const char *sidstr;
204 const unsigned char *sid;
205 const char *login;
206 boolean defined;
207};
208
209struct MAPPING *firstmapping;
210struct MAPPING *lastmapping;
211
212#ifdef WIN32
213char *currentwinname;
214char *currentdomain;
215unsigned char *currentsid;
216#endif
217
218#ifndef WIN32
219
220void *ntfs_handle;
221void *ntfs_context = (void*)NULL;
222
223/*
224 * Shut down compiler warnings for unused parameters
225 */
226
227static long unused(const void *p)
228{
229return ((long)p);
230}
231
232/*
233 * Open and close the security API (platform dependent)
234 */
235
236STATIC boolean open_security_api(void)
237{
238#if USESTUBS
239 return (AGREED);
240#else
241 char *error;
242 boolean err;
243 const char *libfile;
244
245 err = AGREED;
246 libfile = getenv(ENVNTFS3G);
247 if (!libfile)
248 libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE);
249 ntfs_handle = dlopen(libfile,RTLD_LAZY);
250 if (ntfs_handle) {
251 ntfs_initialize_file_security =
252 dlsym(ntfs_handle,INIT_FILE_SECURITY);
253 error = dlerror();
254 if (error)
255 fprintf(stderr," %s\n",error);
256 else {
257 ntfs_leave_file_security =
258 dlsym(ntfs_handle,LEAVE_FILE_SECURITY);
259 ntfs_get_file_security =
260 dlsym(ntfs_handle,GET_FILE_SECURITY);
261 ntfs_set_file_security =
262 dlsym(ntfs_handle,SET_FILE_SECURITY);
263 ntfs_read_directory =
264 dlsym(ntfs_handle,READ_DIRECTORY);
265 err = !ntfs_initialize_file_security
266 || !ntfs_leave_file_security
267 || !ntfs_get_file_security
268 || !ntfs_set_file_security
269 || !ntfs_read_directory;
270 if (error)
271 fprintf(stderr,"ntfs-3g API not available\n");
272 }
273 } else {
274 fprintf(stderr,"Could not open ntfs-3g library\n");
275 fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n");
276 fprintf(stderr,"to appropriate path and retry\n");
277 }
278 return (!err);
279#endif
280}
281
282STATIC boolean close_security_api(void)
283{
284#if USESTUBS
285 return (0);
286#else
287 return (!dlclose(ntfs_handle));
288#endif
289}
290
291/*
292 * Open and close a volume (platform dependent)
293 * assuming a single volume needs to be opened at any time
294 */
295
296STATIC boolean open_volume(const char *volume)
297{
298 boolean ok;
299
300 ok = DENIED;
301 if (!ntfs_context) {
302 ntfs_context = ntfs_initialize_file_security(volume,0);
303 if (ntfs_context) {
304 fprintf(stderr,"\"%s\" opened\n",volume);
305 ok = AGREED;
306 } else {
307 fprintf(stderr,"Could not open \"%s\"\n",volume);
308 fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume);
309 }
310 } else
311 fprintf(stderr,"A volume is already open\n");
312 return (ok);
313}
314
315STATIC boolean close_volume(const char *volume)
316{
317 boolean r;
318
319 r = ntfs_leave_file_security(ntfs_context);
320 if (r)
321 fprintf(stderr,"\"%s\" closed\n",volume);
322 else
323 fprintf(stderr,"Could not close \"%s\"\n",volume);
324 ntfs_context = (void*)NULL;
325 return (r);
326}
327
328/*
329 * A poor man's conversion of Unicode to UTF8
330 * We are assuming outputs to terminal expect UTF8
331 */
332
333STATIC void to_utf8(char *dst, const char *src, unsigned int cnt)
334{
335 unsigned int ch;
336 unsigned int i;
337
338 for (i=0; i<cnt; i++) {
339 ch = *src++ & 255;
340 ch += (*src++ & 255) << 8;
341 if (ch < 0x80)
342 *dst++ = ch;
343 else
344 if (ch < 0x1000) {
345 *dst++ = 0xc0 + (ch >> 6);
346 *dst++ = 0x80 + (ch & 63);
347 } else {
348 *dst++ = 0xe0 + (ch >> 12);
349 *dst++ = 0x80 + ((ch >> 6) & 63);
350 *dst++ = 0x80 + (ch & 63);
351 }
352 }
353 *dst = 0;
354}
355
356STATIC int utf8_size(const char *src, unsigned int cnt)
357{
358 unsigned int ch;
359 unsigned int i;
360 int size;
361
362 size = 0;
363 for (i=0; i<cnt; i++) {
364 ch = *src++ & 255;
365 ch += (*src++ & 255) << 8;
366 if (ch < 0x80)
367 size++;
368 else
369 if (ch < 0x1000)
370 size += 2;
371 else
372 size += 3;
373 }
374 return (size);
375}
376
377#endif
378
379
380STATIC void welcome(void)
381{
382 printf("\nThis tool will help you to build a mapping of Windows users\n");
383 printf("to Linux users.\n");
384 printf("Be prepared to give Linux user id (uid) and group id (gid)\n");
385 printf("for owners of files which will be selected.\n");
386}
387
388STATIC unsigned int get2l(const unsigned char *attr, int p)
389{
390 int i;
391 unsigned int v;
392
393 v = 0;
394 for (i = 0; i < 2; i++)
395 v += (attr[p + i] & 255) << (8 * i);
396 return (v);
397}
398
399STATIC unsigned long get4l(const unsigned char *attr, int p)
400{
401 int i;
402 unsigned long v;
403
404 v = 0;
405 for (i = 0; i < 4; i++)
406 v += (attr[p + i] & 255L) << (8 * i);
407 return (v);
408}
409
410STATIC unsigned long long get6h(const unsigned char *attr, int p)
411{
412 int i;
413 unsigned long long v;
414
415 v = 0;
416 for (i = 0; i < 6; i++)
417 v = (v << 8) + (attr[p + i] & 255L);
418 return (v);
419}
420
421STATIC char *decodesid(const unsigned char *sid)
422{
423 char *str;
424 int i;
425 unsigned long long auth;
426 unsigned long subauth;
427
428 str = (char *)malloc(MAXSIDSZ);
429 if (str) {
430 strcpy(str, "S");
431 sprintf(&str[strlen(str)], "-%d", sid[0]); /* revision */
432 auth = get6h(sid, 2);
433#ifdef WIN32
434 sprintf(&str[strlen(str)], "-%I64u", auth); /* main authority */
435#else
436 sprintf(&str[strlen(str)], "-%llu", auth); /* main authority */
437#endif
438 for (i = 0; (i < 8) && (i < sid[1]); i++) {
439 subauth = get4l(sid, 8 + 4 * i);
440 sprintf(&str[strlen(str)], "-%lu", subauth); /* sub-authority */
441 }
442 }
443 return (str);
444}
445
446/*
447 * Test whether a generic group (S-1-5-21- ... -513)
448 */
449
450STATIC boolean isgenericgroup(const char *sid)
451{
452 boolean yes;
453
454 yes = !strncmp(sid,"S-1-5-21-",9)
455 && !strcmp(strrchr(sid,'-'),"-513");
456 return (yes);
457}
458
459STATIC unsigned char *makegroupsid(const unsigned char *sid)
460{
461 static unsigned char groupsid[MAXSIDSZ];
462 int size;
463
464 size = 8 + 4*sid[1];
465 memcpy(groupsid, sid, size);
466 /* replace last level by 513 */
467 groupsid[size - 4] = 1;
468 groupsid[size - 3] = 2;
469 groupsid[size - 2] = 0;
470 groupsid[size - 1] = 0;
471 return (groupsid);
472}
473
474STATIC void domapping(const char *accname, const char *filename,
475 const unsigned char *sid, int type)
476{
477 char buf[81];
478 char *sidstr;
479 char *idstr;
480 int sidsz;
481 boolean reject;
482 struct MAPPING *mapping;
483 char *login;
484 char *p;
485
486 if ((get6h(sid, 2) == 5) && (get4l(sid, 8) == 21)) {
487 sidstr = decodesid(sid);
488 mapping = firstmapping;
489 while (mapping && strcmp(mapping->sidstr, sidstr))
490 mapping = mapping->next;
491 if (mapping
492 && (mapping->defined
493 || !accname
494 || !strcmp(mapping->login, accname)))
495 free(sidstr); /* decision already known */
496 else {
497 do {
498 reject = DENIED;
499 printf("\n");
500 if (accname)
501 printf("Under Windows login \"%s\"\n", accname);
502 printf(" file \"%s\" has no mapped %s\n",
503 filename,(type ? "group" : "owner"));
504 printf("By which Linux login should this file be owned ?\n");
505 printf("Enter %s of login, or just press \"enter\" if this file\n",
506 (type ? "gid" : "uid"));
507 printf("does not belong to a user, or you do not known to whom\n");
508 printf("\n");
509 if (type)
510 printf("Group : ");
511 else
512 printf("User : ");
513 p = fgets(buf, 80, stdin);
514 if (p && p[0] && (p[strlen(p) - 1] == '\n'))
515 p[strlen(p) - 1] = '\0';
516
517 if (p && p[0]
518 && ((p[0] == '0') || !strcmp(p, "root"))) {
519 printf("Please do not map users to root\n");
520 printf("Administrators will be mapped automatically\n");
521 reject = AGREED;
522 }
523 if (reject)
524 printf("Please retry\n");
525 } while (reject);
526 if (!mapping) {
527 mapping =
528 (struct MAPPING *)
529 malloc(sizeof(struct MAPPING));
530 mapping->next = (struct MAPPING *)NULL;
531 mapping->defined = DENIED;
532 if (lastmapping)
533 lastmapping->next = mapping;
534 else
535 firstmapping = mapping;
536 lastmapping = mapping;
537 }
538 if (mapping) {
539 if (p && p[0]) {
540 idstr = (char *)malloc(strlen(p) + 1);
541 if (idstr) {
542 strcpy(idstr, p);
543 if (type) {
544 mapping->uidstr = "";
545 mapping->gidstr = idstr;
546 } else {
547 mapping->uidstr = idstr;
548 mapping->gidstr = idstr;
549 }
550 mapping->defined = AGREED;
551 }
552 }
553 mapping->sidstr = sidstr;
554 if (accname) {
555 login = (char*)malloc(strlen(accname) + 1);
556 if (login)
557 strcpy(login,accname);
558 mapping->login = login;
559 } else
560 mapping->login = (char*)NULL;
561 sidsz = 8 + sid[1]*4;
562 p = (char*)malloc(sidsz);
563 if (p) {
564 memcpy(p, sid, sidsz);
565 }
566 mapping->sid = (unsigned char*)p;
567 }
568 }
569 }
570}
571
572STATIC void listaclusers(const char *accname, const unsigned char *attr, int off)
573{
574 int i;
575 int cnt;
576 int x;
577
578 cnt = get2l(attr, off + 4);
579 x = 8;
580 for (i = 0; i < cnt; i++) {
581 domapping(accname, (char *)NULL, &attr[off + x + 8], 2);
582 x += get2l(attr, off + x + 2);
583 }
584}
585
586#ifdef WIN32
587
588STATIC void account(const char *accname, const char *dir, const char *name, int type)
589{
590 unsigned char attr[MAXATTRSZ];
591 unsigned long attrsz;
592 char *fullname;
593 int attrib;
594
595 fullname = (char *)malloc(strlen(dir) + strlen(name) + 2);
596 if (fullname) {
597 strcpy(fullname, dir);
598 strcat(fullname, "\\");
599 strcat(fullname, name);
600 attrib = GetFileAttributes(fullname);
601 if (attrib & 0x10) { /* only directories processed */
602 if (GetFileSecurity
603 (fullname, OWNER_SECURITY_INFORMATION, attr, MAXATTRSZ,
604 &attrsz)) {
605 domapping(accname, name, &attr[20], 0);
606 attrsz = 0;
607 if (GetFileSecurity
608 (fullname, GROUP_SECURITY_INFORMATION, attr,
609 MAXATTRSZ, &attrsz))
610 domapping(accname, name, &attr[20], 1);
611 else
612 printf(" No group SID\n");
613 attrsz = 0;
614 if (GetFileSecurityA
615 (fullname, DACL_SECURITY_INFORMATION, attr,
616 MAXATTRSZ, &attrsz)) {
617 if (type == 0)
618 listaclusers(accname, attr, 20);
619 } else
620 printf
621 (" No discretionary access control list\n");
622 }
623 }
624 free(fullname);
625 }
626}
627
628#else
629
630STATIC void account(const char *accname, const char *dir, const char *name, int type)
631{
632 unsigned char attr[MAXATTRSZ];
633 DWORD attrsz;
634 char *fullname;
635
636 fullname = (char *)malloc(strlen(dir) + strlen(name) + 2);
637 if (fullname) {
638 strcpy(fullname, dir);
639 strcat(fullname, "/");
640 strcat(fullname, name);
641 if (ntfs_get_file_security(ntfs_context,
642 fullname, OWNER_SECURITY_INFORMATION,
643 (char*)attr, MAXATTRSZ, &attrsz)) {
644 domapping(accname, name, &attr[20], 0);
645 attrsz = 0;
646 if (ntfs_get_file_security(ntfs_context,
647 fullname, GROUP_SECURITY_INFORMATION,
648 (char*)attr, MAXATTRSZ, &attrsz))
649 domapping(accname, name, &attr[20], 1);
650 else
651 printf(" No group SID\n");
652 attrsz = 0;
653 if (ntfs_get_file_security(ntfs_context,
654 fullname, DACL_SECURITY_INFORMATION,
655 (char*)attr, MAXATTRSZ, &attrsz)) {
656 if (type == 0)
657 listaclusers(accname, attr, 20);
658 } else
659 printf(" No discretionary access control list for %s !\n",
660 dir);
661 }
662 free(fullname);
663 }
664}
665
666#endif
667
668
669/*
670 * recursive search of file owners and groups in a directory
671 */
672
673#ifdef WIN32
674
675STATIC boolean recurse(const char *accname, const char *dir, int levels)
676{
677 WIN32_FIND_DATA found;
678 HANDLE search;
679 char *filter;
680 char *fullname;
681 boolean err;
682
683 err = DENIED;
684 filter = (char *)malloc(strlen(dir) + 5);
685 if (filter) {
686 strcpy(filter, dir);
687 strcat(filter, "\\*.*");
688 search = FindFirstFile(filter, &found);
689 if (search != INVALID_HANDLE_VALUE) {
690 do {
691 if (found.cFileName[0] != '.') {
692 account(accname, dir, found.cFileName,1);
693 if (levels > 0) {
694 fullname =
695 (char *)malloc(strlen(dir) +
696 strlen(found.cFileName)
697 + 2);
698 if (fullname) {
699 strcpy(fullname, dir);
700 strcat(fullname, "\\");
701 strcat(fullname,
702 found.cFileName);
703 recurse(accname,
704 fullname,
705 levels - 1);
706 free(fullname);
707 }
708 }
709 }
710 } while (FindNextFile(search, &found));
711 FindClose(search);
712 }
713 free(filter);
714 } else {
715 printf("Directory %s not found\n",dir);
716 err = AGREED;
717 }
718 return (!err);
719}
720
721#else
722
723STATIC boolean recurse(const char *accname, const char *dir, int levels, int docset);
724
725STATIC int callback(struct CALLBACK *context, char *ntfsname,
726 int length, int type, long long pos, unsigned long long mft_ref,
727 unsigned int dt_type)
728{
729 char *fullname;
730 char *accname;
731 char *name;
732
733 unused((void*)&pos);
734 unused((void*)&mft_ref);
735 unused((void*)&dt_type);
736 fullname = (char *)malloc(strlen(context->dir)
737 + utf8_size(ntfsname, length) + 2);
738 if (fullname) {
739 if (strcmp(context->dir,"/")) {
740 strcpy(fullname, context->dir);
741 strcat(fullname, "/");
742 } else
743 strcpy(fullname,"/");
744 /* Unicode to ascii conversion by a lazy man */
745 name = &fullname[strlen(fullname)];
746 to_utf8(name, ntfsname, length);
747 /* ignore special files and DOS names */
748 if ((type != 2)
749 && strcmp(name,".")
750 && strcmp(name,"..")
751 && (name[0] != '$')) {
752 switch (context->docset) {
753 case 2 :
754 /*
755 * only "Documents and Settings"
756 * or "Users"
757 */
758 if (!strcmp(name,OWNERS1)
759 || !strcmp(name,OWNERS2)) {
760 recurse((char*)NULL, fullname, 2, 1);
761 }
762 break;
763 /*
764 * within "Documents and Settings"
765 * or "Users"
766 */
767 case 1 :
768 accname = (char*)malloc(strlen(name) + 1);
769 if (accname) {
770 strcpy(accname, name);
771 if (context->levels > 0)
772 recurse(name, fullname,
773 context->levels - 1, 0);
774 }
775 break;
776 /*
777 * not related to "Documents and Settings"
778 * or "Users"
779 */
780 case 0 :
781 account(context->accname, context->dir,
782 name, 1);
783 if (context->levels > 0)
784 recurse(context->accname, fullname,
785 context->levels - 1, 0);
786 break;
787 }
788 }
789 free(fullname);
790 }
791/* check expected return value */
792 return (0);
793}
794
795STATIC boolean recurse(const char *accname, const char *dir, int levels, int docset)
796{
797 struct CALLBACK context;
798 boolean err;
799
800 err = DENIED;
801 context.dir = dir;
802 context.accname = accname;
803 context.levels = levels;
804 context.docset = docset;
805 ntfs_read_directory(ntfs_context,dir,callback,&context);
806 return (!err);
807}
808#endif
809
810/*
811 * Search directory "Documents and Settings" for user accounts
812 */
813
814#ifdef WIN32
815
816STATIC boolean getusers(const char *dir, int levels)
817{
818 WIN32_FIND_DATA found;
819 HANDLE search;
820 char *filter;
821 char *fullname;
822 char *accname;
823 boolean err;
824 const char *docset;
825
826 /* first get files from "Documents and Settings" */
827 err = DENIED;
828 if (sizeof(OWNERS1) > sizeof(OWNERS2))
829 filter = (char *)malloc(strlen(dir) + strlen(OWNERS1) + 6);
830 else
831 filter = (char *)malloc(strlen(dir) + strlen(OWNERS2) + 6);
832 if (filter) {
833 docset = OWNERS1;
834 strcpy(filter, dir);
835 strcat(filter, "\\");
836 strcat(filter, docset);
837 strcat(filter, "\\*.*");
838 search = FindFirstFile(filter, &found);
839 /* if failed, retry with "Users" */
840 if (search == INVALID_HANDLE_VALUE) {
841 docset = OWNERS2;
842 strcpy(filter, dir);
843 strcat(filter, "\\");
844 strcat(filter, docset);
845 strcat(filter, "\\*.*");
846 search = FindFirstFile(filter, &found);
847 }
848 if (search != INVALID_HANDLE_VALUE) {
849 do {
850 if (found.cFileName[0] != '.') {
851 fullname =
852 (char *)malloc(strlen(dir)
853 + strlen(docset)
854 + strlen(found.cFileName) + 3);
855 accname = (char *)
856 malloc(strlen(found.cFileName) + 1);
857 if (fullname && accname) {
858 strcpy(accname,
859 found.cFileName);
860
861 strcpy(fullname, dir);
862 strcat(fullname, "\\");
863 strcat(fullname, docset);
864 strcat(fullname, "\\");
865 strcat(fullname,
866 found.cFileName);
867 recurse(accname, fullname, 2);
868
869 free(fullname);
870 }
871 }
872 } while (FindNextFile(search, &found));
873 FindClose(search);
874 } else {
875 printf("No subdirectory found in %s\\%s\n",dir,docset);
876 }
877 /* now search in other directories */
878 strcpy(filter, dir);
879 strcat(filter, "\\*.*");
880 search = FindFirstFile(filter, &found);
881 if (search != INVALID_HANDLE_VALUE) {
882 do {
883 if ((found.cFileName[0] != '.')
884 && strcmp(found.cFileName,OWNERS1)
885 && strcmp(found.cFileName,OWNERS2)) {
886 fullname =
887 (char *)malloc(strlen(dir)
888 + strlen(found.cFileName) + 2);
889 if (fullname) {
890 strcpy(fullname, dir);
891 strcat(fullname, "\\");
892 strcat(fullname,
893 found.cFileName);
894 recurse((char*)NULL, fullname, 2);
895 free(fullname);
896 }
897 }
898 } while (FindNextFile(search, &found));
899 FindClose(search);
900 } else {
901 printf("No directory found in %s\n",dir);
902 err = AGREED;
903 }
904 }
905 return (!err);
906}
907
908#else
909
910STATIC boolean getusers(const char *dir, int levels)
911{
912 boolean err;
913 struct CALLBACK context;
914
915 printf("* Search for \"" OWNERS1 "\" and \"" OWNERS2 "\"\n");
916 err = DENIED;
917 context.dir = dir;
918 context.accname = (const char*)NULL;
919 context.levels = levels;
920 context.docset = 2;
921 ntfs_read_directory(ntfs_context,dir,callback,&context);
922 printf("* Search for other directories %s\n",dir);
923 context.docset = 0;
924 ntfs_read_directory(ntfs_context,dir,callback,&context);
925
926 return (!err);
927}
928
929#endif
930
931#ifdef WIN32
932/*
933 * Get the current login name (Win32 only)
934 */
935
936STATIC void loginname(boolean silent)
937{
938 char *winname;
939 char *domain;
940 unsigned char *sid;
941 unsigned long namesz;
942 unsigned long sidsz;
943 unsigned long domainsz;
944 int nametype;
945 boolean ok;
946 int r;
947
948 ok = FALSE;
949 winname = (char*)malloc(MAXNAMESZ);
950 domain = (char*)malloc(MAXNAMESZ);
951 sid = (char*)malloc(MAXSIDSZ);
952
953 namesz = MAXNAMESZ;
954 domainsz = MAXNAMESZ;
955 sidsz = MAXSIDSZ;
956 if (winname
957 && domain
958 && sid
959 && GetUserName(winname,&namesz)) {
960 winname[namesz] = '\0';
961 if (!silent)
962 printf("Your current user name is %s\n",winname);
963 nametype = 1;
964 r = LookupAccountName((char*)NULL,winname,sid,&sidsz,
965 domain,&domainsz,&nametype);
966 if (r) {
967 domain[domainsz] = '\0';
968 if (!silent)
969 printf("Your account domain is %s\n",domain);
970 ok = AGREED;
971 }
972 }
973 if (ok) {
974 currentwinname = winname;
975 currentdomain = domain;
976 currentsid = sid;
977 } else {
978 currentwinname = (char*)NULL;
979 currentdomain = (char*)NULL;
980 currentsid = (unsigned char*)NULL;
981 }
982}
983
984/*
985 * Minimal output on stdout
986 */
987
988boolean minimal(unsigned char *sid)
989{
990 const unsigned char *groupsid;
991 boolean ok;
992
993 ok = DENIED;
994 if (sid) {
995 groupsid = makegroupsid(sid);
996 printf("# %s\n",BANNER);
997 printf("# For Windows account \"%s\" in domain \"%s\"\n",
998 currentwinname, currentdomain);
999 printf("# Replace \"user\" and \"group\" hereafter by matching Linux login\n");
1000 printf("user::%s\n",decodesid(sid));
1001 printf(":group:%s\n",decodesid(groupsid));
1002 ok = AGREED;
1003 }
1004 return (ok);
1005}
1006
1007#endif
1008
1009STATIC boolean outputmap(const char *volume, const char *dir)
1010{
1011 char buf[256];
1012 int fn;
1013 char *fullname;
1014 char *backup;
1015 struct MAPPING *mapping;
1016 boolean done;
1017 boolean err;
1018 boolean undecided;
1019#ifdef WIN32
1020#else
1021 struct stat st;
1022 int s;
1023#endif
1024
1025 done = DENIED;
1026 fullname = (char *)malloc(strlen(MAPFILE) + 1
1027 + strlen(volume) + 1
1028 + (dir ? strlen(dir) + 1 : 0));
1029 if (fullname) {
1030#ifdef WIN32
1031 strcpy(fullname, volume);
1032 if (dir && dir[0]) {
1033 strcat(fullname, "\\");
1034 strcat(fullname,dir);
1035 }
1036
1037 /* build directory, if not present */
1038 if (GetFileAttributes(fullname) & 0x80000000) {
1039 printf("* Creating directory %s\n", fullname);
1040 mkdir(fullname);
1041 }
1042
1043 strcat(fullname, "\\");
1044 strcat(fullname, MAPFILE);
1045 printf("\n");
1046
1047 if (!(GetFileAttributes(fullname) & 0x80000000)) {
1048 backup = (char*)malloc(strlen(fullname) + 5);
1049 strcpy(backup,fullname);
1050 strcat(backup,".bak");
1051 unlink(backup);
1052 if (!rename(fullname,backup))
1053 printf("* Old mapping file moved to %s\n",backup);
1054 }
1055#else
1056 strcpy(fullname, MAPFILE);
1057 printf("\n");
1058
1059 s = stat(fullname,&st);
1060 if (!s) {
1061 backup = (char*)malloc(strlen(fullname + 5));
1062 strcpy(backup,fullname);
1063 strcat(backup,".bak");
1064 if (rename(fullname,backup))
1065 printf("* Old mapping file moved to %s\n",backup);
1066 }
1067#endif
1068
1069 printf("* Creating file %s\n", fullname);
1070 err = DENIED;
1071#ifdef WIN32
1072 fn = open(fullname,O_CREAT + O_TRUNC + O_WRONLY + O_BINARY,
1073 S_IREAD + S_IWRITE);
1074#else
1075 fn = open(fullname,O_CREAT + O_TRUNC + O_WRONLY,
1076 S_IREAD + S_IWRITE);
1077#endif
1078 if (fn > 0) {
1079 sprintf(buf,"# %s\n",BANNER);
1080 if (!write(fn,buf,strlen(buf)))
1081 err = AGREED;
1082 printf("%s",buf);
1083 undecided = DENIED;
1084 /* records for owner only or group only */
1085 for (mapping = firstmapping; mapping && !err;
1086 mapping = mapping->next)
1087 if (mapping->defined
1088 && (!mapping->uidstr[0] || !mapping->gidstr[0])) {
1089 sprintf(buf,"%s:%s:%s\n",
1090 mapping->uidstr,
1091 mapping->gidstr,
1092 mapping->sidstr);
1093 if (!write(fn,buf,strlen(buf)))
1094 err = AGREED;
1095 printf("%s",buf);
1096 } else
1097 undecided = AGREED;
1098 /* records for both owner and group */
1099 for (mapping = firstmapping; mapping && !err;
1100 mapping = mapping->next)
1101 if (mapping->defined
1102 && mapping->uidstr[0] && mapping->gidstr[0]) {
1103 sprintf(buf,"%s:%s:%s\n",
1104 mapping->uidstr,
1105 mapping->gidstr,
1106 mapping->sidstr);
1107 if (!write(fn,buf,strlen(buf)))
1108 err = AGREED;
1109 printf("%s",buf);
1110 } else
1111 undecided = AGREED;
1112 done = !err;
1113 close(fn);
1114 if (undecided) {
1115 printf("Undecided :\n");
1116 for (mapping = firstmapping; mapping;
1117 mapping = mapping->next)
1118 if (!mapping->defined) {
1119 printf(" %s\n", mapping->sidstr);
1120 }
1121 }
1122#ifndef WIN32
1123 printf("\n* You will have to move the file \"" MAPFILE "\"\n");
1124 printf(" to directory \"" MAPDIR "\" after mounting\n");
1125#endif
1126 }
1127 }
1128 if (!done)
1129 fprintf(stderr, "* Could not create mapping file \"%s\"\n", fullname);
1130 return (done);
1131}
1132
1133STATIC boolean sanitize(void)
1134{
1135 char buf[81];
1136 boolean ok;
1137 int ownercnt;
1138 int groupcnt;
1139 struct MAPPING *mapping;
1140 struct MAPPING *firstowner;
1141 struct MAPPING *genericgroup;
1142 struct MAPPING *group;
1143 char *sidstr;
1144
1145 /* count owners and groups */
1146 /* and find first user, and a generic group */
1147 ownercnt = 0;
1148 groupcnt = 0;
1149 firstowner = (struct MAPPING*)NULL;
1150 genericgroup = (struct MAPPING*)NULL;
1151 for (mapping=firstmapping; mapping; mapping=mapping->next) {
1152 if (mapping->defined && mapping->uidstr[0]) {
1153 if (!ownercnt)
1154 firstowner = mapping;
1155 ownercnt++;
1156 }
1157 if (mapping->defined && mapping->gidstr[0] && !mapping->uidstr[0]) {
1158 groupcnt++;
1159 }
1160 if (!mapping->defined && isgenericgroup(mapping->sidstr)) {
1161 genericgroup = mapping;
1162 }
1163 }
1164#ifdef WIN32
1165 /* no user defined, on Windows, suggest a mapping */
1166 /* based on account currently used */
1167 if (!ownercnt && currentwinname && currentsid) {
1168 char *owner;
1169 char *p;
1170
1171 printf("\nYou have defined no file owner,\n");
1172 printf(" please enter the Linux login which should be mapped\n");
1173 printf(" to account you are currently using\n");
1174 printf(" Linux user ? ");
1175 p = fgets(buf, 80, stdin);
1176 if (p && p[0] && (p[strlen(p) - 1] == '\n'))
1177 p[strlen(p) - 1] = '\0';
1178 if (p && p[0]) {
1179 firstowner = (struct MAPPING*)malloc(sizeof(struct MAPPING));
1180 owner = (char*)malloc(strlen(p) + 1);
1181 if (firstowner && owner) {
1182 strcpy(owner, p);
1183 firstowner->next = firstmapping;
1184 firstowner->uidstr = owner;
1185 firstowner->gidstr = "";
1186 firstowner->sidstr = decodesid(currentsid);
1187 firstowner->sid = currentsid;
1188 firstmapping = firstowner;
1189 ownercnt++;
1190 /* prefer a generic group with the same authorities */
1191 for (mapping=firstmapping; mapping;
1192 mapping=mapping->next)
1193 if (!mapping->defined
1194 && isgenericgroup(mapping->sidstr)
1195 && !memcmp(firstowner->sidstr,
1196 mapping->sidstr,
1197 strlen(mapping->sidstr)-3))
1198 genericgroup = mapping;
1199 }
1200 }
1201 }
1202#endif
1203 if (ownercnt) {
1204 /*
1205 * No group was selected, but there were a generic group
1206 * insist in using it, associated to the first user
1207 */
1208 if (!groupcnt) {
1209 printf("\nYou have defined no group, this can cause problems\n");
1210 printf("Do you accept defining a standard group ?\n");
1211 if (!fgets(buf,80,stdin)
1212 || ((buf[0] != 'n')
1213 && (buf[0] != 'N'))) {
1214 if (genericgroup) {
1215 genericgroup->uidstr = "";
1216 genericgroup->gidstr = firstowner->uidstr;
1217 genericgroup->defined = AGREED;
1218 } else {
1219 group = (struct MAPPING*)
1220 malloc(sizeof(struct MAPPING));
1221 sidstr = decodesid(
1222 makegroupsid(firstowner->sid));
1223 if (group && sidstr) {
1224 group->uidstr = "";
1225 group->gidstr = firstowner->
1226 uidstr;
1227 group->sidstr = sidstr;
1228 group->defined = AGREED;
1229 group->next = firstmapping;
1230 firstmapping = group;
1231 }
1232 }
1233 }
1234 }
1235 ok = AGREED;
1236 } else {
1237 printf("\nYou have defined no user, no mapping can be built\n");
1238 ok = DENIED;
1239 }
1240
1241 return (ok);
1242}
1243
1244STATIC boolean checkoptions(int argc, char *argv[], boolean silent)
1245{
1246 boolean err;
1247#ifdef WIN32
1248 int xarg;
1249 const char *pvol;
1250
1251 if (silent)
1252 err = (argc != 1);
1253 else {
1254 err = (argc < 2);
1255 for (xarg=1; (xarg<argc) && !err; xarg++) {
1256 pvol = argv[xarg];
1257 if (pvol[0] && (pvol[1] == ':') && !pvol[2]) {
1258 err = !(((pvol[0] >= 'A') && (pvol[0] <= 'Z'))
1259 || ((pvol[0] >= 'a') && (pvol[0] <= 'z')));
1260 }
1261 }
1262 }
1263 if (err) {
1264 fprintf(stderr, "Usage : usermap [vol1: [vol2: ...]]\n");
1265 fprintf(stderr, " \"voln\" are the letters of the partition to share with Linux\n");
1266 fprintf(stderr, " eg C:\n");
1267 fprintf(stderr, " the Windows system partition should be named first\n");
1268 }
1269#else
1270 unused((void*)argv);
1271 unused((void*)&silent);
1272 err = (argc < 2);
1273 if (err) {
1274 fprintf(stderr, "Usage : usermap dev1 [dev2 ...]\n");
1275 fprintf(stderr, " \"dev.\" are the devices to share with Windows\n");
1276 fprintf(stderr, " eg /dev/sdb1\n");
1277 fprintf(stderr, " the devices should not be mounted\n");
1278 fprintf(stderr, " the Windows system partition should be named first\n");
1279 } else
1280 if (getuid()) {
1281 fprintf(stderr, "\nSorry, only root can start usermap\n");
1282 err = AGREED;
1283 }
1284#endif
1285 return (!err);
1286}
1287
1288STATIC boolean process(int argc, char *argv[])
1289{
1290 boolean ok;
1291 int xarg;
1292 int targ;
1293
1294 firstmapping = (struct MAPPING *)NULL;
1295 lastmapping = (struct MAPPING *)NULL;
1296 ok = AGREED;
1297#ifdef WIN32
1298 for (xarg=1; (xarg<argc) && ok; xarg++) {
1299 printf("\n* Scanning \"%s\" (two levels)\n",argv[xarg]);
1300 ok = getusers(argv[xarg],2);
1301 }
1302#else
1303 for (xarg=1; (xarg<argc) && ok; xarg++)
1304 if (open_volume(argv[xarg])) {
1305 printf("\n* Scanning \"%s\" (two levels)\n",argv[xarg]);
1306 ok = getusers("/",2);
1307 close_volume(argv[xarg]);
1308 } else
1309 ok = DENIED;
1310#endif
1311 if (ok && sanitize()) {
1312 targ = (argc > 2 ? 2 : 1);
1313 if (!outputmap(argv[targ],MAPDIR)) {
1314 printf("Trying to write file on root directory\n");
1315 if (outputmap(argv[targ],(const char*)NULL)) {
1316 printf("\nNote : you will have to move the file to directory \"%s\" on Linux\n",
1317 MAPDIR);
1318 } else
1319 ok = DENIED;
1320 } else
1321 ok = DENIED;
1322 } else
1323 ok = DENIED;
1324 return (ok);
1325}
1326
1327int main(int argc, char *argv[])
1328{
1329 boolean ok;
1330 boolean silent;
1331
1332 silent = !isatty(1);
1333 if (!silent)
1334 welcome();
1335 if (checkoptions(argc, argv, silent)) {
1336#ifdef WIN32
1337 loginname(silent);
1338 if (silent)
1339 ok = minimal(currentsid);
1340 else
1341 ok = process(argc, argv);
1342#else
1343 if (open_security_api()) {
1344 ok = process(argc,argv);
1345 if (!close_security_api()) ok = DENIED;
1346 }
1347#endif
1348 } else
1349 ok = DENIED;
1350 if (!ok)
1351 exit(1);
1352 return (0);
1353}
1354