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 | |
132 | typedef enum { DENIED, AGREED } boolean; |
133 | |
134 | #else |
135 | |
136 | #include <unistd.h> |
137 | #include <dlfcn.h> |
138 | |
139 | typedef enum { DENIED, AGREED } boolean, BOOL; |
140 | typedef unsigned int DWORD; /* must be 32 bits whatever the platform */ |
141 | typedef DWORD *LPDWORD; |
142 | |
143 | enum { OWNER_SECURITY_INFORMATION = 1, |
144 | GROUP_SECURITY_INFORMATION = 2, |
145 | DACL_SECURITY_INFORMATION = 4, |
146 | SACL_SECURITY_INFORMATION = 8 |
147 | } ; |
148 | |
149 | struct CALLBACK { |
150 | const char *accname; |
151 | const char *dir; |
152 | int levels; |
153 | int docset; |
154 | } ; |
155 | |
156 | typedef 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 | |
164 | BOOL ntfs_get_file_security(void *scapi, |
165 | const char *path, DWORD selection, |
166 | char *buf, DWORD buflen, LPDWORD psize); |
167 | BOOL ntfs_set_file_security(void *scapi, |
168 | const char *path, DWORD selection, const char *attr); |
169 | BOOL ntfs_read_directory(void *scapi, |
170 | const char *path, dircallback callback, void *context); |
171 | void *ntfs_initialize_file_security(const char *device, |
172 | int flags); |
173 | BOOL ntfs_leave_file_security(void *scapi); |
174 | |
175 | #else |
176 | |
177 | #define STATIC |
178 | |
179 | BOOL (*ntfs_get_file_security)(void *scapi, |
180 | const char *path, DWORD selection, |
181 | char *buf, DWORD buflen, LPDWORD psize); |
182 | BOOL (*ntfs_set_file_security)(void *scapi, |
183 | const char *path, DWORD selection, const char *attr); |
184 | BOOL (*ntfs_read_directory)(void *scapi, |
185 | const char *path, dircallback callback, void *context); |
186 | void *(*ntfs_initialize_file_security)(const char *device, |
187 | int flags); |
188 | BOOL (*ntfs_leave_file_security)(void *scapi); |
189 | |
190 | #endif |
191 | |
192 | STATIC boolean open_security_api(void); |
193 | STATIC boolean close_security_api(void); |
194 | STATIC boolean open_volume(const char *volume); |
195 | STATIC boolean close_volume(const char *volume); |
196 | |
197 | #endif |
198 | |
199 | struct 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 | |
209 | struct MAPPING *firstmapping; |
210 | struct MAPPING *lastmapping; |
211 | |
212 | #ifdef WIN32 |
213 | char *currentwinname; |
214 | char *currentdomain; |
215 | unsigned char *currentsid; |
216 | #endif |
217 | |
218 | #ifndef WIN32 |
219 | |
220 | void *ntfs_handle; |
221 | void *ntfs_context = (void*)NULL; |
222 | |
223 | /* |
224 | * Shut down compiler warnings for unused parameters |
225 | */ |
226 | |
227 | static long unused(const void *p) |
228 | { |
229 | return ((long)p); |
230 | } |
231 | |
232 | /* |
233 | * Open and close the security API (platform dependent) |
234 | */ |
235 | |
236 | STATIC 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 | |
282 | STATIC 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 | |
296 | STATIC 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 | |
315 | STATIC 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 | |
333 | STATIC 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 | |
356 | STATIC 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 | |
380 | STATIC 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 | |
388 | STATIC 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 | |
399 | STATIC 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 | |
410 | STATIC 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 | |
421 | STATIC 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 | |
450 | STATIC 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 | |
459 | STATIC 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 | |
474 | STATIC 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 | |
572 | STATIC 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 | |
588 | STATIC 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 | |
630 | STATIC 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 | |
675 | STATIC 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 | |
723 | STATIC boolean recurse(const char *accname, const char *dir, int levels, int docset); |
724 | |
725 | STATIC 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 | |
795 | STATIC 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 | |
816 | STATIC 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 | |
910 | STATIC 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 | |
936 | STATIC 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 | |
988 | boolean 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 | |
1009 | STATIC 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 | |
1133 | STATIC 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 | |
1244 | STATIC 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 | |
1288 | STATIC 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 | |
1327 | int 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 |