Browse Source

Plan 9 from Bell Labs 2004-11-23

David du Colombier 19 years ago
parent
commit
aa3d6a51f5

+ 19 - 13
dist/replica/_plan9.db

@@ -433,7 +433,7 @@
 386/bin/upas/bayes - 775 sys sys 1064598344 70530
 386/bin/upas/deliver - 775 sys sys 1085077111 97777
 386/bin/upas/filter - 775 sys sys 1085077111 145300
-386/bin/upas/fs - 775 sys sys 1089397320 329933
+386/bin/upas/fs - 775 sys sys 1101154538 330331
 386/bin/upas/isspam - 775 sys sys 1064598349 38
 386/bin/upas/list - 775 sys sys 1085077112 80758
 386/bin/upas/marshal - 775 sys sys 1089397321 130452
@@ -2980,7 +2980,7 @@ rc/bin/B - 775 sys sys 945617206 645
 rc/bin/C - 775 sys sys 1045493437 788
 rc/bin/Kill - 775 sys sys 1018637942 115
 rc/bin/a: - 775 sys sys 1063856406 255
-rc/bin/ap - 775 sys sys 1101043629 661
+rc/bin/ap - 775 sys sys 1101132631 734
 rc/bin/ape - 20000000775 sys sys 954039414 0
 rc/bin/ape/ar89 - 775 sys sys 945617285 308
 rc/bin/ape/c89 - 775 sys sys 945617285 39
@@ -4881,7 +4881,7 @@ sys/man/2/isalpharune - 664 sys sys 1015091523 1059
 sys/man/2/keyboard - 664 sys sys 950892860 2065
 sys/man/2/lock - 664 sys sys 1048643958 4692
 sys/man/2/mach - 664 sys sys 1080179298 7995
-sys/man/2/malloc - 664 sys sys 1032238537 4397
+sys/man/2/malloc - 664 sys sys 1101135773 4375
 sys/man/2/matrix - 664 sys sys 950892861 6090
 sys/man/2/memdraw - 664 sys sys 1040484074 10144
 sys/man/2/memlayer - 664 sys sys 1040484074 6963
@@ -6918,18 +6918,18 @@ sys/src/cmd/auth/rsagen.c - 664 sys sys 1048614963 992
 sys/src/cmd/auth/secstore - 20000000775 sys sys 1017337838 0
 sys/src/cmd/auth/secstore/SConn.c - 664 sys sys 1064789003 4419
 sys/src/cmd/auth/secstore/SConn.h - 664 sys sys 1015008431 955
-sys/src/cmd/auth/secstore/aescbc.c - 664 sys sys 1087829615 4175
+sys/src/cmd/auth/secstore/aescbc.c - 664 sys sys 1101135279 4332
 sys/src/cmd/auth/secstore/dirls.c - 664 sys sys 1062277640 1842
 sys/src/cmd/auth/secstore/mkfile - 664 sys sys 1048615193 844
-sys/src/cmd/auth/secstore/pak.c - 664 sys sys 1062277640 9297
+sys/src/cmd/auth/secstore/pak.c - 664 sys sys 1101135278 9290
 sys/src/cmd/auth/secstore/password.c - 664 sys sys 1062277640 2770
 sys/src/cmd/auth/secstore/secacct.c - 644 sys sys 1015008431 755
 sys/src/cmd/auth/secstore/secchk.c - 664 sys sys 1055698993 560
-sys/src/cmd/auth/secstore/secstore.c - 664 sys sys 1062277640 12269
-sys/src/cmd/auth/secstore/secstore.h - 664 sys sys 1041890053 841
+sys/src/cmd/auth/secstore/secstore.c - 664 sys sys 1101135279 12528
+sys/src/cmd/auth/secstore/secstore.h - 664 sys sys 1101135279 829
 sys/src/cmd/auth/secstore/secstored.c - 664 sys sys 1089058000 8328
-sys/src/cmd/auth/secstore/secuser.c - 664 sys sys 1064667494 4971
-sys/src/cmd/auth/secstore/util.c - 664 sys sys 1021579985 1498
+sys/src/cmd/auth/secstore/secuser.c - 664 sys sys 1101135279 5122
+sys/src/cmd/auth/secstore/util.c - 664 sys sys 1101135279 1477
 sys/src/cmd/auth/secureidcheck.c - 664 sys sys 1078840013 9007
 sys/src/cmd/auth/status - 775 sys sys 1015008430 738
 sys/src/cmd/auth/uniq.c - 664 sys sys 1015008430 1429
@@ -9424,15 +9424,15 @@ sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 956275654 1881
 sys/src/cmd/ip/dhcpd/testlook.c - 664 sys sys 950389140 4640
 sys/src/cmd/ip/dhcpd/testlookup.c - 664 sys sys 950389140 3195
 sys/src/cmd/ip/dhcpd/testping.c - 664 sys sys 950389141 352
-sys/src/cmd/ip/ftpd.c - 664 sys sys 1095862384 32934
+sys/src/cmd/ip/ftpd.c - 664 sys sys 1101155057 33054
 sys/src/cmd/ip/ftpfs - 20000000775 sys sys 1014925642 0
 sys/src/cmd/ip/ftpfs/file.c - 664 sys sys 1014925642 4208
 sys/src/cmd/ip/ftpfs/ftpfs.c - 664 sys sys 1093452873 13584
 sys/src/cmd/ip/ftpfs/ftpfs.h - 664 sys sys 1091904423 2353
 sys/src/cmd/ip/ftpfs/mkfile - 664 sys sys 1048312050 173
 sys/src/cmd/ip/ftpfs/proto.c - 664 sys sys 1089920400 29348
-sys/src/cmd/ip/glob.c - 664 sys sys 1015013111 2968
-sys/src/cmd/ip/glob.h - 664 sys sys 1015090252 270
+sys/src/cmd/ip/glob.c - 664 sys sys 1101155057 3290
+sys/src/cmd/ip/glob.h - 664 sys sys 1101155058 308
 sys/src/cmd/ip/gping.c - 664 sys sys 1015013112 20476
 sys/src/cmd/ip/hogports.c - 664 sys sys 988225294 987
 sys/src/cmd/ip/httpd - 20000000775 sys sys 1016902735 0
@@ -10846,7 +10846,7 @@ sys/src/cmd/upas/fs/imap4.c - 664 sys sys 1075069146 16233
 sys/src/cmd/upas/fs/mbox.c - 664 sys sys 1071334860 28493
 sys/src/cmd/upas/fs/mkfile - 664 sys sys 1047490336 321
 sys/src/cmd/upas/fs/plan9.c - 664 sys sys 1071334861 7465
-sys/src/cmd/upas/fs/pop3.c - 664 sys sys 1080159334 12445
+sys/src/cmd/upas/fs/pop3.c - 664 sys sys 1101154341 12864
 sys/src/cmd/upas/fs/readdir.c - 664 sys sys 944961331 203
 sys/src/cmd/upas/fs/strtotm.c - 664 sys sys 1041137528 1904
 sys/src/cmd/upas/fs/tester.c - 664 sys sys 985037420 1418
@@ -12394,3 +12394,9 @@ usr/glenda/lib/profile - 664 glenda glenda 1021580005 847
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
+386/bin/auth/aescbc - 775 sys sys 1101182919 131188
+386/bin/auth/secstore - 775 sys sys 1101182919 187191
+386/bin/auth/secstored - 775 sys sys 1101182920 194586
+386/bin/auth/secuser - 775 sys sys 1101182920 150251
+386/bin/ip/ftpd - 775 sys sys 1101182921 166228
+386/bin/upas/fs - 775 sys sys 1101182921 330315

+ 18 - 18
dist/replica/plan9.db

@@ -43,7 +43,7 @@
 386/bin/ascii - 775 sys sys 1085076975 62654
 386/bin/astro - 775 sys sys 1085076975 138775
 386/bin/auth - 20000000775 sys sys 1016920815 0
-386/bin/auth/aescbc - 775 sys sys 1087873349 131000
+386/bin/auth/aescbc - 775 sys sys 1101182919 131188
 386/bin/auth/asn12rsa - 775 sys sys 1085076976 119140
 386/bin/auth/authsrv - 775 sys sys 1089257526 163370
 386/bin/auth/changeuser - 775 sys sys 1085076977 94911
@@ -71,9 +71,9 @@
 386/bin/auth/rsafill - 775 sys sys 1085076984 142998
 386/bin/auth/rsagen - 775 sys sys 1085076985 152588
 386/bin/auth/secretpem - 775 sys sys 1045537944 118526
-386/bin/auth/secstore - 775 sys sys 1085076985 188566
-386/bin/auth/secstored - 775 sys sys 1089257528 194770
-386/bin/auth/secuser - 775 sys sys 1085076986 151623
+386/bin/auth/secstore - 775 sys sys 1101182919 187191
+386/bin/auth/secstored - 775 sys sys 1101182920 194586
+386/bin/auth/secuser - 775 sys sys 1101182920 150251
 386/bin/auth/status - 775 sys sys 1020319060 738
 386/bin/auth/uniq - 775 sys sys 1085076986 61081
 386/bin/auth/warning - 775 sys sys 1085076987 97534
@@ -268,7 +268,7 @@
 386/bin/ip/dhcpclient - 775 sys sys 1089257531 92091
 386/bin/ip/dhcpd - 775 sys sys 1089257532 147194
 386/bin/ip/dhcpleases - 775 sys sys 1089257532 84202
-386/bin/ip/ftpd - 775 sys sys 1095910154 166038
+386/bin/ip/ftpd - 775 sys sys 1101182921 166228
 386/bin/ip/gizzard - 775 sys sys 1081480408 101521
 386/bin/ip/gping - 775 sys sys 1098158507 179977
 386/bin/ip/hogports - 775 sys sys 1085077067 42855
@@ -433,7 +433,7 @@
 386/bin/upas/bayes - 775 sys sys 1064598344 70530
 386/bin/upas/deliver - 775 sys sys 1085077111 97777
 386/bin/upas/filter - 775 sys sys 1085077111 145300
-386/bin/upas/fs - 775 sys sys 1089397320 329933
+386/bin/upas/fs - 775 sys sys 1101182921 330315
 386/bin/upas/isspam - 775 sys sys 1064598349 38
 386/bin/upas/list - 775 sys sys 1085077112 80758
 386/bin/upas/marshal - 775 sys sys 1089397321 130452
@@ -2980,7 +2980,7 @@ rc/bin/B - 775 sys sys 945617206 645
 rc/bin/C - 775 sys sys 1045493437 788
 rc/bin/Kill - 775 sys sys 1018637942 115
 rc/bin/a: - 775 sys sys 1063856406 255
-rc/bin/ap - 775 sys sys 1101043629 661
+rc/bin/ap - 775 sys sys 1101132631 734
 rc/bin/ape - 20000000775 sys sys 954039414 0
 rc/bin/ape/ar89 - 775 sys sys 945617285 308
 rc/bin/ape/c89 - 775 sys sys 945617285 39
@@ -4881,7 +4881,7 @@ sys/man/2/isalpharune - 664 sys sys 1015091523 1059
 sys/man/2/keyboard - 664 sys sys 950892860 2065
 sys/man/2/lock - 664 sys sys 1048643958 4692
 sys/man/2/mach - 664 sys sys 1080179298 7995
-sys/man/2/malloc - 664 sys sys 1032238537 4397
+sys/man/2/malloc - 664 sys sys 1101135773 4375
 sys/man/2/matrix - 664 sys sys 950892861 6090
 sys/man/2/memdraw - 664 sys sys 1040484074 10144
 sys/man/2/memlayer - 664 sys sys 1040484074 6963
@@ -6918,18 +6918,18 @@ sys/src/cmd/auth/rsagen.c - 664 sys sys 1048614963 992
 sys/src/cmd/auth/secstore - 20000000775 sys sys 1017337838 0
 sys/src/cmd/auth/secstore/SConn.c - 664 sys sys 1064789003 4419
 sys/src/cmd/auth/secstore/SConn.h - 664 sys sys 1015008431 955
-sys/src/cmd/auth/secstore/aescbc.c - 664 sys sys 1087829615 4175
+sys/src/cmd/auth/secstore/aescbc.c - 664 sys sys 1101135279 4332
 sys/src/cmd/auth/secstore/dirls.c - 664 sys sys 1062277640 1842
 sys/src/cmd/auth/secstore/mkfile - 664 sys sys 1048615193 844
-sys/src/cmd/auth/secstore/pak.c - 664 sys sys 1062277640 9297
+sys/src/cmd/auth/secstore/pak.c - 664 sys sys 1101135278 9290
 sys/src/cmd/auth/secstore/password.c - 664 sys sys 1062277640 2770
 sys/src/cmd/auth/secstore/secacct.c - 644 sys sys 1015008431 755
 sys/src/cmd/auth/secstore/secchk.c - 664 sys sys 1055698993 560
-sys/src/cmd/auth/secstore/secstore.c - 664 sys sys 1062277640 12269
-sys/src/cmd/auth/secstore/secstore.h - 664 sys sys 1041890053 841
+sys/src/cmd/auth/secstore/secstore.c - 664 sys sys 1101135279 12528
+sys/src/cmd/auth/secstore/secstore.h - 664 sys sys 1101135279 829
 sys/src/cmd/auth/secstore/secstored.c - 664 sys sys 1089058000 8328
-sys/src/cmd/auth/secstore/secuser.c - 664 sys sys 1064667494 4971
-sys/src/cmd/auth/secstore/util.c - 664 sys sys 1021579985 1498
+sys/src/cmd/auth/secstore/secuser.c - 664 sys sys 1101135279 5122
+sys/src/cmd/auth/secstore/util.c - 664 sys sys 1101135279 1477
 sys/src/cmd/auth/secureidcheck.c - 664 sys sys 1078840013 9007
 sys/src/cmd/auth/status - 775 sys sys 1015008430 738
 sys/src/cmd/auth/uniq.c - 664 sys sys 1015008430 1429
@@ -9424,15 +9424,15 @@ sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 956275654 1881
 sys/src/cmd/ip/dhcpd/testlook.c - 664 sys sys 950389140 4640
 sys/src/cmd/ip/dhcpd/testlookup.c - 664 sys sys 950389140 3195
 sys/src/cmd/ip/dhcpd/testping.c - 664 sys sys 950389141 352
-sys/src/cmd/ip/ftpd.c - 664 sys sys 1095862384 32934
+sys/src/cmd/ip/ftpd.c - 664 sys sys 1101155057 33054
 sys/src/cmd/ip/ftpfs - 20000000775 sys sys 1014925642 0
 sys/src/cmd/ip/ftpfs/file.c - 664 sys sys 1014925642 4208
 sys/src/cmd/ip/ftpfs/ftpfs.c - 664 sys sys 1093452873 13584
 sys/src/cmd/ip/ftpfs/ftpfs.h - 664 sys sys 1091904423 2353
 sys/src/cmd/ip/ftpfs/mkfile - 664 sys sys 1048312050 173
 sys/src/cmd/ip/ftpfs/proto.c - 664 sys sys 1089920400 29348
-sys/src/cmd/ip/glob.c - 664 sys sys 1015013111 2968
-sys/src/cmd/ip/glob.h - 664 sys sys 1015090252 270
+sys/src/cmd/ip/glob.c - 664 sys sys 1101155057 3290
+sys/src/cmd/ip/glob.h - 664 sys sys 1101155058 308
 sys/src/cmd/ip/gping.c - 664 sys sys 1015013112 20476
 sys/src/cmd/ip/hogports.c - 664 sys sys 988225294 987
 sys/src/cmd/ip/httpd - 20000000775 sys sys 1016902735 0
@@ -10846,7 +10846,7 @@ sys/src/cmd/upas/fs/imap4.c - 664 sys sys 1075069146 16233
 sys/src/cmd/upas/fs/mbox.c - 664 sys sys 1071334860 28493
 sys/src/cmd/upas/fs/mkfile - 664 sys sys 1047490336 321
 sys/src/cmd/upas/fs/plan9.c - 664 sys sys 1071334861 7465
-sys/src/cmd/upas/fs/pop3.c - 664 sys sys 1080159334 12445
+sys/src/cmd/upas/fs/pop3.c - 664 sys sys 1101154341 12864
 sys/src/cmd/upas/fs/readdir.c - 664 sys sys 944961331 203
 sys/src/cmd/upas/fs/strtotm.c - 664 sys sys 1041137528 1904
 sys/src/cmd/upas/fs/tester.c - 664 sys sys 985037420 1418

+ 19 - 0
dist/replica/plan9.log

@@ -17089,3 +17089,22 @@
 1100964641 0 c sys/src/cmd/sed.c - 664 sys sys 1100962924 27001
 1101011450 0 c 386/bin/sed - 775 sys sys 1101010294 87484
 1101043856 0 c rc/bin/ap - 775 sys sys 1101043629 661
+1101133873 0 c rc/bin/ap - 775 sys sys 1101132631 734
+1101135674 0 c sys/src/cmd/auth/secstore/aescbc.c - 664 sys sys 1101135279 4332
+1101135674 1 c sys/src/cmd/auth/secstore/pak.c - 664 sys sys 1101135278 9290
+1101135674 2 c sys/src/cmd/auth/secstore/secstore.c - 664 sys sys 1101135279 12528
+1101135674 3 c sys/src/cmd/auth/secstore/secstore.h - 664 sys sys 1101135279 829
+1101135674 4 c sys/src/cmd/auth/secstore/secuser.c - 664 sys sys 1101135279 5122
+1101135674 5 c sys/src/cmd/auth/secstore/util.c - 664 sys sys 1101135279 1477
+1101137474 0 c sys/man/2/malloc - 664 sys sys 1101135773 4375
+1101154900 0 c 386/bin/upas/fs - 775 sys sys 1101154538 330331
+1101154900 1 c sys/src/cmd/upas/fs/pop3.c - 664 sys sys 1101154341 12864
+1101155477 0 c sys/src/cmd/ip/ftpd.c - 664 sys sys 1101155057 33054
+1101155477 1 c sys/src/cmd/ip/glob.c - 664 sys sys 1101155057 3290
+1101155477 2 c sys/src/cmd/ip/glob.h - 664 sys sys 1101155058 308
+1101184282 0 c 386/bin/auth/aescbc - 775 sys sys 1101182919 131188
+1101184282 1 c 386/bin/auth/secstore - 775 sys sys 1101182919 187191
+1101184282 2 c 386/bin/auth/secstored - 775 sys sys 1101182920 194586
+1101184282 3 c 386/bin/auth/secuser - 775 sys sys 1101182920 150251
+1101184282 4 c 386/bin/ip/ftpd - 775 sys sys 1101182921 166228
+1101184282 5 c 386/bin/upas/fs - 775 sys sys 1101182921 330315

+ 6 - 3
rc/bin/ap

@@ -14,6 +14,7 @@ if ( ~ $#* 0 )
 				s/^• / /g
 				s/\n/ /g
 				s/\[\/news\/nationworld\/wire\//|/
+				s/sns-ap-//
 				s/,[0-9]+,[0-9]+\.story.*$//
 				p
 		}' |
@@ -26,12 +27,14 @@ if ( ~ $#* 0 )
 		}'
 
 if not
-	hget $wire/^$1^.story |
+	hget $wire/sns-ap-^$1^.story |
 		htmlfmt |
 		sed '
 			s/\| Article licensing.*$//
 			/^Copyright ©/p
 			/^Copyright ©/,$d
+			/^Subscribe to Newsday/d
 			1,/^Top Stories$/d
-			/^$/,/^$/d
-		'
+			s/[ 	]*$//
+			s/^\* __$//
+		' #| fmt

+ 2 - 2
sys/man/2/malloc

@@ -29,13 +29,13 @@ ulong	msize(void *ptr)
 void	setmalloctag(void *ptr, ulong tag)
 .PP
 .B
-ulong	getmalloctag(void *ptr, ulong tag)
+ulong	getmalloctag(void *ptr)
 .PP
 .B
 void	setrealloctag(void *ptr, ulong tag)
 .PP
 .B
-ulong	getrealloctag(void *ptr, ulong tag)
+ulong	getrealloctag(void *ptr)
 .PP
 .B
 void*	malloctopoolblock(void*)

+ 11 - 3
sys/src/cmd/auth/secstore/aescbc.c

@@ -11,7 +11,7 @@
 #include <libsec.h>
 #include <authsrv.h>
 
-int getpasswd(char*, char*, int);
+extern char* getpass(char*);
 
 enum{ CHK = 16, BUF = 4096 };
 
@@ -41,11 +41,12 @@ saferead(uchar *buf, int n)
 	exits("read error");
 }
 
-void
+int
 main(int argc, char **argv)
 {
 	int encrypt = 0;  /* 0=decrypt, 1=encrypt */
 	int n, nkey, pass_stdin = 0, pass_nvram = 0;
+	char *pass;
 	uchar key[AESmaxkey], key2[SHA1dlen];
 	uchar buf[BUF+SHA1dlen];    /* assumption: CHK <= SHA1dlen */
 	AESstate aes;
@@ -84,7 +85,13 @@ main(int argc, char **argv)
 		strecpy((char*)buf, (char*)buf+sizeof buf, (char*)nvr.config);
 		n = strlen((char*)buf);
 	}else{
-		n = getpasswd("password:", (char*)buf, sizeof buf);
+		pass = getpass("aescbc key:");
+		n = strlen(pass);
+		if(n >= BUF)
+			exits("key too long");
+		strcpy((char*)buf, pass);
+		memset(pass, 0, n);
+		free(pass);
 	}
 	if(n <= 0){
 		fprint(2,"no key\n");
@@ -155,4 +162,5 @@ main(int argc, char **argv)
 		}
 	}
 	exits("");
+	return 1;  /* keep  other compilers happy */
 }

+ 1 - 1
sys/src/cmd/auth/secstore/pak.c

@@ -10,7 +10,7 @@
 
 extern int verbose;
 
-extern char VERSION[] = "secstore";
+char VERSION[] = "secstore";
 static char *feedback[] = {"alpha","bravo","charlie","delta","echo","foxtrot","golf","hotel"};
 
 typedef struct PAKparams{

+ 24 - 12
sys/src/cmd/auth/secstore/secstore.c

@@ -302,33 +302,34 @@ chpasswd(AuthConn *c, char *id)
 	int rv = -1, newpasslen = 0;
 	mpint *H, *Hi;
 	uchar *memfile;
-	char *newpass = nil;
+	char *newpass, *passck;
 	char *list, *cur, *next, *hexHi;
-	char *f[8], prompt[128], buf[Maxmsg];
+	char *f[8], prompt[128];
 
 	H = mpnew(0);
 	Hi = mpnew(0);
 	// changing our password is vulnerable to connection failure
 	for(;;){
 		snprint(prompt, sizeof(prompt), "new password for %s: ", id);
-		if(getpasswd(prompt, buf, sizeof(buf)) < 0)
+		newpass = getpass(prompt);
+		if(newpass == nil)
 			goto Out;
-		if(strlen(buf) >= 7)
+		if(strlen(newpass) >= 7)
 			break;
-		else if(strlen(buf) == 0){
+		else if(strlen(newpass) == 0){
 			fprint(2, "!password change aborted\n");
 			goto Out;
 		}
 		print("!password must be at least 7 characters\n");
 	}
-	newpass = estrdup(buf);
 	newpasslen = strlen(newpass);
 	snprint(prompt, sizeof(prompt), "retype password: ");
-	if(getpasswd(prompt, buf, sizeof(buf)) < 0){
+	passck = getpass(prompt);
+	if(passck == nil){
 		fprint(2, "getpasswd failed\n");
 		goto Out;
 	}
-	if(strcmp(buf, newpass) != 0){
+	if(strcmp(passck, newpass) != 0){
 		fprint(2, "passwords didn't match\n");
 		goto Out;
 	}
@@ -377,7 +378,7 @@ login(char *id, char *dest, int pass_stdin, int pass_nvram)
 {
 	AuthConn *c;
 	int fd, n, ntry = 0;
-	char *S, *PINSTA = nil, *nl, s[Maxmsg+1];
+	char *S, *PINSTA = nil, *nl, s[Maxmsg+1], *pass;
 
 	if(dest == nil){
 		fprint(2, "tried to login with nil dest\n");
@@ -417,8 +418,16 @@ login(char *id, char *dest, int pass_stdin, int pass_nvram)
 			return nil;
 		}
 		ntry++;
-		if(!pass_stdin && !pass_nvram)
-			getpasswd("secstore password: ", c->pass, sizeof c->pass);
+		if(!pass_stdin && !pass_nvram){
+			pass = getpass("secstore password: ");
+			if(strlen(pass) >= sizeof c->pass){
+				fprint(2, "password too long, skipping secstore login\n");
+				exits("password too long");
+			}
+			strcpy(c->pass, pass);
+			memset(pass, 0, strlen(pass));
+			free(pass);
+		}
 		if(c->pass[0]==0){
 			fprint(2, "null password, skipping secstore login\n");
 			exits("no password");
@@ -451,7 +460,10 @@ login(char *id, char *dest, int pass_stdin, int pass_nvram)
 				exits("missing PIN+SecureID on standard input");
 			free(PINSTA);
 		}else{
-			getpasswd("STA PIN+SecureID: ", s+3, (sizeof s)-3);
+			pass = getpass("STA PIN+SecureID: ");
+			strncpy(s+3, pass, (sizeof s)-4);
+			memset(pass, 0, strlen(pass));
+			free(pass);
 		}
 		sn = strlen(s+3);
 		if(verbose)

+ 1 - 1
sys/src/cmd/auth/secstore/secstore.h

@@ -17,7 +17,7 @@ typedef struct PW {
 PW *getPW(char *, int);
 int putPW(PW *);
 void freePW(PW *);
-int getpasswd(char*, char*, int);
+char* getpass(char*);
 
 // *client: SConn, client name, passphrase
 // *server: SConn, (partial) 1st msg, PW entry

+ 18 - 10
sys/src/cmd/auth/secstore/secuser.c

@@ -27,11 +27,12 @@ ensure_exists(char *f, ulong perm)
 }
 
 
-void
+int
 main(int argc, char **argv)
 {
 	int isnew;
-	char *id, buf[Maxmsg], passck[Maxmsg], home[Maxmsg], prompt[100], *hexHi;
+	char *id, buf[Maxmsg], home[Maxmsg], prompt[100], *hexHi;
+	char *pass, *passck;
 	long expsecs;
 	mpint *H = mpnew(0), *Hi = mpnew(0);
 	PW *pw;
@@ -76,32 +77,38 @@ main(int argc, char **argv)
 			snprint(prompt, sizeof(prompt), "%s password: ", id);
 		else
 			snprint(prompt, sizeof(prompt), "%s password [default = don't change]: ", id);
-		if(getpasswd(prompt, buf, sizeof(buf)) < 0){
+		pass = getpass(prompt);
+		if(pass == nil){
 			print("getpass failed\n");
 			exits("getpass failed");
 		}
 		if(verbose)
-			print("%ld characters\n", strlen(buf));
-		if(buf[0] == '\0' && isnew == 0)
+			print("%ld characters\n", strlen(pass));
+		if(pass[0] == '\0' && isnew == 0)
 			break;
-		if(strlen(buf) >= 7)
+		if(strlen(pass) >= 7)
 			break;
 		print("password must be at least 7 characters\n");
 	}
 
-	if(buf[0] != '\0'){
+	if(pass[0] != '\0'){
 		snprint(prompt, sizeof(prompt), "retype password: ");
 		if(verbose)
 			print("confirming...\n");
-		if(getpasswd(prompt, passck, sizeof(passck)) < 0){
+		passck = getpass(prompt);
+		if(passck == nil){
 			print("getpass failed\n");
 			exits("getpass failed");
 		}
-		if(strcmp(buf, passck) != 0){
+		if(strcmp(pass, passck) != 0){
 			print("passwords didn't match\n");
 			exits("no match");
 		}
-		hexHi = PAK_Hi(id, buf, H, Hi);
+		memset(passck, 0, strlen(passck));
+		free(passck);
+		hexHi = PAK_Hi(id, pass, H, Hi);
+		memset(pass, 0, strlen(pass));
+		free(pass);
 		free(hexHi);
 		mpfree(H);
 		pw->Hi = Hi;
@@ -209,6 +216,7 @@ main(int argc, char **argv)
 	}
 
 	exits("");
+	return 1;  /* keep  other compilers happy */
 }
 
 

+ 9 - 8
sys/src/cmd/auth/secstore/util.c

@@ -27,11 +27,10 @@ estrdup(char *s)
 	return s;
 }
 
-// name changed from getpass() to avoid conflict with Irix stdlib.h
-int
-getpasswd(char *prompt, char *line, int len)
+char*
+getpass(char *prompt)
 {
-	char *p;
+	char *p, line[4096];
 	int n, nr;
 	static int cons, consctl;  // closing and reopening fails in ssh environment
 
@@ -56,13 +55,15 @@ getpasswd(char *prompt, char *line, int len)
 		if(n < 0){
 			fprint(consctl, "rawoff");
 			fprint(cons, "\n");
-			return -1;
+			return nil;
 		}
 		if(n == 0 || *p == '\n' || *p == '\r' || *p == 0x7f){
 			*p = '\0';
 			fprint(consctl, "rawoff");
 			fprint(cons, "\n");
-			return nr;
+			p = strdup(line);
+			memset(line, 0, nr);
+			return p;
 		}
 		if(*p == '\b'){
 			if(nr > 0){
@@ -77,11 +78,11 @@ getpasswd(char *prompt, char *line, int len)
 			nr++;
 			p++;
 		}
-		if(nr == len){
+		if(nr+1 == sizeof line){
 			fprint(cons, "line too long; try again\n%s", prompt);
 			nr = 0;
 			p = line;
 		}
 	}
-	return -1;  // NOT REACHED
+	return nil;  // NOT REACHED
 }

+ 178 - 164
sys/src/cmd/ip/ftpd.c

@@ -308,7 +308,7 @@ main(int argc, char **argv)
 		alarm(Maxwait);
 	}
 	if(pid)
-		postnote(PNGROUP, pid, "kill");
+		postnote(PNPROC, pid, "kill");
 }
 
 /*
@@ -392,7 +392,8 @@ transfer(char *cmd, char *a1, char *a2, char *a3, int image)
 	case -1:
 		return reply("450 Out of processes: %r");
 	case 0:
-logit("running tar %d\n", getpid());
+		logit("running %s %s %s %s pid %d",
+			cmd, a1?a1:"", a2?a2:"" , a3?a3:"",getpid());
 		close(pfd[1]);
 		close(dfd);
 		dup(pfd[0], 1);
@@ -454,7 +455,7 @@ logit("running tar %d\n", getpid());
 			break;
 		free(w);
 	}
-	if(w != nil && w->msg != nil){
+	if(w != nil && w->msg != nil && w->msg[0] != 0){
 		bytes = -1;
 		logit("%s", w->msg);
 		logit("%s %s %s %s failed %s", cmd, a1?a1:"", a2?a2:"" , a3?a3:"", w->msg);
@@ -657,7 +658,7 @@ quitcmd(char *arg)
 	USED(arg);
 	reply("200 Bye");
 	if(pid)
-		postnote(PNGROUP, pid, "kill");
+		postnote(PNPROC, pid, "kill");
 	return -1;
 }
 
@@ -852,8 +853,7 @@ void
 listfile(Biobufhdr *b, char *name, int lflag, char *dname)
 {
 	char ts[32];
-	char buf[256];
-	int n, links;
+	int n, links, pad;
 	long now;
 	char *x;
 	Dir *d;
@@ -867,8 +867,8 @@ listfile(Biobufhdr *b, char *name, int lflag, char *dname)
 	if(isnone){
 		if(strncmp(x, "/incoming/", sizeof("/incoming/")-1) != 0)
 			d->mode &= ~0222;
-		strcpy(d->uid, "none");
-		strcpy(d->gid, "none");
+		d->uid = "none";
+		d->gid = "none";
 	}
 
 	strcpy(ts, ctime(d->mtime));
@@ -884,24 +884,27 @@ listfile(Biobufhdr *b, char *name, int lflag, char *dname)
 		} else
 			links = 1;
 		
-		n = snprint(buf, sizeof(buf), "%s %3d %-8s %-8s %7lld %s ", mode2asc(d->mode), links,
+		Bprint(b, "%s %3d %-8s %-8s %7lld %s ",
+			mode2asc(d->mode), links,
 			d->uid, d->gid, d->length, ts+4);
-	} else
-		n = 0;
-	if(dname)
-		n += snprint(buf+n, sizeof(buf)-n, "%s/", dname);
-	n += snprint(buf+n, sizeof(buf)-n, "%s", name);
-	if(Cflag && col + maxnamelen + 1 < 40){
-		if(n < maxnamelen+1){
-			memset(buf+n, ' ', maxnamelen+1-n);
-			buf[maxnamelen+1] = 0;
+	}
+	if(Cflag && maxnamelen < 40){
+		n = strlen(name);
+		pad = ((col+maxnamelen)/(maxnamelen+1))*(maxnamelen+1);
+		if(pad+maxnamelen+1 < 60){
+			Bprint(b, "%*s", pad-col+n, name);
+			col = pad+n;
 		}
-		col += maxnamelen + 1;
-	} else {
-		n += snprint(buf+n, sizeof(buf)-n, "\r\n");
-		col = 0;
+		else{
+			Bprint(b, "\r\n%s", name);
+			col = n;
+		}
+	}
+	else{
+		if(dname)
+			Bprint(b, "%s/", dname);
+		Bprint(b, "%s\r\n", name);
 	}
-	Bwrite(b, buf, n);
 	free(d);
 }
 int
@@ -923,7 +926,7 @@ void
 listdir(char *name, Biobufhdr *b, int lflag, int *printname, Globlist *gl)
 {
 	Dir *p;
-	int fd, n, i;
+	int fd, n, i, l;
 	char *dname;
 	uvlong total;
 
@@ -944,9 +947,11 @@ listdir(char *name, Biobufhdr *b, int lflag, int *printname, Globlist *gl)
 	n = dirreadall(fd, &p);
 	close(fd);
 	if(Cflag){
-		for(i = 0; i < n; i++)
-			if(strlen(p[i].name) > maxnamelen)
-				maxnamelen = strlen(p[i].name);
+		for(i = 0; i < n; i++){
+			l = strlen(p[i].name);
+			if(l > maxnamelen)
+				maxnamelen = l;
+		}
 	}
 
 	/* Unix style total line */
@@ -980,11 +985,10 @@ list(char *arg, int lflag)
 	int dfd, printname;
 	int i, n, argc;
 	char *alist[Narg];
-	char path[Maxpath];
 	char **argv;
 	Biobufhdr bh;
 	uchar buf[512];
-	char *p;
+	char *p, *s;
 
 	if(arg == 0)
 		arg = "";
@@ -1035,11 +1039,10 @@ list(char *arg, int lflag)
 		argv = alist;
 		argv[0] = ".";
 	}
+
 	for(i = 0; i < argc; i++){
 		chdir(curdir);
-		strncpy(path, argv[i], sizeof(path));
-		path[sizeof(path)-1] = 0;
-		gl = glob(path);
+		gl = glob(argv[i]);
 		if(gl == nil)
 			continue;
 		
@@ -1050,20 +1053,24 @@ list(char *arg, int lflag)
 			for(g = gl->first; g; g = g->next)
 				if(g->glob && (n = strlen(s_to_c(g->glob))) > maxnamelen)
 					maxnamelen = n;
-
-		for(g = gl->first; g; g = g->next){
+		while(s = globiter(gl)){
 			if(debug)
-				logit("glob %s", s_to_c(g->glob));
-			p = abspath(s_to_c(g->glob));
-			if(p == nil)
+				logit("glob %s", s);
+			p = abspath(s);
+			if(p == nil){
+				free(s);
 				continue;
+			}
 			d = dirstat(p);
-			if(d == nil)
+			if(d == nil){
+				free(s);
 				continue;
+			}
 			if(d->qid.type & QTDIR)
-				listdir(s_to_c(g->glob), &bh, lflag, &printname, gl);
+				listdir(s, &bh, lflag, &printname, gl);
 			else
-				listfile(&bh, s_to_c(g->glob), lflag, 0);
+				listfile(&bh, s, lflag, 0);
+			free(s);
 			free(d);
 		}
 		globlistfree(gl);
@@ -1173,28 +1180,29 @@ retrievedir(char *arg)
 {
 	int n;
 	char *p;
-	char file[Maxpath];
+	String *file;
 
 	if(type != Timage){
 		reply("550 This file requires type binary/image");
 		return;
 	}
 
-	strcpy(file, arg);
-	p = strrchr(arg, '/');
-	if(p != arg){
+	file = s_copy(arg);
+	p = strrchr(s_to_c(file), '/');
+	if(p != s_to_c(file)){
 		*p++ = 0;
-		chdir(arg);
+		chdir(s_to_c(file));
 	} else {
 		chdir("/");
-		p = arg+1;
+		p = s_to_c(file)+1;
 	}
 
 	n = transfer("/bin/tar", "c", p, 0, 1);
 	if(n < 0)
-		logit("get %s failed", file);
+		logit("get %s failed", arg);
 	else
-		logit("get %s OK %d", file, n);
+		logit("get %s OK %d", arg, n);
+	s_free(file);
 }
 void
 retrieve(char *arg, int arg2)
@@ -1427,7 +1435,7 @@ storeucmd(char *arg)
 	USED(arg);
 	if(isnone)
 		return reply("550 Permission denied");
-	strcpy(name, "ftpXXXXXXXXXXX");
+	strncpy(name, "ftpXXXXXXXXXXX", sizeof name);
 	mktemp(name);
 	fd = create(name, OWRITE, createperm);
 	if(fd == -1)
@@ -1480,8 +1488,14 @@ int
 abortcmd(char *arg)
 {
 	USED(arg);
-	if(pid && postnote(PNGROUP, pid, "kill") == 0)
-		reply("426 Command aborted");
+
+	logit("abort pid %d", pid);
+	if(pid){
+		if(postnote(PNPROC, pid, "kill") == 0)
+			reply("426 Command aborted");
+		else
+			logit("postnote pid %d %r", pid);
+	}
 	return reply("226 Abort processed");
 }
 
@@ -1519,7 +1533,7 @@ helpcmd(char *arg)
 /*
  *  renaming a file takes two commands
  */
-static char filepath[256];
+static String *filepath;
 
 int
 rnfrcmd(char *from)
@@ -1531,16 +1545,20 @@ rnfrcmd(char *from)
 	from = abspath(from);
 	if(from == 0)
 		return reply("550 Permission denied");
-	strncpy(filepath, from, sizeof(filepath));
-	filepath[sizeof(filepath)-1] = 0;
-	return reply("350 Rename %s to ...", filepath);
+	if(filepath == nil)
+		filepath = s_copy(from);
+	else{
+		s_reset(filepath);
+		s_append(filepath, from);
+	}
+	return reply("350 Rename %s to ...", s_to_c(filepath));
 }
 int
 rntocmd(char *to)
 {
+	int r;
 	Dir nd;
-	char *fp;
-	char *tp;
+	char *fp, *tp;
 
 	if(isnone)
 		return reply("550 Permission denied");
@@ -1549,24 +1567,26 @@ rntocmd(char *to)
 	to = abspath(to);
 	if(to == 0)
 		return reply("550 Permission denied");
-	if(*filepath == 0)
+	if(filepath == nil || *(s_to_c(filepath)) == 0)
 		return reply("503 Rnto must be preceeded by an rnfr");
 
 	tp = strrchr(to, '/');
-	fp = strrchr(filepath, '/');
+	fp = strrchr(s_to_c(filepath), '/');
 	if((tp && fp == 0) || (fp && tp == 0)
-	|| (fp && tp && (fp-filepath != tp-to || memcmp(filepath, to, tp-to))))
+	|| (fp && tp && (fp-s_to_c(filepath) != tp-to || memcmp(s_to_c(filepath), to, tp-to))))
 		return reply("550 Rename can't change directory");
 	if(tp)
 		to = tp+1;
 
 	nulldir(&nd);
 	nd.name = to;
-	if(dirwstat(filepath, &nd) < 0)
-		return reply("550 Can't rename %s to %s: %r\n", filepath, to);
+	if(dirwstat(s_to_c(filepath), &nd) < 0)
+		r = reply("550 Can't rename %s to %s: %r\n", s_to_c(filepath), to);
+	else
+		r = reply("250 %s now %s", s_to_c(filepath), to);
+	s_reset(filepath);
 
-	filepath[0] = 0;
-	return reply("250 %s now %s", filepath, to);
+	return r;
 }
 
 /*
@@ -1605,75 +1625,15 @@ dialdata(void)
 	return fd;
 }
 
-/*
- *  to circumscribe the accessible files we have to eliminate ..'s
- *  and resolve all names from the root.  We also remove any /bin/rc
- *  special characters to avoid later problems with executed commands.
- */
-char *special = "`;| ";
-
-char*
-abspath(char *origpath)
-{
-	int n, c;
-	char *p, *sp, *path;
-	char work[Maxpath];
-	static char rpath[Maxpath];
-
-	if(origpath == 0)
-		*work = 0;
-	else
-		strncpy(work, origpath, sizeof(work));
-	path = work;
-
-	for(sp = special; *sp; sp++){
-		p = strchr(path, *sp);
-		if(p)
-			*p = 0;
-	}
-
-	if(*path == '/')
-		rpath[0] = 0;
-	else
-		strcpy(rpath, curdir);
-	n = strlen(rpath);
-
-	while(*path && n < Maxpath-2){
-		p = strchr(path, '/');
-		if(p)
-			*p++ = 0;
-		if(strcmp(path, "..") == 0){
-			while(n > 1){
-				n--;
-				c = rpath[n];
-				rpath[n] = 0;
-				if(c == '/')
-					break;
-			}
-		} else if(strcmp(path, ".") == 0)
-			n = n;
-		else if(n == 1)
-			n += snprint(rpath+n, Maxpath - n, "%s", path);
-		else
-			n += snprint(rpath+n, Maxpath - n - 1, "/%s", path);
-		if(p)
-			path = p;
-		else
-			break;
-	}
-
-	if(!accessok(rpath))
-		return nil;
-
-	return rpath;
-}
-
 int
 postnote(int group, int pid, char *note)
 {
 	char file[128];
 	int f, r;
 
+	/*
+	 * Use #p because /proc may not be in the namespace.
+	 */
 	switch(group) {
 	case PNPROC:
 		sprint(file, "#p/%d/note", pid);
@@ -1698,12 +1658,54 @@ postnote(int group, int pid, char *note)
 	return 0;
 }
 
-static char *pfile = "/.httplogin";
+/*
+ *  to circumscribe the accessible files we have to eliminate ..'s
+ *  and resolve all names from the root.  We also remove any /bin/rc
+ *  special characters to avoid later problems with executed commands.
+ */
+char *special = "`;| ";
+
+char*
+abspath(char *origpath)
+{
+	char *p, *sp, *path;
+	static String *rpath;
+
+	if(rpath == nil)
+		rpath = s_new();
+	else
+		s_reset(rpath);
+
+	if(origpath == nil)
+		s_append(rpath, curdir);
+	else{
+		if(*origpath != '/'){
+			s_append(rpath, curdir);
+			s_append(rpath, "/");
+		}
+		s_append(rpath, origpath);
+	}
+	path = s_to_c(rpath);
+
+	for(sp = special; *sp; sp++){
+		p = strchr(path, *sp);
+		if(p)
+			*p = 0;
+	}
+
+	cleanname(s_to_c(rpath));
+	rpath->ptr = rpath->base+strlen(rpath->base);
+
+	if(!accessok(s_to_c(rpath)))
+		return nil;
+
+	return s_to_c(rpath);
+}
 
 typedef struct Path Path;
 struct Path {
 	Path	*next;
-	char	*path;
+	String	*path;
 	int	inuse;
 	int	ok;
 };
@@ -1719,32 +1721,33 @@ Path *pathlevel[Maxlevel];
 Path*
 unlinkpath(char *path, int level)
 {
+	String *s;
 	Path **l, *p;
 	int n;
 
 	n = 0;
 	for(l = &pathlevel[level]; *l; l = &(*l)->next){
 		p = *l;
-		if(strcmp(p->path, path) == 0){
+		/* hit */
+		if(strcmp(s_to_c(p->path), path) == 0){
 			*l = p->next;
 			p->next = nil;
 			return p;
 		}
-		if(++n >= Maxperlevel - 1 || p->next == nil)
-			break;
-	}
-	if(*l){
 		/* reuse */
-		p = *l;
-		*l = p->next;
-		free(p->path);
-		memset(p, 0, sizeof *p);
-		
-	} else {
-		/* allocate */
-		p = mallocz(sizeof *p, 1);
+		if(++n >= Maxperlevel){
+			*l = p->next;
+			s = p->path;
+			s_reset(p->path);
+			memset(p, 0, sizeof *p);
+			p->path = s_append(s, path);
+			return p;
+		}
 	}
-	p->path = strdup(path);
+
+	/* allocate */
+	p = mallocz(sizeof *p, 1);
+	p->path = s_copy(path);
 	return p;
 }
 
@@ -1765,11 +1768,12 @@ addpath(Path *p, int level, int ok)
 }
 
 int
-_accessok(char *path, int level)
+_accessok(String *s, int level)
 {
 	Path *p;
 	char *cp;
-	int lvl;
+	int lvl, offset;
+	static char httplogin[] = "/.httplogin";
 
 	if(level < 0)
 		return 1;
@@ -1777,46 +1781,56 @@ _accessok(char *path, int level)
 	if(lvl >= Maxlevel)
 		lvl = Maxlevel - 1;
 
-	p = unlinkpath(path, lvl);
+	p = unlinkpath(s_to_c(s), lvl);
 	if(p->inuse){
 		/* move to front */
 		linkpath(p, lvl);
 		return p->ok;
 	}
-	cp = strrchr(path, '/');
+	cp = strrchr(s_to_c(s), '/');
 	if(cp == nil)
-		cp = path;
-	p->path = strdup(path);
-	strcat(path, pfile);
-	if(access(path, AEXIST) == 0){
+		offset = 0;
+	else
+		offset = cp - s_to_c(s);
+	s_append(s, httplogin);
+	if(access(s_to_c(s), AEXIST) == 0){
 		addpath(p, lvl, 0);
 		return 0;
 	}
-	*cp = 0;
-	addpath(p, lvl, _accessok(path, level-1));
+
+	/*
+	 * There's no way to shorten a String without
+	 * knowing the implementation.
+	 */
+	s->ptr = s->base+offset;
+	s_terminate(s);
+	addpath(p, lvl, _accessok(s, level-1));
+
 	return p->ok;
 }
 
 /*
- *  work down from the root
+ * check for a subdirectory containing .httplogin
+ * at each level of the path.
  */
 int
 accessok(char *path)
 {
-	int level, n;
+	int level, r;
 	char *p;
-	char npath[Maxpath+1];
-
-	strcpy(npath, path);
-	n = strlen(path)-1;
-	if(npath[n] == '/')
-		npath[n] = 0;
-	p = npath+1;
-	for(level = 1; p >= path && level < Maxlevel; level++){
+	String *npath;
+
+	npath = s_copy(path);
+	p = s_to_c(npath)+1;
+	for(level = 1; level < Maxlevel; level++){
 		p = strchr(p, '/');
 		if(p == nil)
 			break;
 		p++;
 	}
-	return _accessok(npath, level-1);
+
+	r = _accessok(npath, level-1);
+	s_free(npath);
+
+	return r;
 }

+ 27 - 2
sys/src/cmd/ip/glob.c

@@ -21,6 +21,13 @@ globnew(void)
 	return g;
 }
 
+static void
+globfree1(Glob *g)
+{
+	s_free(g->glob);
+	free(g);
+}
+
 static void
 globfree(Glob *g)
 {
@@ -28,8 +35,7 @@ globfree(Glob *g)
 
 	for(; g != nil; g = next){
 		next = g->next;
-		s_free(g->glob);
-		free(g);
+		globfree1(g);
 	}
 }
 
@@ -177,6 +183,25 @@ globnext(Globlist *gl, char *pattern)
 		globnext(gl, pattern);
 }
 
+char *
+globiter(Globlist *gl)
+{
+	Glob *g;
+	char *s;
+
+	if(gl->first == nil)
+		return nil;
+	g = gl->first;
+	gl->first = g->next;
+	if(gl->first == nil)
+		gl->l = &gl->first;
+	s = strdup(s_to_c(g->glob));
+	if(s == nil)
+		sysfatal("globiter: %r");
+	globfree1(g);
+	return s;
+}
+
 Globlist*
 glob(char *pattern)
 {

+ 1 - 0
sys/src/cmd/ip/glob.h

@@ -14,3 +14,4 @@ struct Globlist{
 extern	Globlist*	glob(char*);
 extern	void		globadd(Globlist*, char*, char*);
 extern	void		globlistfree(Globlist *gl);
+extern	char*		globiter(Globlist *gl);

+ 54 - 35
sys/src/cmd/upas/fs/pop3.c

@@ -14,14 +14,16 @@ struct Pop {
 
 	char *host;
 	char *user;
+	char *port;
 
 	int ppop;
 	int refreshtime;
 	int debug;
 	int pipeline;
-	int hastls;
+	int encrypted;
 	int needtls;
 	int notls;
+	int needssl;
 
 	// open network connection
 	Biobuf bin;
@@ -108,6 +110,38 @@ pop3log(char *fmt, ...)
 	return 0;
 }
 
+static char*
+pop3pushtls(Pop *pop)
+{
+	int fd;
+	uchar digest[SHA1dlen];
+	TLSconn conn;
+
+	memset(&conn, 0, sizeof conn);
+	// conn.trace = pop3log;
+	fd = tlsClient(pop->fd, &conn);
+	if(fd < 0)
+		return "tls error";
+	if(conn.cert==nil || conn.certlen <= 0){
+		close(fd);
+		return "server did not provide TLS certificate";
+	}
+	sha1(conn.cert, conn.certlen, digest, nil);
+	if(!pop->thumb || !okThumbprint(digest, pop->thumb)){
+		fmtinstall('H', encodefmt);
+		close(fd);
+		free(conn.cert);
+		fprint(2, "upas/fs pop3: server certificate %.*H not recognized\n", SHA1dlen, digest);
+		return "bad server certificate";
+	}
+	free(conn.cert);
+	close(pop->fd);
+	pop->fd = fd;
+	pop->encrypted = 1;
+	Binit(&pop->bin, pop->fd, OREAD);
+	Binit(&pop->bout, pop->fd, OWRITE);
+	return nil;
+}
 
 //
 // get capability list, possibly start tls
@@ -115,11 +149,8 @@ pop3log(char *fmt, ...)
 static char*
 pop3capa(Pop *pop)
 {
-	int fd;
 	char *s;
-	uchar digest[SHA1dlen];
 	int hastls;
-	TLSconn conn;
 
 	pop3cmd(pop, "CAPA");
 	if(!isokay(pop3resp(pop)))
@@ -140,28 +171,8 @@ pop3capa(Pop *pop)
 		pop3cmd(pop, "STLS");
 		if(!isokay(s = pop3resp(pop)))
 			return s;
-		memset(&conn, 0, sizeof conn);
-		// conn.trace = pop3log;
-		fd = tlsClient(pop->fd, &conn);
-		if(fd < 0)
-			return "tls error";
-		if(conn.cert==nil || conn.certlen <= 0){
-			close(fd);
-			return "server did not provide TLS certificate";
-		}
-		sha1(conn.cert, conn.certlen, digest, nil);
-		if(!pop->thumb || !okThumbprint(digest, pop->thumb)){
-			fmtinstall('H', encodefmt);
-			close(fd);
-			fprint(2, "upas/fs pop3: server certificate %.*H not recognized\n", SHA1dlen, digest);
-			return "bad server certificate";
-		}
-		free(conn.cert);
-		close(pop->fd);
-		pop->fd = fd;
-		Binit(&pop->bin, fd, OREAD);
-		Binit(&pop->bout, fd, OWRITE);
-		pop->hastls = 1;
+		if((s = pop3pushtls(pop)) != nil)
+			return s;
 	}
 	return nil;
 }
@@ -211,7 +222,7 @@ pop3login(Pop *pop)
 		if(s = pop3capa(pop))
 			return s;
 
-		if(pop->needtls && !pop->hastls)
+		if(pop->needtls && !pop->encrypted)
 			return "could not negotiate TLS";
 
 		up = auth_getuserpasswd(auth_getkey, "proto=pass service=pop dom=%q%s",
@@ -241,11 +252,16 @@ pop3dial(Pop *pop)
 {
 	char *err;
 
-	if((pop->fd = dial(netmkaddr(pop->host, "net", "pop3"), 0, 0, 0)) < 0)
+	if((pop->fd = dial(netmkaddr(pop->host, "net", pop->needssl ? "pop3s" : "pop3"), 0, 0, 0)) < 0)
 		return geterrstr();
 
-	Binit(&pop->bin, pop->fd, OREAD);
-	Binit(&pop->bout, pop->fd, OWRITE);
+	if(pop->needssl){
+		if((err = pop3pushtls(pop)) != nil)
+			return err;
+	}else{
+		Binit(&pop->bin, pop->fd, OREAD);
+		Binit(&pop->bout, pop->fd, OWRITE);
+	}
 
 	if(err = pop3login(pop)) {
 		close(pop->fd);
@@ -615,17 +631,19 @@ char*
 pop3mbox(Mailbox *mb, char *path)
 {
 	char *f[10];
-	int nf, apop, ppop, apoptls, popnotls, apopnotls, poptls;
+	int nf, apop, ppop, popssl, apopssl, apoptls, popnotls, apopnotls, poptls;
 	Pop *pop;
 
 	quotefmtinstall();
+	popssl = strncmp(path, "/pops/", 6) == 0;
+	apopssl = strncmp(path, "/apops/", 7) == 0;
 	poptls = strncmp(path, "/poptls/", 8) == 0;
 	popnotls = strncmp(path, "/popnotls/", 10) == 0;
-	ppop = poptls || popnotls || strncmp(path, "/pop/", 5) == 0;
+	ppop = popssl || poptls || popnotls || strncmp(path, "/pop/", 5) == 0;
 	apoptls = strncmp(path, "/apoptls/", 9) == 0;
 	apopnotls = strncmp(path, "/apopnotls/", 11) == 0;
-	apop = apoptls || apopnotls || strncmp(path, "/apop/", 6) == 0;
-	
+	apop = apopssl || apoptls || apopnotls || strncmp(path, "/apop/", 6) == 0;
+
 	if(!ppop && !apop)
 		return Enotme;
 
@@ -636,7 +654,7 @@ pop3mbox(Mailbox *mb, char *path)
 	nf = getfields(path, f, nelem(f), 0, "/");
 	if(nf != 3 && nf != 4) {
 		free(path);
-		return "bad pop3 path syntax /[a]pop[tls]/system[/user]";
+		return "bad pop3 path syntax /[a]pop[tls|ssl]/system[/user]";
 	}
 
 	pop = emalloc(sizeof(*pop));
@@ -647,6 +665,7 @@ pop3mbox(Mailbox *mb, char *path)
 	else
 		pop->user = f[3];
 	pop->ppop = ppop;
+	pop->needssl = popssl || apopssl;
 	pop->needtls = poptls || apoptls;
 	pop->refreshtime = 60;
 	pop->notls = popnotls || apopnotls;