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 | |
135 | typedef enum { DENIED, AGREED } boolean; |
136 | |
137 | #else |
138 | |
139 | #include <unistd.h> |
140 | #include <dlfcn.h> |
141 | |
142 | typedef enum { DENIED, AGREED } boolean, BOOL; |
143 | typedef unsigned int DWORD; /* must be 32 bits whatever the platform */ |
144 | typedef DWORD *LPDWORD; |
145 | |
146 | enum { OWNER_SECURITY_INFORMATION = 1, |
147 | GROUP_SECURITY_INFORMATION = 2, |
148 | DACL_SECURITY_INFORMATION = 4, |
149 | SACL_SECURITY_INFORMATION = 8 |
150 | } ; |
151 | |
152 | struct CALLBACK { |
153 | const char *accname; |
154 | const char *dir; |
155 | int levels; |
156 | int docset; |
157 | } ; |
158 | |
159 | typedef 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 | |
167 | BOOL ntfs_get_file_security(void *scapi, |
168 | const char *path, DWORD selection, |
169 | char *buf, DWORD buflen, LPDWORD psize); |
170 | BOOL ntfs_set_file_security(void *scapi, |
171 | const char *path, DWORD selection, const char *attr); |
172 | BOOL ntfs_read_directory(void *scapi, |
173 | const char *path, dircallback callback, void *context); |
174 | void *ntfs_initialize_file_security(const char *device, |
175 | int flags); |
176 | BOOL ntfs_leave_file_security(void *scapi); |
177 | |
178 | #else |
179 | |
180 | #define STATIC |
181 | |
182 | BOOL (*ntfs_get_file_security)(void *scapi, |
183 | const char *path, DWORD selection, |
184 | char *buf, DWORD buflen, LPDWORD psize); |
185 | BOOL (*ntfs_set_file_security)(void *scapi, |
186 | const char *path, DWORD selection, const char *attr); |
187 | BOOL (*ntfs_read_directory)(void *scapi, |
188 | const char *path, dircallback callback, void *context); |
189 | void *(*ntfs_initialize_file_security)(const char *device, |
190 | int flags); |
191 | BOOL (*ntfs_leave_file_security)(void *scapi); |
192 | |
193 | #endif |
194 | |
195 | STATIC boolean open_security_api(void); |
196 | STATIC boolean close_security_api(void); |
197 | STATIC boolean open_volume(const char *volume); |
198 | STATIC boolean close_volume(const char *volume); |
199 | |
200 | #endif |
201 | |
202 | struct 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 | |
212 | struct MAPPING *firstmapping; |
213 | struct MAPPING *lastmapping; |
214 | |
215 | #ifdef WIN32 |
216 | char *currentwinname; |
217 | char *currentdomain; |
218 | unsigned char *currentsid; |
219 | #endif |
220 | |
221 | #ifndef WIN32 |
222 | |
223 | void *ntfs_handle; |
224 | void *ntfs_context = (void*)NULL; |
225 | |
226 | /* |
227 | * Shut down compiler warnings for unused parameters |
228 | */ |
229 | |
230 | static long unused(const void *p) |
231 | { |
232 | return ((long)p); |
233 | } |
234 | |
235 | /* |
236 | * Open and close the security API (platform dependent) |
237 | */ |
238 | |
239 | STATIC 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 | |
285 | STATIC 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 | |
299 | STATIC 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 | |
318 | STATIC 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 | |
336 | STATIC 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 | |
359 | STATIC 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 | |
383 | STATIC 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 | |
391 | STATIC 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 | |
402 | STATIC 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 | |
413 | STATIC 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 | |
424 | STATIC 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 | |
453 | STATIC 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 | |
462 | STATIC 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 | |
477 | STATIC 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 | |
575 | STATIC 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 | |
591 | STATIC 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 | |
633 | STATIC 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 | |
678 | STATIC 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 | |
726 | STATIC boolean recurse(const char *accname, const char *dir, int levels, int docset); |
727 | |
728 | STATIC 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 | |
798 | STATIC 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 | |
819 | STATIC 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 | |
913 | STATIC 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 | |
939 | STATIC 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 | |
991 | boolean 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 | |
1012 | STATIC 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 | |
1136 | STATIC 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 | |
1247 | STATIC 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 | |
1291 | STATIC 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 | |
1330 | int 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 |