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