summaryrefslogtreecommitdiffstats
path: root/perl-install/authentication.pm
blob: 518411a28cb925b97319119535d416beba9051a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
package authentication;

use common;

my $authentication;

sub kinds { 
    my $no_para = @_ == 0;
    my ($do_pkgs, $_meta_class) = @_;
    my $allow_SmartCard = $no_para || $do_pkgs->is_available('castella-pam');
    (
	'LDAP',
	'KRB5',
	'winbind', 
	'NIS', 
	if_($allow_SmartCard, 'SmartCard'), 
	'local',
    );
}

sub kind2name {
    my ($kind) = @_;
    # Keep the following strings in sync with kind2description ones!!!
    ${{ local => N("Local file"), 
    LDAP => N("LDAP"), 
    NIS => N("NIS"),
    SmartCard => N("Smart Card"),
    winbind => N("Windows Domain"), 
    KRB5 => N("Kerberos 5") }}{$kind};
}

my %kind2pam_kind = (
    local     => [],
    SmartCard => ['castella'],
    LDAP      => ['ldap'], 
    NIS       => [],
    KRB5        => ['krb5'],
    winbind   => ['winbind'], 
);

my %kind2nsswitch = (
    local     => [],
    SmartCard => [],
    LDAP      => ['ldap'], 
    NIS       => ['nis'],
    KRB5        => ['ldap'],
    winbind   => ['winbind'], 
);

my $lib = (arch() =~ /x86_64/ ? 'lib64' : 'lib');

my %kind2packages = (
    local     => [],
    SmartCard => [ 'castella-pam' ],
    LDAP      => [ 'openldap-clients', 'nss-pam-ldapd', 'autofs', 'nss_updatedb' ],
    KRB5       => [ 'nss-pam-ldapd', 'pam_krb5', "${lib}sasl2-plug-gssapi", 'nss_updatedb' ],
    NIS       => [ 'ypbind', 'autofs' ],
    winbind   => [ 'samba-winbind', 'nss-pam-ldapd', 'pam_krb5', "${lib}sasl2-plug-gssapi" ],
);


sub kind2description_raw {
    my (@kinds) = @_;
    my %kind2description = (
	local     => [ N("Local file:"), N("Use local for all authentication and information user tell in local file"), ],
	LDAP      => [ N("LDAP:"), N("Tells your computer to use LDAP for some or all authentication. LDAP consolidates certain types of information within your organization."), ],
	NIS       => [ N("NIS:"), N("Allows you to run a group of computers in the same Network Information Service domain with a common password and group file."), ],
	winbind   => [ N("Windows Domain:"), N("Winbind allows the system to retrieve information and authenticate users in a Windows domain."), ],
	KRB5        => [ N("Kerberos 5 :"), N("With Kerberos and LDAP for authentication in Active Directory Server "), ],
    );
    join('', map { $_ ? qq($_->[0]\n$_->[1]) : '' } map { $kind2description{$_} } @kinds);
}

sub kind2description {
    my (@kinds) = @_;
    join('', map { $_ ? qq($_\n\n) : '' } map { kind2description_raw($_) } @kinds);
}

sub to_kind {
    my ($authentication) = @_;
    (find { exists $authentication->{$_} } kinds()) || 'local';
}

sub domain_to_ldap_domain {
    my ($domain) = @_;
    join(',', map { "dc=$_" } split /\./, $domain);
}

sub ask_parameters {
    my ($in, $net, $authentication, $kind) = @_;

    #- keep only this authentication kind
    foreach (kinds()) {
	delete $authentication->{$_} if $_ ne $kind;
    }
    # do not enable ccreds unless required
    undef $authentication->{ccreds};

    if ($kind eq 'LDAP') {
	$authentication->{LDAPDOMAIN} ||= domain_to_ldap_domain($net->{resolv}{DOMAINNAME});
	$authentication->{ccreds} = 1;

    # this package must be installed for 'Fetch DN' button to actually work
    $in->do_pkgs->ensure_are_installed([ 'openldap-clients' ], 1) or return;
    
	$in->ask_from('', N(" "),
		     [ { label => N("Welcome to the Authentication Wizard"), title => 1 },
                     {},
                     { label => N("You have selected LDAP authentication. Please review the configuration options below "), },
                     {},
		     { label => N("LDAP Server"), val => \$authentication->{LDAP_server} },
		     { label => N("Base dn"), val => \$authentication->{LDAPDOMAIN} },
                     { val => N("Fetch base Dn "), type  => 'button' , clicked_may_quit => sub { $authentication->{LDAPDOMAIN} = fetch_dn($authentication->{LDAP_server}); 0 } },
		     {},
		     { text => N("Use encrypt connection with TLS "), val => \$authentication->{cafile}, type => 'bool' },
                     { val => N("Download CA Certificate "), type  => 'button' , disabled => sub { !$authentication->{cafile} }, clicked_may_quit => sub { $authentication->{file} = add_cafile(); 0 }  },
		     
		     { text => N("Use Disconnect mode "), val => \$authentication->{ccreds}, type => 'bool' },
		     { text => N("Use anonymous BIND "), val => \$authentication->{anonymous}, type => 'bool' , advanced => 1 },
		     { text => N("  "), advanced => 1 },
                     { label => N("Bind DN "), val => \$authentication->{LDAP_binddn}, disabled => sub { !$authentication->{anonymous} }, advanced => 1  },
                     { label => N("Bind Password "), val => \$authentication->{LDAP_bindpwd}, disabled => sub { !$authentication->{anonymous} }, advanced => 1 },
		     { text => N("  "), advanced => 1 },
		     { text => N("Advanced path for group "), val => \$authentication->{nssgrp}, type => 'bool' , advanced => 1 },
		     { text => N("  "), advanced => 1 },
                     { label => N("Password base"), val => \$authentication->{nss_pwd},  disabled => sub { !$authentication->{nssgrp} }, advanced => 1 },
                     { label => N("Group base"), val => \$authentication->{nss_grp},  disabled => sub { !$authentication->{nssgrp} }, advanced => 1 },
                     { label => N("Shadow base"), val => \$authentication->{nss_shadow},  disabled => sub { !$authentication->{nssgrp} }, advanced => 1 },
		     { text => N("  "), advanced => 1 },
		     ]) or return;
    } elsif ($kind eq 'KRB5') {
	
	$authentication->{AD_domain} ||= $net->{resolv}{DOMAINNAME};
	$in->do_pkgs->ensure_are_installed([ 'perl-Net-DNS' ], 1) or return;
	my @srvs = query_srv_names($authentication->{AD_domain}); #FIXME: update this list if the REALM has changed
	$authentication->{AD_server} ||= $srvs[0] if @srvs;
	my $AD_user = $authentication->{AD_user} =~ /(.*)\@\Q$authentication->{AD_domain}\E$/ ? $1 : $authentication->{AD_user};
	$authentication->{ccreds} = 1;

	$in->ask_from('', N(" "),
                        [ { label => N("Welcome to the Authentication Wizard"), title => 1 },
                        {},
                        { label => N("You have selected Kerberos 5 authentication. Please review the configuration options below "), },
                        {},
		       { label => N("Realm "),  val => \$authentication->{AD_domain} },
                       {},
		       { label => N("KDCs Servers"), title => 1, val => \$authentication->{AD_server} , list => \@srvs , not_edit => 0,  title => 1 },
                       {},
		       { text => N("Use DNS to locate KDC for the realm"), val => \$authentication->{KRB_host_lookup}, type => 'bool' },
		       { text => N("Use DNS to locate realms"), val => \$authentication->{KRB_dns_lookup}, type => 'bool' },
		       { text => N("Use Disconnect mode "), val => \$authentication->{ccreds}, type => 'bool' },
		     ]) or return;

my %level = (
             1 => N("Use local file for users information"),
             2 => N("Use LDAP for users information"),
            );

 $in->ask_from('', N(" "),
                        [ { label => N(" "), title => 1 },
                        {},
                        { label => N("You have selected Kerberos 5 for authentication, now you must choose the type of users information "), },
                        {},
			{ label => "" , val => \$authentication->{nsskrb}, type => 'list', list => [ keys %level ], format => sub { $level{$_[0]} } },
			{},	
			{ label => N("LDAP Server"), val => \$authentication->{LDAP_server}, disabled => sub { $authentication->{nsskrb} eq "1"  } },
                     	{ label => N("Base dn"), val => \$authentication->{LDAPDOMAIN} , disabled => sub { $authentication->{nsskrb} eq "1"  } },
                     	{ val => N("Fecth base Dn "), type  => 'button' , clicked_may_quit => sub { $authentication->{LDAPDOMAIN} = fetch_dn($authentication->{LDAP_server}); 0 }, disabled => sub { $authentication->{nsskrb} eq "1"  } },
			{},
                     	{ text => N("Use encrypt connection with TLS "), val => \$authentication->{cafile}, type => 'bool',, disabled => sub { $authentication->{nsskrb} eq "1"  } },
                     	{ val => N("Download CA Certificate "), type  => 'button' , disabled => sub { !$authentication->{cafile} }, clicked_may_quit => sub { $authentication->{file} = add_cafile(); 0 }  },
                     	{ text => N("Use anonymous BIND "), val => \$authentication->{anonymous}, type => 'bool', disabled => sub { $authentication->{nsskrb} eq "1"  } },
                     	{ label => N("Bind DN "), val => \$authentication->{LDAP_binddn}, disabled => sub { !$authentication->{anonymous} } },
                     	{ label => N("Bind Password "), val => \$authentication->{LDAP_bindpwd}, disabled => sub { !$authentication->{anonymous} } },
                     	{},
			]) or return;
	
	$authentication->{AD_user} = !$AD_user || $authentication->{sub_kind} eq 'anonymous' ? '' : 
	                             $AD_user =~ /@/ ? $AD_user : "$AD_user\@$authentication->{AD_domain}";
	$authentication->{AD_password} = '' if !$authentication->{AD_user};


    } elsif ($kind eq 'NIS') {
	$authentication->{NIS_server} ||= 'broadcast';
	$net->{network}{NISDOMAIN} ||= $net->{resolv}{DOMAINNAME};
	$in->ask_from('', N(" "),
		[ { label => N("Welcome to the Authentication Wizard"), title => 1 },
		{},
		{ label => N("You have selected NIS authentication. Please review the configuration options below "), },
		{},
		{ label => N("NIS Domain"), val => \$net->{network}{NISDOMAIN} },
		{ label => N("NIS Server"), val => \$authentication->{NIS_server}, list => ["broadcast"], not_edit => 0 },
		{},
		     ]) or return;
    } elsif ($kind eq 'winbind') {
	#- maybe we should browse the network like diskdrake --smb and get the 'doze server names in a list 
	#- but networking is not setup yet necessarily
	#
	my @sec_domain = (
		"Windows Active Directory Domain",
		"Windows NT4 Domain",
);


	$authentication->{DNS_domain} ||= $net->{resolv}{DOMAINNAME};
	$authentication->{WINDOMAIN} ||= $net->{resolv}{DOMAINNAME};
	$in->do_pkgs->ensure_are_installed([ 'samba-client' ], 1) or return;
	my @domains=list_domains();

	$in->ask_from('', N(" "),
			[ { label => N("Welcome to the Authentication Wizard"), title => 1 },
			{},
			{ label => N("You have selected Windows Domain authentication. Please review the configuration options below "), },
		        {},
			{ label => N("Windows Domain"), val => \$authentication->{WINDOMAIN}, list => \@domains, not_edit => 1 },
		        {},
		        { label => N("Domain Model "), val => \$authentication->{model}, list => \@sec_domain , not_edit => 1 },
		        {},
			{ label => N("Active Directory Realm "), val => \$authentication->{AD_domain} , disabled => sub { $authentication->{model} eq "Windows NT4 Domain"  } },
			{ label => N("DNS Domain"), val => \$authentication->{DNS_domain} , disabled => sub { $authentication->{model} eq "Windows NT4 Domain"  } },
			{ label => N("DC Server"), val => \$authentication->{AD_server} , disabled => sub { $authentication->{model} eq "Windows NT4 Domain"  } },
		        {},
			]) or return;
    }
    $authentication->{$kind} ||= 1;
    1;
}
sub ask_root_password_and_authentication {
    my ($in, $net, $superuser, $authentication, $meta_class, $security) = @_;

    my $kind = to_kind($authentication);
    my @kinds = kinds($in->do_pkgs, $meta_class);

    $in->ask_from_({
	 title => N("Authentication"), 
	 messages => N("Set administrator (root) password"),
	 advanced_label => N("Authentication method"),
	 advanced_messages => kind2description(@kinds),
	 interactive_help_id => "setRootPassword",
	 cancel => ($security <= 2 ? 
		    #-PO: keep this short or else the buttons will not fit in the window
		    N("No password") : ''),
	 focus_first => 1,
	 callbacks => { 
	     complete => sub {
		 check_given_password($in, $superuser, 2 * $security) or return 1,0;
		 return 0;
        } } }, [
{ label => N("Password"), val => \$superuser->{password},  hidden => 1 },
{ label => N("Password (again)"), val => \$superuser->{password2}, hidden => 1 },
{ label => N("Authentication"), val => \$kind, type => 'list', list => \@kinds, format => \&kind2name, advanced => 1 },
        ]) or delete $superuser->{password};

    ask_parameters($in, $net, $authentication, $kind) or goto &ask_root_password_and_authentication;
}

sub check_given_password {
    my ($in, $u, $min_length) = @_;
    if ($u->{password} ne $u->{password2}) {
	$in->ask_warn('', [ N("The passwords do not match"), N("Please try again") ]);
	0;
    } elsif (length $u->{password} < $min_length) {
	$in->ask_warn('', N("This password is too short (it must be at least %d characters long)", $min_length));
	0;
    } else {
	1;
    }
}

sub get() {
    my $system_auth = cat_("/etc/pam.d/system-auth");
    my $authentication = {
	blowfish => to_bool($system_auth =~ /\$2a\$/),
	md5      => to_bool($system_auth =~ /md5/), 
	shadow   => to_bool($system_auth =~ /shadow/),
    };

    my @pam_kinds = get_pam_authentication_kinds();
    if (my $kind = find { intersection(\@pam_kinds, $kind2pam_kind{$_}) } keys %kind2pam_kind) {
	$authentication->{$kind} = '';
    } else {
	#- we can't use pam to detect NIS
	if (my $yp_conf = read_yp_conf()) {
	    $authentication->{NIS} = 1;
	    map_each { $authentication->{"NIS_$::a"} = $::b } %$yp_conf;
	}
    }
    $authentication;
}

sub install_needed_packages {
    my ($do_pkgs, $kind, $ccreds) = @_;
    if (my $pkgs = $kind2packages{$kind}) {
	# install ccreds if required
	$ccreds and push(@$pkgs, 'pam_ccreds');
	#- automatic during install
	$do_pkgs->ensure_are_installed($pkgs, $::isInstall) or return;
    } else {
	log::l("ERROR: $kind not listed in kind2packages");
    }
    1;
}

sub set {
    my ($in, $net, $authentication, $o_when_network_is_up) = @_;

    install_needed_packages($in->do_pkgs, to_kind($authentication), $authentication->{ccreds}) or return;
    set_raw($net, $authentication, $o_when_network_is_up);

    require services;
    services::set_status('network-auth', to_kind($authentication) ne 'local', 'dont_apply');
}

sub set_raw {
    my ($net, $authentication, $o_when_network_is_up) = @_;

    my $conf_file = "$::prefix/etc/sysconfig/drakauth";
    my $when_network_is_up = $o_when_network_is_up || sub { my ($f) = @_; $f->() };

    enable_shadow() if $authentication->{shadow};    

    my $kind = to_kind($authentication);

    log::l("authentication::set $kind");

    my $pam_modules = $kind2pam_kind{$kind} or log::l("kind2pam_kind does not know $kind");
    $pam_modules ||= [];
    set_pam_authentication($pam_modules, $authentication->{ccreds});

    my $nsswitch = $kind2nsswitch{$kind} or log::l("kind2nsswitch does not know $kind");
    $nsswitch ||= [];
    set_nsswitch_priority($nsswitch, $authentication->{ccreds});

    if ($kind eq 'local') {

	output($conf_file, <<EOF);
auth=Local File 
server=none 
realm=none
EOF



    } elsif ($kind eq 'SmartCard') {
    } elsif ($kind eq 'LDAP') {

	configure_nss_ldap($authentication);

	output($conf_file, <<EOF);
auth=LDAP Directory
server=$authentication->{LDAP_server}
realm=$authentication->{LDAPDOMAIN}
EOF

    if ($authentication->{ccreds}) {
	run_program::rooted($::prefix, '/usr/sbin/nss_updatedb.cron');  # updates offline cache.
    }

    } elsif ($kind eq 'KRB5') {

	configure_krb5_for_AD($authentication);
	configure_nss_ldap($authentication);

	output($conf_file, <<EOF);
auth=Kerberos 5
server=$authentication->{AD_server}
realm=$authentication->{AD_domain}
EOF

    } elsif ($kind eq 'NIS') {
	my $domain = $net->{network}{NISDOMAIN};
	my $NIS_server = $authentication->{NIS_server};
	$domain || $NIS_server ne "broadcast" or die N("Cannot use broadcast with no NIS domain");
	my $t = $domain ? 
	  ($NIS_server eq 'broadcast' ? 
	     "domain $domain broadcast" : 
	     "domain $domain server $NIS_server") :
	     "server $NIS_server";

	substInFile {
	    if (/^#/) {
		$_ = '' if /^#\Q[PREVIOUS]/;
	    } else {
		$_ = "#[PREVIOUS] $_";
	    }
	    $_ .= "$t\n" if eof;
	} "$::prefix/etc/yp.conf";

	#- no need to modify system-auth for nis

	$when_network_is_up->(sub {
	    run_program::rooted($::prefix, 'nisdomainname', $domain);
	    run_program::rooted($::prefix, 'service', 'ypbind', 'restart');
	});

	output($conf_file, <<EOF);
auth=$kind
server=$NIS_server
realm=$domain
EOF

    } elsif ($kind eq 'winbind') {

	my $domain = uc $authentication->{WINDOMAIN};
	($authentication->{winuser}, $authentication->{winpass}) = auth();

	if ($authentication->{model} eq "Windows NT4 Domain") {

	require fs::remote::smb;
	fs::remote::smb::write_smb_conf($domain);
	run_program::rooted($::prefix, "chkconfig", "--level", "35", "winbind", "on");
	mkdir_p("$::prefix/home/$domain");
	run_program::rooted($::prefix, 'service', 'smb', 'restart');
	run_program::rooted($::prefix, 'service', 'winbind', 'restart');
	
	#- defer running smbpassword until the network is up

	$when_network_is_up->(sub {
	    run_program::raw({ root => $::prefix, sensitive_arguments => 1 },
			                 #'net', 'join', $domain, '-U', $authentication->{winuser} . '%' . $authentication->{winpass});
			     'echo', '"', 'net', 'join', $domain, '-U', $authentication->{winuser} . '%' . $authentication->{winpass}, '"');
	});

	output($conf_file, <<EOF);
auth=Windows NT4 Domain
server= none 
realm=$domain
EOF




	} else { 	
	# FIXME: the DC isn't named ads.domain... try to do reserve lookup?
	$authentication->{AD_server} ||= 'ads.' . $authentication->{AD_domain};
	my $domain = uc $authentication->{WINDOMAIN};
	my $realm = $authentication->{AD_domain};
	($authentication->{winuser}, $authentication->{winpass}) = auth();
	configure_krb5_for_AD($authentication);
		
	require fs::remote::smb;
	fs::remote::smb::write_smb_ads_conf($domain,$realm);
	run_program::rooted($::prefix, "chkconfig", "--level", "35", "winbind", "on");
	mkdir_p("$::prefix/home/$domain");
	run_program::rooted($::prefix, 'net', 'time', 'set', '-S', $authentication->{AD_server});
	run_program::rooted($::prefix, 'service', 'smb', 'restart');
	
	$when_network_is_up->(sub {
	    run_program::raw({ root => $::prefix, sensitive_arguments => 1 }, 
			     'net', 'ads', 'join', '-U', $authentication->{winuser} . '%' . $authentication->{winpass});
	    run_program::rooted($::prefix, 'service', 'winbind', 'restart');
	});

	#FIXME: perhaps save the defaults values ?
	output($conf_file, <<EOF);
auth=Windows Active Directory Domain
server= none
realm=$realm
EOF
    } }
    1;
}


sub pam_modules() {
    'pam_ldap', 'pam_castella', 'pam_winbind', 'pam_krb5', 'pam_mkhomedir', 'pam_ccreds', 'pam_deny' , 'pam_permit';
}
sub pam_module_from_path { 
    $_[0] && $_[0] =~ m|(/lib/security/)?(pam_.*)\.so| && $2;
}
sub pam_module_to_path { 
    "$_[0].so";
}
sub pam_format_line {
    my ($type, $control, $module, @para) = @_;
    sprintf("%-11s %-13s %s\n", $type, $control, join(' ', pam_module_to_path($module), @para));
}

sub get_raw_pam_authentication() {
    my %before_deny;
    foreach (cat_("$::prefix/etc/pam.d/system-auth")) {
	my ($type, $_control, $other) = /(\S+)\s+(\[.*?\]|\S+)\s+(.*)/;
	my ($module, @para) = split(' ', $other);
	if ($module = pam_module_from_path($module)) {
	    $before_deny{$type}{$module} = \@para if member($module, pam_modules());
	}
    }
    \%before_deny;
}

sub get_pam_authentication_kinds() {
    my $before_deny = get_raw_pam_authentication();
    map { s/pam_//; $_ } keys %{$before_deny->{auth}};
}

sub sufficient {
    my ($ccreds, $module, $type) = @_;

    $ccreds && member($module, 'pam_tcb' , 'pam_winbind') ?
      'sufficient' :
    $ccreds && member($module, 'pam_ldap', 'pam_krb5') && $type eq 'account' ?
      '[authinfo_unavail=ignore default=done]' :
    $ccreds && member($module, 'pam_ldap', 'pam_krb5') && $type eq 'password' ?
      'sufficient' :
    $ccreds && member($module, 'pam_ldap', 'pam_krb5') ?
      '[authinfo_unavail=ignore user_unknown=ignore success=1 default=2]' :
      'sufficient';
}

sub pam_sufficient_line {
    my ($ccreds, $type, $module, @para) = @_;
    my $control = sufficient($ccreds, $module, $type);
    if ($module eq 'pam_winbind') {
	push @para, 'cached_login';
    }
    pam_format_line($type, $control, $module, @para);
}






sub set_pam_authentication {
    my ($authentication_kinds, $o_ccreds) = @_;
    
    my %special = (
	auth => [ difference2($authentication_kinds,, [ 'mount' ]) ],
	account => [ difference2($authentication_kinds, [ 'castella', 'mount', 'ccreds' ]) ],
	password => [ intersection($authentication_kinds, [ 'ldap', 'krb5', 'ccreds' ]) ],
    );
    my %before_first = (
	auth => member('mount', @$authentication_kinds) ? pam_format_line('auth', 'required', 'pam_mount') : '',
	session => 
	  intersection($authentication_kinds, [ 'winbind', 'krb5', 'ldap' ])
	    ? pam_format_line('session', 'optional', 'pam_mkhomedir', 'skel=/etc/skel/', 'umask=0022') :
	    member('castella', @$authentication_kinds)
	    ? pam_format_line('session', 'optional', 'pam_castella') : '',
    );
    my %after_deny = (
	session =>
          member('krb5', @$authentication_kinds)
            ? pam_format_line('session', 'optional', 'pam_krb5') :
          member('mount', @$authentication_kinds)
            ? pam_format_line('session', 'optional', 'pam_mount') : '',
    );

    substInFile {
	my ($type, $control, $other) = /(\S+)\s+(\[.*?\]|\S+)\s+(.*)/;
	my ($module, @para) = split(' ', $other);
	if ($module = pam_module_from_path($module)) {
	    if (member($module, pam_modules())) {
		#- first removing previous config
		$_ = '';
	    }
	    if ($module eq 'pam_tcb' && $special{$type}) {
		my @para_for_last = 
		    member($type, 'auth', 'account') ? qw(use_first_pass) : @{[]};
		@para = difference2(\@para, \@para_for_last);

		my ($before_noask, $ask) = partition { $_ eq 'castella' } @{$special{$type}};

		if (!@$ask) {
		    @para_for_last = grep { $_ ne 'use_first_pass' } @para_for_last;
		}

		my @l = ((map { [ "pam_$_" ] } @$before_noask),
			 [ 'pam_tcb', @para ],
			 (map { [ "pam_$_" ] } @$ask),
			 );
		push @{$l[-1]}, @para_for_last;

		$_ = join('', map { pam_sufficient_line($o_ccreds, $type, @$_) } @l);

		if ($control eq 'required') {
		    #- ensure a pam_deny line is there. it will be added below
		    ($module, @para) = ('pam_deny');
		}

		if ($type eq 'auth' && $o_ccreds) {
			$_ .= pam_format_line('auth', '[default=done]', 'pam_ccreds', 'action=validate use_first_pass');
			$_ .= pam_format_line('auth', '[default=done]', 'pam_ccreds', 'action=store');
			$_ .= pam_format_line('auth', '[default=bad]',  'pam_ccreds', 'action=update');
		}
	    }


	    if (member($module, 'pam_deny', 'pam_permit')) {
		$_ .= pam_format_line($type, $control, 
				      $type eq 'account' && $o_ccreds ? 'pam_permit' : 'pam_deny');
	    }
	    if (my $s = delete $before_first{$type}) {
		$_ = $s . $_;
	    }
	    if ($control eq 'required' && member($module, 'pam_deny', 'pam_permit', 'pam_tcb')) {
		if (my $s = delete $after_deny{$type}) {
		    $_ .= $s;
		}
	    }
	}
    } "$::prefix/etc/pam.d/system-auth";
}

sub set_nsswitch_priority {
    my ($kinds, $connected) = @_;
    my @known = qw(nis ldap winbind compat);
    substInFile {
	if (my ($database, $l) = /^(\s*(?:passwd|shadow|group|automount):\s*)(.*)/) {
	    my @l = difference2([ split(' ', $l) ], \@known);
		$_ = $database . join(' ', uniq('files', @$kinds, @l)) . "\n";
	}
	if (/^\s*(?:passwd|group):/) {
		my $option = '[NOTFOUND=return] db';
	if ($connected) {
		s/$/ $option/ if !/\Q$option/;
	} else {
		s/\s*\Q$option//;
	}
}	

    } "$::prefix/etc/nsswitch.conf";
}

sub read_yp_conf() {
    my $yp_conf = cat_("$::prefix/etc/yp.conf");
    
    if ($yp_conf =~ /^domain\s+(\S+)\s+(\S+)\s*(.*)/m) {
	{ domain => $1, server => $2 eq 'broadcast' ? 'broadcast' : $3 };
    } elsif ($yp_conf =~ /^server\s+(.*)/m) {
	{ server => $1 };
    } else {
	undef;
    }    
}

my $special_ldap_cmds = join('|', 'nss_map_attribute', 'nss_map_objectclass');
sub _after_read_ldap_line {
    my ($s) = @_;
    $s =~ s/\b($special_ldap_cmds)\s*/$1 . '_'/e;
    $s;
}
sub _pre_write_ldap_line {
    my ($s) = @_;
    $s =~ s/\b($special_ldap_cmds)_/$1 . ' '/e;
    $s;
}

sub read_ldap_conf() {
    my %conf = map { 
	s/^\s*#.*//; 
	if_(_after_read_ldap_line($_) =~ /(\S+)\s+(.*)/, $1 => $2);
    } cat_("$::prefix/etc/nslcd.conf");
    \%conf;
}

sub update_ldap_conf {    
    my (%conf) = @_;

    substInFile {
	my ($cmd) = _after_read_ldap_line($_) =~ /^\s*#?\s*(\w+)\s/;
	if ($cmd && exists $conf{$cmd}) {
	    my $val = $conf{$cmd};
	    $conf{$cmd} = '';
	    $_ = $val ? _pre_write_ldap_line("$cmd $val\n") : /^\s*#/ ? $_ : "#$_";
        }
	if (eof) {
	    foreach my $cmd (keys %conf) {
		my $val = $conf{$cmd} or next;
		$_ .= _pre_write_ldap_line("$cmd $val\n");
	    }
	}
    } "$::prefix/etc/nslcd.conf";
}

sub configure_krb5_for_AD {
    my ($authentication) = @_;

    my $uc_domain = uc $authentication->{AD_domain};
    my $krb5_conf_file = "$::prefix/etc/krb5.conf";

    krb5_conf_update($krb5_conf_file,
		     libdefaults => (
				     default_realm => $uc_domain,
				     dns_lookup_realm => $authentication->{KRB_dns_lookup} ? 'true' : 'false',
				     dns_lookup_kdc => $authentication->{KRB_host_lookup} ? 'true' : 'false',
				     default_tgs_enctypes => undef, 
				     default_tkt_enctypes => undef,
				     permitted_enctypes => undef,
				    ));

    my @sections = (
		    realms => <<EOF,
 $uc_domain = {
  kdc = $authentication->{AD_server}:88
  admin_server = $authentication->{AD_server}:749
  default_domain = $authentication->{AD_domain}
 }
EOF
		    domain_realm => <<EOF,
 .$authentication->{AD_domain} = $uc_domain
 $authentication->{AD_domain} = $uc_domain
EOF
		    kdc => <<'EOF',
 profile = /etc/kerberos/krb5kdc/kdc.conf
EOF
		    pam => <<'EOF',
 debug = false
 ticket_lifetime = 36000
 renew_lifetime = 36000
 forwardable = true
 krb4_convert = false
EOF
		    login => <<'EOF',
 krb4_convert = false
 krb4_get_tickets = false
EOF
		       );
    foreach (group_by2(@sections)) {
	my ($section, $txt) = @$_;
	krb5_conf_overwrite_category($krb5_conf_file, $section => $authentication->{AD_server} ? $txt : '');
    }
}

sub krb5_conf_overwrite_category {
    my ($file, $category, $new_val) = @_;

    my $done;
    substInFile {
	if (my $i = /^\s*\[\Q$category\E\]/i ... /^\[/) {
	    if ($new_val) {
		if ($i == 1) {
		    $_ .= $new_val;
		    $done = 1;
		} elsif ($i =~ /E/) {
		    $_ = "\n$_";
		} else {
		    $_ = '';
		}
	    } else {
		$_ = '' if $i !~ /E/;
	    }
	}
	#- if category has not been found above.
	if (eof && $new_val && !$done) {
	    $_ .= "\n[$category]\n$new_val";
	}
    } $file;
}

#- same as update_gnomekderc(), but allow spaces around "="
sub krb5_conf_update {
    my ($file, $category, %subst_) = @_;

    my %subst = map { lc($_) => [ $_, $subst_{$_} ] } keys %subst_;

    my $s;
    foreach (MDK::Common::File::cat_($file), "[NOCATEGORY]\n") {
	if (my $i = /^\s*\[\Q$category\E\]/i ... /^\[/) {
	    if ($i =~ /E/) { #- for last line of category
		chomp $s; $s .= "\n";
		$s .= " $_->[0] = $_->[1]\n" foreach grep { defined($_->[1]) } values %subst;
		%subst = ();
	    } elsif (/^\s*([^=]*?)\s*=/) {
		if (my $e = delete $subst{lc($1)}) {
		    $_ = defined($e->[1]) ? " $1 = $e->[1]\n" : '';
		}
	      }
	}
	$s .= $_ if !/^\Q[NOCATEGORY]/;
    }

    #- if category has not been found above.
    if (keys %subst) {
	chomp $s;
	$s .= "\n[$category]\n";
	$s .= " $_->[0] = $_->[1]\n" foreach grep { defined($_->[1]) } values %subst;
    }

    MDK::Common::File::output($file, $s);

}

sub query_srv_names {
    my ($domain) = @_;

    eval { require Net::DNS; 1 } or return;
    my $res = Net::DNS::Resolver->new;
    my $query = $res->query("_ldap._tcp.$domain", 'srv') or return;
    map { $_->target } $query->answer;
}

sub enable_shadow() {
    run_program::rooted($::prefix, "pwconv")  or log::l("pwconv failed");
    run_program::rooted($::prefix, "grpconv") or log::l("grpconv failed");
}

sub salt {
    my ($nb) = @_;
    require devices;
    open(my $F, "/dev/urandom") or die "missing urandom";
    my $s; read $F, $s, $nb;
    $s = pack("b8" x $nb, unpack "b6" x $nb, $s);
    $s =~ tr|\0-\x3f|0-9a-zA-Z./|;
    $s;
}

sub user_crypted_passwd {
    my ($u, $authentication) = @_;
    if ($u->{password}) {
	require utf8;
	utf8::encode($u->{password}); #- we don't want perl to do "smart" things in crypt()

	crypt($u->{password}, 
	      !$authentication || $authentication->{blowfish} ? '$2a$08$' . salt(60) :
	      $authentication->{md5} ? '$1$' . salt(8) : salt(2));
    } else {
	$u->{pw} || '';
    }
}

sub set_root_passwd {
    my ($superuser, $authentication) = @_;
    $superuser->{name} = 'root';
    write_passwd_user($superuser, $authentication);    
    delete $superuser->{name};
}

sub write_passwd_user {
    my ($u, $authentication) = @_;

    $u->{pw} = user_crypted_passwd($u, $authentication);
    $u->{shell} ||= '/bin/bash';

    substInFile {
	my $l = unpack_passwd($_);
	if ($l->{name} eq $u->{name}) {
	    add2hash_($u, $l);
	    $_ = pack_passwd($u);
	    $u = {};
	}
	if (eof && $u->{name}) {
	    $_ .= pack_passwd($u);
	}
    } "$::prefix/etc/passwd";
}

my @etc_pass_fields = qw(name pw uid gid realname home shell);
sub unpack_passwd {
    my ($l) = @_;
    my %l; @l{@etc_pass_fields} = split ':', chomp_($l);
    \%l;
}
sub pack_passwd {
    my ($l) = @_;
    join(':', @$l{@etc_pass_fields}) . "\n";
}

sub add_cafile() {
	my $in = interactive->vnew;
	$in->ask_filename({ title => N("Select file") }) or return;
}

sub auth() {
	my $in = interactive->vnew;
        $in->ask_from('', N(" "), [
		{ label => N("Domain Windows for authentication : ") . $authentication->{WINDOMAIN} },
		{},
		{ label => N("Domain Admin User Name"), val => \$authentication->{winuser} },
	        { label => N("Domain Admin Password"), val => \$authentication->{winpass}, hidden => 1 },
	]);
	return $authentication->{winuser}, $authentication->{winpass};
}

require fs::remote::smb;
sub list_domains() {
    my $smb = fs::remote::smb->new;
    my %domains;
    foreach my $server ($smb->find_servers) {
        $domains{$server->{group}} = 1;
    }
    return sort keys %domains;
}
sub get_server_for_domain {
    my $smb = fs::remote::smb->new;
    foreach my $server ($smb->find_servers) {
        return $server->{name} if $server->{group} == $_[0];
    }
}

sub fetch_dn {
	my ($srv) = @_;
	my $s = run_program::rooted_get_stdout($::prefix, 'ldapsearch', '-x', '-h', $srv, '-b', '', '-s', 'base', '+');
	$authentication->{LDAPDOMAIN} = first($s =~ /namingContexts: (.+)/);
	return $authentication->{LDAPDOMAIN};
}
	
sub configure_nss_ldap {
	my ($authentication) = @_;
	update_ldap_conf(
			 uri => $authentication->{cafile} eq '1' ? "ldaps://" . $authentication->{LDAP_server} . "/" : "ldap://" . $authentication->{LDAP_server} . "/",
                         base => $authentication->{LDAPDOMAIN},
                        );

        if ($authentication->{nssgrp} eq '1') {

        update_ldap_conf(
                         'base shadow' => $authentication->{nss_shadow},
                         'base passwd' => $authentication->{nss_pwd},
                         'base group' => $authentication->{nss_grp},
			 scope => "sub",
                        );
        } else {

        update_ldap_conf(
                         'base shadow' => $authentication->{LDAPDOMAIN},
                         'base passwd' => $authentication->{LDAPDOMAIN},
                         'base group' => $authentication->{LDAPDOMAIN},
			 scope => "sub",
                        );
                }
        if ($authentication->{anonymous} eq '1') {
                 update_ldap_conf(
                         binddn => $authentication->{LDAP_binddn},
                         bindpw => $authentication->{LDAP_bindpwd},
                        );
        }

        if ($authentication->{cafile} eq '1') {
                 update_ldap_conf(
                 ssl => "on",
                 tls_reqcert => "allow",
                 tls_cacertfile => $authentication->{file},
                );
        }
 }

 sub compute_password_weakness {

   my ($password) = @_;
   my $score = 0;
   my $len = length($password);

   return 0 if $len == 0;

   $score = $len < 5 ? 3 :
   $len > 4 && $len < 8 ? 6 :
   $len > 7 && $len < 16 ? 12 : 18;

   $score += 1 if $password =~ /[a-z]/;
   $score += 5 if $password =~ /[A-Z]/;
   $score += 5 if $password =~ /\d+/;
   $score += 5 if $password =~ /(.*[0-9].*[0-9].*[0-9])/;
   $score += 5 if $password =~ /.[!@#$%^&*?_~,]/;
   $score += 5 if $password =~ /(.*[!@#$%^&*?_~,].*[!@#$%^&*?_~,])/;
   $score += 2 if $password =~ /([a-z].*[A-Z])|([A-Z].*[a-z])/;
   $score += 2 if $password =~ /([a-zA-Z])/ && $password =~ /([0-9])/;
   $score += 2 if $password =~ /([a-z].*[A-Z])|([A-Z].*[a-z])/;
   $score += 2 if $password =~ /([a-zA-Z0-9].*[!@#$%^&*?_~])|([!@#$%^&*?_~,].*[a-zA-Z0-9])/;

   my $level = $score < 11 ? 1 :
   $score > 10 && $score < 20 ? 2 :
   $score > 19 && $score < 30 ? 3 :
   $score > 29 && $score < 40 ? 4 : 5;

   return $level;
 }
1;
kwa">msgid "Installing packages on nodes..." msgstr "正在由節點安裝套件..." #: ../urpm/parallel_ssh.pm:28 ../urpm/parallel_ssh.pm:126 #: ../urpm/parallel_ssh.pm:230 #, c-format msgid "scp failed on host %s (%d)" msgstr "主機 %s scp 失敗 (%d)" #: ../urpm/parallel_ssh.pm:124 #, c-format msgid "Propagating synthesis to %s..." msgstr "正在將綜合文件傳送到 %s..." #: ../urpm/parallel_ssh.pm:177 #, c-format msgid "Resolving dependencies on %s..." msgstr "正在解决 %s 上的相依性..." #: ../urpm/parallel_ssh.pm:207 #, c-format msgid "host %s does not have a good version of urpmi (%d)" msgstr "主機 %s 上的 urpmi 版本並不正確 (%d)" #: ../urpm/parallel_ssh.pm:223 #, c-format msgid "Distributing files to %s..." msgstr "正在發佈檔案到 %s" #: ../urpm/parallel_ssh.pm:237 #, c-format msgid "Verifying if install is possible on %s..." msgstr "正在驗證使不可以在 %s 上進行安裝..." #: ../urpm/parallel_ssh.pm:261 #, c-format msgid "Performing install on %s..." msgstr "正在 %s 上進行安装..." #: ../urpm/parallel_ssh.pm:274 #, c-format msgid "Installing %s on %s..." msgstr "正在 %2$s 上安装 %1$s..." #: ../urpm/parallel_ssh.pm:275 #, c-format msgid "Preparing install on %s..." msgstr "正在準備安裝到 %s 上..." #: ../urpme:37 #, c-format msgid "" "urpme version %s\n" "Copyright (C) 1999-2006 Mandriva.\n" "This is free software and may be redistributed under the terms of the GNU " "GPL.\n" "\n" "usage:\n" msgstr "" "urpme 版本號 %s\n" "Copyright (C) 1999-2006 Mandriva。\n" "這是自由軟體並可於 GNU GPL 條款下重新散佈。\n" "\n" "用法:\n" #: ../urpme:42 ../urpmf:34 ../urpmi:80 ../urpmi.addmedia:44 #: ../urpmi.recover:31 ../urpmi.removemedia:54 ../urpmi.update:31 ../urpmq:44 msgid " --help - print this help message.\n" msgstr " --help - 顯示此說明訊息。\n" #: ../urpme:43 msgid " --auto - automatically select a package in choices.\n" msgstr " --auto - 自動選擇套件。\n" #: ../urpme:44 msgid " --test - verify if the removal can be achieved correctly.\n" msgstr " --test - 確認刪除是否能夠正確進行。\n" #: ../urpme:45 ../urpmi:102 ../urpmq:63 msgid "" " --force - force invocation even if some packages do not exist.\n" msgstr " --force - 即使某些套件不存在仍然強制執行。\n" #: ../urpme:46 ../urpmi:107 ../urpmq:65 msgid " --parallel - distributed urpmi across machines of alias.\n" msgstr " --parallel - 在同步管理的機器上分散式的執行 urpmi。\n" #: ../urpme:47 ../urpmi:134 msgid " --repackage - Re-package the files before erasing\n" msgstr " --repackage - 在移除前重新打包檔案\n" #: ../urpme:48 msgid " --root - use another root for rpm removal.\n" msgstr " --root - 使用另一個根目錄移除 rpm 套件。\n" #: ../urpme:49 msgid " --noscripts - do not execute package scriptlet(s).\n" msgstr " --noscripts - 不執行套件中的命令稿。\n" #: ../urpme:50 msgid "" " --use-distrib - configure urpme on the fly from a distrib tree, useful\n" " to (un)install a chroot with --root option.\n" msgstr "" " --use-distrib - 立即由一個散佈套件樹設定 urpme,在搭配 --root 選項來安\n" " 裝/移除一個 chroot 時很方便。\n" #: ../urpme:52 ../urpmi:145 ../urpmi.addmedia:70 ../urpmi.removemedia:59 #: ../urpmi.update:49 ../urpmq:91 msgid " -v - verbose mode.\n" msgstr " -v - 完整訊息模式。\n" #: ../urpme:53 msgid " -a - select all packages matching expression.\n" msgstr " -a - 選擇所有符合描述的套件。\n" #: ../urpme:70 msgid "Only superuser is allowed to remove packages" msgstr "只有擁有管理者權限的使用者才能移除套件" #: ../urpme:96 msgid "unknown package" msgstr "未知的套件" #. - Warning : the following message is parsed in urpm::parallel_* #: ../urpme:96 msgid "unknown packages" msgstr "未知的套件" #. - Warning : the following message is parsed in urpm::parallel_* #: ../urpme:108 ../urpmi:488 #, c-format msgid "removing package %s will break your system" msgstr "移除套件 %s 將破壞您的系統" #: ../urpme:111 msgid "Nothing to remove" msgstr "沒有東西可移除" #. - Warning : the following message is parsed in urpm::parallel_* #: ../urpme:116 msgid "Checking to remove the following packages" msgstr "正在檢查以移除下列套件" #: ../urpme:123 #, c-format msgid "" "To satisfy dependencies, the following %d packages will be removed (%d MB)" msgstr "為了滿足相依性,下列 %d 個套件將被移除 (%d MB)" #: ../urpme:125 ../urpmi:510 ../urpmi:643 msgid " (y/N) " msgstr " (y/N) (是/否) " #: ../urpme:125 #, c-format msgid "Remove %d packages?" msgstr "要移除這 %d 個套件嗎?" #. - Warning : the following message is parsed in urpm::parallel_* #: ../urpme:149 msgid "Removal failed" msgstr "移除失敗" #: ../urpmf:28 #, c-format msgid "" "urpmf version %s\n" "Copyright (C) 2002-2006 Mandriva.\n" "This is free software and may be redistributed under the terms of the GNU " "GPL.\n" "\n" "usage: urpmf [options] pattern-expression\n" msgstr "" "urpmf 版本號 %s\n" "Copyright (C) 2002-2006 Mandriva。\n" "這是自由軟體並可於 GNU GPL 條款下重新散佈。\n" "\n" "用法:urpmf [選項] pattern-expression\n" #: ../urpmf:35 msgid " --version - print this tool's version number.\n" msgstr " --version - 印出這個工具的版本編號。\n" #: ../urpmf:36 ../urpmi:125 ../urpmq:74 msgid " --env - use specific environment (typically a bug report).\n" msgstr " --env - 使用特定環境 (一般用於臭蟲回報)。\n" #: ../urpmf:37 ../urpmi:82 ../urpmq:48 msgid " --excludemedia - do not use the given media, separated by comma.\n" msgstr " --excludemedia - 不使用給定的媒體,不同媒體間請以逗號分隔。\n" #: ../urpmf:38 msgid "" " --literal, -l - don't match patterns, use argument as a literal string.\n" msgstr " --literal, -l - 不比對樣版,把參數當作一般字串。\n" #: ../urpmf:39 ../urpmi:81 ../urpmq:46 msgid " --media - use only the given media, separated by comma.\n" msgstr " --media - 只使用給定的媒體,不同媒體間請以逗號分隔。\n" #: ../urpmf:40 ../urpmi:85 ../urpmq:49 msgid "" " --sortmedia - sort media according to substrings separated by comma.\n" msgstr " --sortmedia - 依據子字串排序媒體,以逗號分開。\n" #: ../urpmf:41 ../urpmi:86 ../urpmq:50 msgid " --synthesis - use the given synthesis instead of urpmi db.\n" msgstr " --synthesis - 使用指定的 synthesis 檔而非 urpmi 資料庫。\n" #: ../urpmf:42 msgid " --uniq - do not print identical lines twice.\n" msgstr " --uniq - 不顯示相同的訊息。\n" #: ../urpmf:43 ../urpmi:83 ../urpmq:45 msgid " --update - use only update media.\n" msgstr " --update - 只使用更新媒體。\n" #: ../urpmf:44 msgid " --verbose - verbose mode.\n" msgstr " --verbose - 完整訊息模式。\n" #: ../urpmf:45 msgid " -i - ignore case distinctions in patterns.\n" msgstr " -i - 忽略每個樣版中的大小寫差異。\n" #: ../urpmf:46 msgid " -F<str> - change field separator (defaults to ':').\n" msgstr " -F<字串> - 更改字串分隔符號 (預設為“:”)。\n" #: ../urpmf:47 msgid "Pattern expressions:\n" msgstr "樣版表示式:\n" #: ../urpmf:48 msgid " text - any text is parsed as a regexp, unless -l is used.\n" msgstr " 文字 - 任何文字都將被分析為正規表示式,除非使用了 -l。\n" #: ../urpmf:49 msgid " -e - include perl code directly as perl -e.\n" msgstr " -e - 直接包含 perl 原始碼,類似 perl -e。\n" #: ../urpmf:50 msgid " -a - binary AND operator.\n" msgstr " -a - 二元 AND 運算子。\n" #: ../urpmf:51 msgid " -o - binary OR operator.\n" msgstr " -o - 二元 OR 運算子。\n" #: ../urpmf:52 msgid " ! - unary NOT.\n" msgstr " ! - 一元 NOT 運算子。\n" #: ../urpmf:53 msgid " ( ) - left and right parentheses.\n" msgstr " ( ) - 左右括弧。\n" #: ../urpmf:54 msgid "List of tags:\n" msgstr "標籤清單:\n" #: ../urpmf:55 msgid " --qf - specify a printf-like output format\n" msgstr " --qf - 使用類似 printf 的輸出格式\n" #: ../urpmf:56 #, c-format msgid " example: '%%name:%%files'\n" msgstr " 範例:'%%name:%%files'\n" #: ../urpmf:57 msgid " --arch - architecture\n" msgstr " --arch - 硬體架構\n" #: ../urpmf:58 msgid " --buildhost - build host\n" msgstr " --buildhost - 建立主機\n" #: ../urpmf:59 msgid " --buildtime - build time\n" msgstr " --buildtime - 建立時間\n" #: ../urpmf:60 msgid " --conffiles - configuration files\n" msgstr " --conffiles - 組態檔\n" #: ../urpmf:61 msgid " --conflicts - conflict tags\n" msgstr " --conflicts - 衝突標籤\n" #: ../urpmf:62 msgid " --description - package description\n" msgstr " --description - 套件描述\n" #: ../urpmf:63 msgid " --distribution - distribution\n" msgstr " --distribution - 發行版\n" #: ../urpmf:64 msgid " --epoch - epoch\n" msgstr " --epoch - 時期\n" #: ../urpmf:65 msgid " --filename - filename of the package\n" msgstr " --filename - 套件檔案名稱\n" #: ../urpmf:66 msgid " --files - list of files contained in the package\n" msgstr " --files - 列出套件內包含的檔案\n" #: ../urpmf:67 msgid " --group - group\n" msgstr " --group - 群組\n" #: ../urpmf:68 msgid " --name - package name\n" msgstr " --name - 套件名稱\n" #: ../urpmf:69 msgid " --obsoletes - obsoletes tags\n" msgstr "" " --obsoletes - 淘汰標籤\n" "\n" #: ../urpmf:70 msgid " --packager - packager\n" msgstr " --packager - 打包者\n" #: ../urpmf:71 msgid " --provides - provides tags\n" msgstr " --provides - 提供標籤\n" #: ../urpmf:72 msgid " --requires - requires tags\n" msgstr " --requires - 需要標籤\n" #: ../urpmf:73 msgid " --size - installed size\n" msgstr " --size - 安裝大小\n" #: ../urpmf:74 msgid " --sourcerpm - source rpm name\n" msgstr " --sourcerpm - 原始碼套件名稱\n" #: ../urpmf:75 msgid " --summary - summary\n" msgstr " --summary - 摘要\n" #: ../urpmf:76 msgid " --url - url\n" msgstr " --url - URL\n" #: ../urpmf:77 msgid " --vendor - vendor\n" msgstr " --vendor - 提供者\n" #: ../urpmf:78 msgid " -m - the media in which the package was found\n" msgstr " -m - 這個套件被找到的媒介\n" #: ../urpmf:79 ../urpmq:80 msgid " -f - print version, release and arch with name.\n" msgstr " -f - 顯示版本、發行編號與平台。\n" #: ../urpmf:131 msgid "Incorrect format: you may use only one multi-valued tag" msgstr "格式錯誤:您只能使用一個多值標籤" #: ../urpmf:173 ../urpmi:231 ../urpmq:126 #, c-format msgid "using specific environment on %s\n" msgstr "正在 %s 上使用特定的環境\n" #: ../urpmf:219 msgid "" "Note: since no media searched uses hdlists, urpmf was unable to return any " "result\n" msgstr "" "注意:因為所有搜尋過的媒體都沒有使用 hdlists,所以 urpmf 無法回傳任何結果\n" #: ../urpmf:220 msgid "You may want to use --name to search for package names.\n" msgstr "您或許想要使用 --name 參數來搜尋套件名稱。\n" #: ../urpmi:75 #, c-format msgid "" "urpmi version %s\n" "Copyright (C) 1999-2006 Mandriva.\n" "This is free software and may be redistributed under the terms of the GNU " "GPL.\n" "\n" "usage:\n" msgstr "" "urpmi 版本號 %s\n" "Copyright (C) 1999-2006 Mandriva。\n" "這是自由軟體並可於 GNU GPL 條款下重新散佈。\n" "\n" "用法:\n" #: ../urpmi:84 msgid "" " --searchmedia - use only the given media to search requested packages.\n" msgstr " --searchmedia - 只使用指定的媒體來搜尋需要的套件。\n" #: ../urpmi:87 msgid "" " --auto - non-interactive mode, assume default answers to " "questions.\n" msgstr " --auto - 非互動式模式,對問題使用預設的回答。\n" #: ../urpmi:88 ../urpmq:51 msgid "" " --auto-select - automatically select packages to upgrade the system.\n" msgstr " --auto-select - 自動選擇要用來升級系統的套件。\n" #: ../urpmi:89 msgid "" " --no-uninstall - never ask to uninstall a package, abort the " "installation.\n" msgstr " --no-uninstall - 絕不要求移除套件,直接中斷安裝。\n" #: ../urpmi:90 msgid " --no-install - don't install packages (only download)\n" msgstr " --no-install - 不安裝套件 (只下載)。\n" #: ../urpmi:91 ../urpmq:53 msgid "" " --keep - keep existing packages if possible, reject requested\n" " packages that lead to removals.\n" msgstr "" " --keep - 盡可能的保留現存的套件,拒絕安裝會導致移除其他套件的\n" " 套件。\n" #: ../urpmi:93 #, c-format msgid "" " --split-level - split in small transaction if more than given packages\n" " are going to be installed or upgraded,\n" " default is %d.\n" msgstr "" " --split-level - 如果要安裝或升級的套件數大於指定的數量,將整個安裝程序\n" " 分割為幾個小的安裝程序。\n" " 預設值為 %d\n" #: ../urpmi:96 #, c-format msgid " --split-length - small transaction length, default is %d.\n" msgstr " --split-length - 小型安裝程序大小,預設值為 %d\n" #: ../urpmi:97 msgid " --fuzzy, -y - impose fuzzy search.\n" msgstr " --fuzzy, -y - 加上模糊搜尋。\n" #: ../urpmi:98 msgid " --src, -s - next package is a source package.\n" msgstr " --src, -s - 下個套件是原始碼套件。\n" #: ../urpmi:99 msgid " --install-src - install only source package (no binaries).\n" msgstr " --install-src - 只安裝原始碼套件 (不安裝二進位檔)。\n" #: ../urpmi:100 msgid " --clean - remove rpm from cache before anything else.\n" msgstr " --clean - 在執行任何事前先由快取中移除 RPM 檔案。\n" #: ../urpmi:101 msgid " --noclean - don't clean rpms from cache.\n" msgstr " --noclean - 不清除快取中的 RPM 檔案。\n" #: ../urpmi:103 msgid "" " --allow-nodeps - allow asking user to install packages without\n" " dependencies checking.\n" msgstr " --allow-nodeps - 允許要求使用者不檢查相依性就安裝套件。\n" #: ../urpmi:105 msgid "" " --allow-force - allow asking user to install packages without\n" " dependencies checking and integrity.\n" msgstr "" " --allow-force - 允許要求使用者安裝套件而不檢查相依性與完整\n" " 性。\n" #: ../urpmi:108 msgid " --root - use another root for rpm installation.\n" msgstr " --root - 使用另一個根目錄進行 RPM 套件的安裝。\n" #: ../urpmi:109 msgid "" " --use-distrib - configure urpmi on the fly from a distrib tree, useful\n" " to install a chroot with --root option.\n" msgstr "" " --use-distrib - 立即由一個散佈套件樹設定 urpmi,在搭配 --root 選項來安\n" " 裝/移除一個 chroot 時很方便。\n" #: ../urpmi:111 ../urpmi.addmedia:45 ../urpmi.update:32 ../urpmq:68 msgid " --wget - use wget to retrieve distant files.\n" msgstr " --wget - 使用 wget 擷取遠端檔案。\n" #: ../urpmi:112 ../urpmi.addmedia:46 ../urpmi.update:33 ../urpmq:69 msgid " --curl - use curl to retrieve distant files.\n" msgstr " --curl - 使用 curl 擷取遠端檔案。\n" #: ../urpmi:113 msgid " --curl-options - additional options to pass to curl\n" msgstr " --curl-options - 要額外傳給 curl 的參數\n" #: ../urpmi:114 msgid " --rsync-options- additional options to pass to rsync\n" msgstr " --rsync-options- 要額外傳給 rsync 的參數\n" #: ../urpmi:115 msgid " --wget-options - additional options to pass to wget\n" msgstr " --wget-options - 要額外傳給 wget 的參數\n" #: ../urpmi:116 ../urpmi.addmedia:47 ../urpmi.update:34 msgid " --limit-rate - limit the download speed.\n" msgstr " --limit-rate - 限制下載的速度。\n" #: ../urpmi:117 msgid "" " --resume - resume transfer of partially-downloaded files\n" " (--no-resume disables it, default is disabled).\n" msgstr "" " --resume - 接著傳送下載到一半的檔案\n" " (--no-resume 選項停用它,預設值為停用)。\n" #: ../urpmi:119 ../urpmi.addmedia:48 ../urpmi.update:35 ../urpmq:70 msgid "" " --proxy - use specified HTTP proxy, the port number is assumed\n" " to be 1080 by default (format is <proxyhost[:port]>).\n" msgstr "" " --proxy - 使用指定的 HTTP 代理伺服器,通訊埠假設為預設值 1080 \n" " (格式為 <proxyhost[:port]>)。\n" #: ../urpmi:121 ../urpmi.addmedia:50 ../urpmi.update:37 ../urpmq:72 msgid "" " --proxy-user - specify user and password to use for proxy\n" " authentication (format is <user:password>).\n" msgstr "" " --proxy-user - 指定代理伺服器認證的使用者帳號與密碼\n" " (格式為 <user:password>)。\n" #: ../urpmi:123 msgid "" " --bug - output a bug report in directory indicated by\n" " next arg.\n" msgstr " --bug - 輸出臭蟲回報到下一個參數所指定的目錄。\n" #: ../urpmi:126 msgid "" " --verify-rpm - verify rpm signature before installation\n" " (--no-verify-rpm disables it, default is enabled).\n" msgstr "" " --verify-rpm - 安裝前檢驗 RPM 檔案的簽章。\n" " (--no-verify-rpm 會停用它,預設值為啟用)。\n" #: ../urpmi:128 msgid "" " --test - only verify if the installation can be achieved " "correctly.\n" msgstr " --test - 僅確認安裝是否能夠正確完成。\n" #: ../urpmi:129 msgid " --excludepath - exclude path separated by comma.\n" msgstr " --excludepath - 排除以逗號分隔的路徑。\n" #: ../urpmi:130 msgid " --excludedocs - exclude doc files.\n" msgstr " --excludedocs - 排除說明文件檔案。\n" #: ../urpmi:131 msgid " --ignoresize - don't verify disk space before installation.\n" msgstr " --ignoresize - 安裝前不檢查剩餘的磁碟空間。\n" #: ../urpmi:132 msgid " --ignorearch - allow to install rpms for unmatched architectures.\n" msgstr " --ignorearch - 允許安裝硬體架構不相符的 RPM 檔。\n" #: ../urpmi:133 msgid " --noscripts - do not execute package scriptlet(s)\n" msgstr " --noscripts - 不執行套件中的命令稿。\n" #: ../urpmi:135 msgid " --skip - packages which installation should be skipped\n" msgstr " --skip - 安裝時應該略過的套件。\n" #: ../urpmi:136 msgid "" " --more-choices - when several packages are found, propose more choices\n" " than the default.\n" msgstr "" " --more-choices - 當找到不只一個套件時,提供除了預設值之外的多個選擇。\n" #: ../urpmi:138 ../urpmi.addmedia:64 ../urpmi.update:42 msgid " --norebuild - don't try to rebuild hdlist if not readable.\n" msgstr "" " --norebuild - 如果 hdlist 檔案無法讀取,不要嘗試重新建立\n" " 它。\n" #: ../urpmi:139 msgid " --nolock - don't lock rpm db.\n" msgstr " --nolock - 不鎖定 RPM 資料庫。\n" #: ../urpmi:140 msgid " --strict-arch - upgrade only packages with the same architecture.\n" msgstr " --strict-arch - 只升級相同平台的套件。\n" #: ../urpmi:141 ../urpmq:77 msgid " -a - select all matches on command line.\n" msgstr " -a - 選擇命令列中所有符合的項目。\n" #: ../urpmi:142 msgid " -p - allow search in provides to find package.\n" msgstr " -p - 允許於 provides 中搜尋套件。\n" #: ../urpmi:143 msgid " -P - do not search in provides to find package.\n" msgstr " -P - 不在 provides 中搜尋套件。\n" #: ../urpmi:144 ../urpmi.addmedia:69 ../urpmi.removemedia:58 #: ../urpmi.update:48 msgid " -q - quiet mode.\n" msgstr " -q - 安靜模式。\n" #: ../urpmi:146 msgid " names or rpm files given on command line will be installed.\n" msgstr " 將會安裝於命令列指定的名稱或 RPM 檔案。\n" #: ../urpmi:197 msgid "You can't install binary rpm files when using --install-src" msgstr "當使用 --install-src 時您無法安裝二進制 RPM 檔案" #: ../urpmi:220 #, c-format msgid "" "Directory [%s] already exists, please use another directory for bug report " "or delete it" msgstr "目錄 [%s] 已經存在,請指定另一個目錄給臭蟲回報或刪除它" #: ../urpmi:221 #, c-format msgid "Unable to create directory [%s] for bug report" msgstr "無法建立 [%s] 目錄給臭蟲回報使用" #: ../urpmi:224 ../urpmi:380 msgid "Copying failed" msgstr "複製失敗" #: ../urpmi:230 #, c-format msgid "Environment directory %s does not exist" msgstr "環境目錄 %s 不存在" #: ../urpmi:248 #, c-format msgid "" "Error: %s appears to be mounted read-only.\n" "Use --allow-force to force operation." msgstr "" "錯誤:%s 似乎被掛載為唯讀模式。\n" "使用 --allow-force 標籤來強制執行。" #. - For translators : there are several media here #: ../urpmi:332 msgid "Updating media..." msgstr "正在更新媒體..." #: ../urpmi:417 #, c-format msgid "What is your choice? (1-%d) " msgstr "您要選擇何者? (1-%d) " #: ../urpmi:447 #, c-format msgid "" "The following packages can't be installed because they depend on packages\n" "that are older than the installed ones:\n" "%s" msgstr "" "下列套件無法安裝,因為它們需要比您系統上的套件為舊的版本:\n" "%s" #: ../urpmi:455 ../urpmi:473 msgid "" "\n" "Continue installation anyway?" msgstr "" "\n" "無論如何都要繼續安裝嗎?" #: ../urpmi:455 ../urpmi:473 ../urpmi:560 msgid " (Y/n) " msgstr " (Y/n) (是/否) " #: ../urpmi:466 #, c-format msgid "" "Some requested packages cannot be installed:\n" "%s" msgstr "" "某些要求的套件無法安裝:\n" "%s" #: ../urpmi:496 #, c-format msgid "" "The installation cannot continue because the following packages\n" "have to be removed for others to be upgraded:\n" "%s\n" msgstr "" "安裝無法繼續,因為下列套件必須移除給其他套件來升級:\n" "%s\n" #: ../urpmi:501 #, c-format msgid "" "The following packages have to be removed for others to be upgraded:\n" "%s" msgstr "" "下列套件必須移除給其他套件來升級:\n" "%s" #: ../urpmi:503 msgid "(test only, removal will not be actually done)" msgstr "(僅測試,移除動作並不會真的執行)" #: ../urpmi:539 ../urpmi:551 msgid "" "To satisfy dependencies, the following packages are going to be installed" msgstr "為了滿足相依性,將一併安裝下列套件" #: ../urpmi:540 ../urpmi:552 msgid "To satisfy dependencies, the following package is going to be installed" msgstr "為了滿足相依性,將一併安裝下列套件" #: ../urpmi:541 #, c-format msgid "(%d packages, %d MB)" msgstr "(%d 個套件,共 %d MB)" #: ../urpmi:547 #, c-format msgid "" "You need to be root to install the following dependencies:\n" "%s\n" msgstr "" "您必須具有管理者權限以安裝下列的相依性項目:\n" "%s\n" #: ../urpmi:554 msgid "(test only, installation will not be actually done)" msgstr "(僅測試,安裝動作並不會真的執行)" #: ../urpmi:556 #, c-format msgid "Proceed with the installation of the %d packages? (%d MB)" msgstr "繼續安裝這 %d 個套件?(共 %d MB)" #: ../urpmi:580 msgid "Press Enter when ready..." msgstr "準備好時請按 Enter..." #: ../urpmi:586 msgid "Cancel" msgstr "取消" #: ../urpmi:586 msgid "Ok" msgstr "確定" #: ../urpmi:633 msgid "The following packages have bad signatures" msgstr "下列套件有不正確的簽章" #: ../urpmi:634 msgid "Do you want to continue installation ?" msgstr "您要繼續安裝嗎?" #: ../urpmi:682 #, c-format msgid "distributing %s" msgstr "正在發佈 %s" #. - there's a common prefix, simplify message #: ../urpmi:693 #, c-format msgid "installing %s from %s" msgstr "正在由 %2$s 安裝 %1$s" #: ../urpmi:695 #, c-format msgid "installing %s" msgstr "正在安裝 %s" #: ../urpmi:729 msgid "Try installation without checking dependencies? (y/N) " msgstr "嘗試不檢查相依性直接安裝? (y/N)(是/否)" #: ../urpmi:747 msgid "Try harder to install (--force)? (y/N) " msgstr "嘗試採用強制安裝的方式 (--force)? (y/N)(是/否)" #: ../urpmi:787 #, c-format msgid "%d installation transactions failed" msgstr "%d 個安裝程序失敗" #: ../urpmi:803 #, c-format msgid "The following package names were assumed: %s" msgstr "以下套件名稱是臆測的:%s" #: ../urpmi:820 msgid "restarting urpmi" msgstr "正在重新啟動 urpmi" #. Translator: The URI types strings 'file:', 'ftp:', 'http:', #. Translator: and 'removable:' must not be translated! #. Translator: neither the ``with''. #. Translator: only what is between <brackets> can be translated. #: ../urpmi.addmedia:35 msgid "" "usage: urpmi.addmedia [options] <name> <url> [with <relative_path>]\n" "where <url> is one of\n" " [file:/]/<path> with <relative filename of hdlist>\n" " ftp://<login>:<password>@<host>/<path> with <relative filename of " "hdlist>\n" " ftp://<host>/<path> with <relative filename of hdlist>\n" " http://<host>/<path> with <relative filename of hdlist>\n" " removable://<path>\n" "\n" "and [options] are from\n" msgstr "" "用法: urpmi.addmedia [選項] <名稱> <url> [with <相對路徑>]\n" "其中 <url> 是以下其中一項\n" " [file:/]/<路徑> with <hdlist 的相對檔案名稱>\n" " ftp://<登入名稱>:<密碼>@<主機名稱>/<路徑> with <hdlist 的相對檔案名" "稱>\n" " ftp://<主機名稱>/<路徑> with <hdlist 的相對檔案名稱>\n" " http://<主機名稱>/<路徑> with <hdlist 的相對檔案名稱>\n" " removable://<路徑>\n" "\n" "而 [選項] 來自\n" #: ../urpmi.addmedia:52 msgid " --update - create an update medium.\n" msgstr " --update - 建立更新的媒體。\n" #: ../urpmi.addmedia:53 msgid " --probe-synthesis - try to find and use synthesis file.\n" msgstr " --probe-synthesis - 嘗試尋找並使用 synthesis 檔案。\n" #: ../urpmi.addmedia:54 msgid " --probe-hdlist - try to find and use hdlist file.\n" msgstr " --probe-hdlist - 嘗試尋找並使用 hdlist 檔案。\n" #: ../urpmi.addmedia:55 msgid "" " --no-probe - do not try to find any synthesis or\n" " hdlist file.\n" msgstr " --no-probe - 不尋找任何 synthesis 或 hdlist 檔案。\n" #: ../urpmi.addmedia:57 msgid "" " --distrib - automatically create all media from an installation\n" " medium.\n" msgstr " --distrib - 自動根據安裝媒體建立所有的媒體。\n" #: ../urpmi.addmedia:59 #, c-format msgid "" " --from - use specified url for list of mirrors, the default is\n" " %s\n" msgstr "" " --from - 使用指定的 URL 取得映射站台清單,預設為\n" " %s\n" #: ../urpmi.addmedia:61 msgid "" " --virtual - create virtual media wich are always up-to-date,\n" " only file:// protocol is allowed.\n" msgstr "" " --virtual - 建立長保持於最新狀態的虛擬媒體,僅接受 file:// \n" " 通訊協定。\n" #: ../urpmi.addmedia:63 ../urpmi.update:40 msgid " --no-md5sum - disable MD5SUM file checking.\n" msgstr " --no-md5sum - 不使用 MD5SUM 檔案檢查功能。\n" #: ../urpmi.addmedia:65 msgid " --nopubkey - don't import pubkey of added media\n" msgstr " --nopubkey - 不匯入新增的媒體的公鑰\n" #: ../urpmi.addmedia:66 msgid " --raw - add the media in config, but don't update it.\n" msgstr " --raw - 加入這個媒介到設定檔中,但不更新它。\n" #: ../urpmi.addmedia:67 ../urpmi.removemedia:56 ../urpmi.update:46 msgid " -c - clean headers cache directory.\n" msgstr " -c - 清除標頭快取目錄。\n" #: ../urpmi.addmedia:68 ../urpmi.update:47 msgid " -f - force generation of hdlist files.\n" msgstr " -f - 強制產生 hdlist 檔案。\n" #: ../urpmi.addmedia:80 #, c-format msgid "unable to update medium \"%s\"\n" msgstr "無法更新媒體 \"%s\"\n" #: ../urpmi.addmedia:113 msgid "Only superuser is allowed to add media" msgstr "只有管理者才能新增媒體" #: ../urpmi.addmedia:116 #, c-format msgid "Will create config file [%s]" msgstr "將建立設定檔 [%s]" #: ../urpmi.addmedia:117 #, c-format msgid "Can't create config file [%s]" msgstr "無法建立設定檔 [%s]" #: ../urpmi.addmedia:124 msgid "no need to give <relative path of hdlist> with --distrib" msgstr "使用 --distrib 參數時不需給予 <hdlist 檔案的相對路徑>" #: ../urpmi.addmedia:134 msgid "<relative path of hdlist> missing\n" msgstr "<hdlist 檔案的相對路徑> 遺失\n" #: ../urpmi.addmedia:136 msgid "`with' missing for network media\n" msgstr "使用網路媒體時遺漏了 `with'\n" #: ../urpmi.addmedia:153 #, c-format msgid "unable to create medium \"%s\"\n" msgstr "無法建立媒體 \"%s\"\n" #: ../urpmi.recover:26 #, c-format msgid "" "urpmi.recover version %s\n" "Copyright (C) 2006 Mandriva.\n" "This is free software and may be redistributed under the terms of the GNU " "GPL.\n" "\n" "usage:\n" msgstr "" "urpmi.recover 版本號 %s\n" "Copyright (C) 2006 Mandriva。\n" "這是自由軟體並可於 GNU GPL 條款下重新散佈。\n" "\n" "用法:\n" #: ../urpmi.recover:32 msgid " --checkpoint - set repackaging start now\n" msgstr " --checkpoint - 設定現在開始重新打包\n" #: ../urpmi.recover:33 msgid " --noclean - don't clean repackage directory on checkpoint\n" msgstr " --noclean - 不清除檢查點的重新打包目錄。\n" #: ../urpmi.recover:34 msgid "" " --list - list transactions since provided date/duration argument\n" msgstr "" " --list - 列出給定的日期至今或給定的期間內的交易\n" #: ../urpmi.recover:35 msgid " --list-all - list all transactions in rpmdb (long)\n" msgstr " --list-all - 列出 rpmdb 中的所有交易 (long)。\n" #: ../urpmi.recover:36 msgid "" " --rollback - rollback until specified date,\n" " or rollback the specified number of transactions\n" msgstr "" " --rollback - 回復到特定的日期,或者回復特定的交易\n" #: ../urpmi.recover:52 #, c-format msgid "Invalid date or duration [%s]\n" msgstr "錯誤的日期或期間 [%s]\n" #: ../urpmi.recover:62 #, c-format msgid "Spurious command-line arguments [%s]\n" msgstr "" #: ../urpmi.recover:64 msgid "You can't specify --checkpoint and --rollback at the same time\n" msgstr "您不能同時指定 --checkpoint 以及 --rollback\n" #: ../urpmi.recover:66 msgid "You can't specify --checkpoint and --list at the same time\n" msgstr "您不能同時指定 --checkpoint 以及 --list\n" #: ../urpmi.recover:68 msgid "You can't specify --rollback and --list at the same time\n" msgstr "您不能同時指定 --rollback 以及 --list\n" #: ../urpmi.recover:90 #, c-format msgid "No transaction found since %s\n" msgstr "從 %s 至今沒有找到任何交易\n" #. - check we're running as root #: ../urpmi.recover:105 msgid "You must be superuser to do this" msgstr "您必須是超級使用者才能執行" #: ../urpmi.recover:114 msgid "Repackage directory not defined\n" msgstr "沒有定義重新打包目錄\n" #: ../urpmi.recover:117 #, c-format msgid "Can't write to repackage directory [%s]\n" msgstr "無法寫入重新打包目錄 [%s]\n" #: ../urpmi.recover:122 #, c-format msgid "Cleaning up repackage directory [%s]...\n" msgstr "正在清除重新打包目錄 [%s]...\n" #: ../urpmi.recover:124 #, c-format msgid "%d files removed\n" msgstr "移除了 %d 個檔案\n" #. - write rpm config file #: ../urpmi.recover:128 #, c-format msgid "Writing rpm macros file [%s]...\n" msgstr "正在寫入 rpm 巨集檔 [%s]...\n" #: ../urpmi.recover:170 msgid "No rollback date found\n" msgstr "沒有找到回復日期\n" #: ../urpmi.recover:173 #, c-format msgid "Rollback until %s...\n" msgstr "回復到 %s...\n" #: ../urpmi.removemedia:52 msgid "" "usage: urpmi.removemedia [-a] <name> ...\n" "where <name> is a medium name to remove.\n" msgstr "" "用法:urpmi.removemedia [-a] <名稱> ...\n" "其中 <名稱> 是要移除的媒體名稱。\n" #: ../urpmi.removemedia:55 msgid " -a - select all media.\n" msgstr " -a - 選擇全部的媒體。\n" #: ../urpmi.removemedia:57 msgid " -y - fuzzy match on media names.\n" msgstr " -y - 對媒體名稱進行模糊比對。\n" #: ../urpmi.removemedia:60 #, c-format msgid "" "\n" "unknown options '%s'\n" msgstr "" "\n" "未知的選項 '%s'\n" #: ../urpmi.removemedia:70 msgid "Only superuser is allowed to remove media" msgstr "只有管理者才可以移除媒體" #: ../urpmi.removemedia:81 msgid "nothing to remove (use urpmi.addmedia to add a media)\n" msgstr "沒有東西可以移除 (使用 urpmi.addmedia 來新增一個媒體)\n" #: ../urpmi.removemedia:83 #, c-format msgid "" "the entry to remove is missing\n" "(one of %s)\n" msgstr "" "要移除的項目遺失\n" "(%s 的其中之一)\n" #: ../urpmi.update:29 msgid "" "usage: urpmi.update [options] <name> ...\n" "where <name> is a medium name to update.\n" msgstr "" "用法:urpmi.update [選項] <名稱> ...\n" "其中 <名稱> 為要更新的媒體名稱。\n" #: ../urpmi.update:39 msgid " --update - update only update media.\n" msgstr " --update - 只更新更新的媒體。\n" #: ../urpmi.update:41 msgid " --force-key - force update of gpg key.\n" msgstr " --force-key - 強制更新 gpg 鑰匙。\n" #: ../urpmi.update:43 msgid " --ignore - don't update, mark the media as ignored.\n" msgstr " --ignore - 不更新,並標示此媒體為略過。\n" #: ../urpmi.update:44 msgid " --no-ignore - don't update, mark the media as enabled.\n" msgstr " --no-ignore - 不更新,並將此媒體標示為啟用。\n" #: ../urpmi.update:45 msgid " -a - select all non-removable media.\n" msgstr " -a - 選擇所有不可移除式媒體。\n" #: ../urpmi.update:68 msgid "Only superuser is allowed to update media" msgstr "只有管理者才能跟新媒體" #: ../urpmi.update:76 msgid "nothing to update (use urpmi.addmedia to add a media)\n" msgstr "沒有東西可供更新 (使用 urpmi.addmedia 以新增一個媒體)\n" #: ../urpmi.update:94 #, c-format msgid "" "the entry to update is missing\n" "(one of %s)\n" msgstr "" "要更新的項目遺失\n" "(%s 的其中之一)\n" #: ../urpmi.update:98 #, c-format msgid "\"%s\"" msgstr "\"%s\"" #: ../urpmi.update:99 #, c-format msgid "enabling media %s" msgstr "啟用媒體 %s" #: ../urpmi.update:99 #, c-format msgid "ignoring media %s" msgstr "略過媒體 %s" #: ../urpmq:39 #, c-format msgid "" "urpmq version %s\n" "Copyright (C) 2000-2006 Mandriva.\n" "This is free software and may be redistributed under the terms of the GNU " "GPL.\n" "\n" "usage:\n" msgstr "" "urpmq 版本號 %s\n" "Copyright (C) 2000-2006 Mandriva。\n" "這是自由軟體並可於 GNU GPL 條款下重新散佈。\n" "\n" "用法:\n" #: ../urpmq:47 msgid "" " --searchmedia - use only the given media to search requested (or updated) " "packages.\n" msgstr " --searchmedia - 只使用指定的媒體來搜尋或升級套件。\n" #: ../urpmq:52 msgid " --fuzzy - impose fuzzy search (same as -y).\n" msgstr " --fuzzy - 加上模糊搜尋 (與 -y 相同)。\n" #: ../urpmq:55 msgid " --list - list available packages.\n" msgstr " --list - 列出可用的的套件。\n" #: ../urpmq:56 msgid " --list-media - list available media.\n" msgstr " --list-media - 列出可用的媒體。\n" #: ../urpmq:57 msgid " --list-url - list available media and their url.\n" msgstr " --list-url - 列出可用的媒體與其 URL。\n" #: ../urpmq:58 msgid " --list-nodes - list available nodes when using --parallel.\n" msgstr " --list-nodes - 當使用 --parallel 選項時列出可用的節點。\n" #: ../urpmq:59 msgid " --list-aliases - list available parallel aliases.\n" msgstr " --list-aliases - 列出可用的同步管理別名。\n" #: ../urpmq:60 msgid "" " --dump-config - dump the config in form of urpmi.addmedia argument.\n" msgstr " --dump-config - 以 urpmi.addmedia 的參數形式的匯出設定值。\n" #: ../urpmq:61 msgid " --src - next package is a source package (same as -s).\n" msgstr " --src - 下個套件是原始碼套件 (與 -s 相同)。\n" #: ../urpmq:62 msgid "" " --sources - give all source packages before downloading (root only).\n" msgstr " --sources - 下載前先給予所有的原始碼套件 (僅供管理者使用).\n" #: ../urpmq:64 msgid " --ignorearch - allow to query rpms for unmatched architectures.\n" msgstr " --ignorearch - 允許查詢硬體架構不相符的 RPM 檔。\n" #: ../urpmq:66 msgid "" " --use-distrib - configure urpmi on the fly from a distrib tree.\n" " This permit to querying a distro.\n" msgstr "" " --use-distrib - 立即由一個散佈套件樹設定 urpmi。可用來查詢散佈\n" " 套件。\n" #: ../urpmq:75 msgid " --changelog - print changelog.\n" msgstr " --changelog - 顯示更新紀錄。\n" #: ../urpmq:76 msgid " --summary, -S - print summary.\n" msgstr " --summary, -S - 顯示摘要。\n" #: ../urpmq:78 msgid " -c - complete output with package to be removed.\n" msgstr " -c - 完整輸出要移除的套件。\n" #: ../urpmq:79 msgid " -d - extend query to package dependencies.\n" msgstr " -d - 延伸套件相依性的查詢。\n" #: ../urpmq:81 msgid " -g - print groups with name also.\n" msgstr " -g - 顯示群組名稱。\n" #: ../urpmq:82 msgid " -i - print useful information in human readable form.\n" msgstr " -i - 以人類可讀的形式顯示有用資訊。\n" #: ../urpmq:83 msgid " -l - list files in package.\n" msgstr " -l - 列出套件內包含的檔案。\n" #: ../urpmq:84 msgid "" " -P - do not search in provides to find package (default).\n" msgstr " -P - 不於 provides 中搜尋套件 (預設值)。\n" #: ../urpmq:85 msgid " -p - search in provides to find package.\n" msgstr " -p - 於 provides 中搜尋套件。\n" #: ../urpmq:86 msgid " -r - print version and release with name also.\n" msgstr " -r - 顯示名稱時一併顯示版本號與發行編號。\n" #: ../urpmq:87 msgid " -R - reverse search to what requires package.\n" msgstr " -R - 逆向搜尋何者需要此套件。\n" #: ../urpmq:88 msgid "" " -RR - extended reverse search (includes virtual packages).\n" msgstr " -RR - 進階逆向搜尋 (包含虛擬套件)。\n" #: ../urpmq:89 msgid " -s - next package is a source package (same as --src).\n" msgstr " -s - 下個套件是原始碼套件 (與 --src 相同)。\n" #: ../urpmq:90 msgid "" " -u - remove package if a more recent version is already " "installed.\n" msgstr " -u - 若已經安裝較新的版本則移除套件。\n" #: ../urpmq:92 msgid " -y - impose fuzzy search (same as --fuzzy).\n" msgstr " -y - 加上模糊搜尋 (與 --fuzzy 相同)。\n" #: ../urpmq:93 msgid " -Y - like -y, but forces to match case-insensitively.\n" msgstr " -Y - 類似 -y 參數,但強制比對大小寫。\n" #: ../urpmq:94 msgid " names or rpm files given on command line are queried.\n" msgstr " 查詢命令列給予的套件名稱或 RPM 檔案。\n" #: ../urpmq:170 msgid "--list-nodes can only be used with --parallel" msgstr "--list-nodes 參數只能夠配合 --parallel 參數一起使用" #: ../urpmq:327 #, c-format msgid "skipping media %s: no hdlist" msgstr "略過媒體 %s:沒有 hdlist 檔" #: ../urpmq:401 msgid "No filelist found\n" msgstr "沒有找到檔案列表\n" #: ../urpmq:413 msgid "No changelog found\n" msgstr "沒有找到更新紀錄\n" #~ msgid "Search" #~ msgstr "搜尋" #~ msgid "Is this OK?" #~ msgstr "這樣可以嗎?" #~ msgid "" #~ " --version - use specified distribution version, the default is " #~ "taken\n" #~ " from the version of the distribution told by the\n" #~ " installed mandriva-release package.\n" #~ msgstr "" #~ " --version - 使用指定的散佈套件版號,預設值決定於安裝於系統上的\n" #~ " mandriva-release 套件回報的散佈套件版本。\n" #~ msgid "" #~ " --arch - use specified architecture, the default is arch of\n" #~ " mandriva-release package installed.\n" #~ msgstr "" #~ " --arch - 使用指定的硬體平台,預設值決定於安裝於系統上的\n" #~ " mandriva-release 套件所使用的平台。\n" #~ msgid "" #~ " --headers - extract headers for package listed from urpmi db to\n" #~ " stdout (root only).\n" #~ msgstr "" #~ " --headers - 由 urpmi 資料庫中擷取套件標頭到標準輸出 (僅供管理者\n" #~ " 使用)。\n" #~ msgid "rpm2header utility not found, impossible to use the --header option" #~ msgstr "找不到 rpm2header 這個工具,無法使用 --header 這個選項" #~ msgid "" #~ "To satisfy dependencies, the following %d packages are going to be " #~ "installed (%d MB)" #~ msgstr "為了滿足相依性,下列的 %d 個套件 (%d MB) 將一併安裝" #~ msgid "installing %s\n" #~ msgstr "正在安裝 %s\n" #~ msgid "" #~ "Automatic installation of packages...\n" #~ "You requested installation of package %s\n" #~ msgstr "" #~ "自動化套件安裝...\n" #~ "您要求安裝的套件 %s\n" #~ msgid "%s: command not found\n" #~ msgstr "%s:找不到指令\n" #~ msgid "" #~ "Some package requested cannot be installed:\n" #~ "%s\n" #~ "Continue?" #~ msgstr "" #~ "某些要求的套件無法安裝:\n" #~ "%s\n" #~ "要繼續嗎?" #~ msgid "" #~ "The following packages have to be removed for others to be upgraded:\n" #~ "%s\n" #~ "Continue?" #~ msgstr "" #~ "下列套件必須移除以便升級其他的套件:\n" #~ "%s\n" #~ "要繼續嗎?" #~ msgid "md5sum mismatch" #~ msgstr "md5sum 不合" #~ msgid "" #~ "urpmf version %s\n" #~ "Copyright (C) 2002-2004 Mandriva.\n" #~ "This is free software and may be redistributed under the terms of the GNU " #~ "GPL.\n" #~ "\n" #~ "usage:\n" #~ msgstr "" #~ "urpmf 版本 %s\n" #~ "Copyright (C) 2002-2004 Mandriva。\n" #~ "這是自由軟體並可於 GNU GPL 條款下重新散佈。\n" #~ "\n" #~ "使用方式:\n" #~ msgid " --synthesis - use the synthesis given instead of urpmi db.\n" #~ msgstr " --synthesis - 使用給定的 synthesis 檔,而非 urpmi 資料庫。\n" #~ msgid "" #~ " --quiet - do not print tag name (default if no tag given on " #~ "command\n" #~ " line, incompatible with interactive mode).\n" #~ msgstr "" #~ " --quiet - 不顯示標籤名稱 (除非在命令列給定參數,否則此為預\n" #~ " 設值;此外本模式並不相容於互動模式)。\n" #~ msgid " --uniq - do not print identical lines.\n" #~ msgstr " --uniq - 不顯示相同的訊息。\n" #~ msgid " --all - print all tags.\n" #~ msgstr " --all - 顯示全部的標籤。\n" #~ msgid " --summary - print tag summary: summary.\n" #~ msgstr " --summary - 列印摘要標籤:摘要。\n" #~ msgid " --description - print tag description: description.\n" #~ msgstr " --description - 顯示描述標籤:描述。\n" #~ msgid " --buildhost - print tag buildhost: build host.\n" #~ msgstr " --buildhost - 顯示建立主機標籤:建立主機。\n" #~ msgid " --provides - print tag provides: all provides.\n" #~ msgstr " --provides - 顯示提供標籤:提供。\n" #~ msgid " --requires - print tag requires: all requires.\n" #~ msgstr " --requires - 顯示需要標籤:需要。\n" #~ msgid " --files - print tag files: all files.\n" #~ msgstr " --files - 顯示檔案標籤:檔案。\n" #~ msgid " --obsoletes - print tag obsoletes: all obsoletes.\n" #~ msgstr " --obsoletes - 顯示廢棄標籤:廢棄。\n" #~ msgid "" #~ " --env - use specific environment (typically a bug\n" #~ " report).\n" #~ msgstr " --env - 使用特定環境 (一般用於臭蟲回報)。\n" #~ msgid " -i - ignore case distinctions in every pattern.\n" #~ msgstr " -i - 忽略每個樣版中的大小寫差異。\n" #~ msgid "" #~ " -a - binary AND operator, true if both expression are " #~ "true.\n" #~ msgstr " -a - 二元 AND 運算子,若兩表示式皆真則其值為真。\n" #~ msgid "" #~ " -o - binary OR operator, true if one expression is true.\n" #~ msgstr " -o - 二元 OR 運算子,若表示式之一為真則其值為真。\n" #~ msgid " ! - unary NOT, true if expression is false.\n" #~ msgstr " ! - 一元 NOT 運算子,若表示式假則其值為真。\n" #~ msgid " ( - left parenthesis to open group expression.\n" #~ msgstr " ( - 左括弧用來表示一組表示式的開始。\n" #~ msgid " ) - right parenthesis to close group expression.\n" #~ msgstr " ) - 右括弧用來表示一組表示式的結束。\n" #~ msgid "" #~ "callback is:\n" #~ "%s\n" #~ msgstr "" #~ "回傳值:\n" #~ "%s\n" #~ msgid "" #~ "\n" #~ "Continue?" #~ msgstr "" #~ "\n" #~ "要繼續嗎?" #~ msgid "" #~ "Some package requested cannot be installed:\n" #~ "%s" #~ msgstr "" #~ "某些要求的套件無法安裝:\n" #~ "%s"