add others
diff --git a/src/cmd/auth/passwd.c b/src/cmd/auth/passwd.c
new file mode 100644
index 0000000..da23638
--- /dev/null
+++ b/src/cmd/auth/passwd.c
@@ -0,0 +1,153 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+#include <authsrv.h>
+
+static char *pbmsg = "AS protocol botch";
+
+int
+asrdresp(int fd, char *buf, int len)
+{
+	char error[AERRLEN];
+
+	if(read(fd, buf, 1) != 1){
+		werrstr(pbmsg);
+		return -1;
+	}
+
+	switch(buf[0]){
+	case AuthOK:
+		if(readn(fd, buf, len) < 0){
+			werrstr(pbmsg);
+			return -1;
+		}
+		break;
+	case AuthErr:
+		if(readn(fd, error, AERRLEN) < 0){
+			werrstr(pbmsg);
+			return -1;
+		}
+		error[AERRLEN-1] = 0;
+		werrstr(error);
+		return -1;
+	default:
+		werrstr(pbmsg);
+		return -1;
+	}
+	return 0;
+}
+
+void
+readln(char *prompt, char *buf, int nbuf, int secret)
+{
+	char *p;
+	
+	p = readcons(prompt, nil, secret);
+	if(p == nil)
+		sysfatal("user terminated input");
+	if(strlen(p) >= nbuf)
+		sysfatal("too long");
+	strcpy(buf, p);
+	memset(p, 0, strlen(p));
+	free(p);
+}
+
+void
+main(int argc, char **argv)
+{
+	int fd;
+	Ticketreq tr;
+	Ticket t;
+	Passwordreq pr;
+	char tbuf[TICKETLEN];
+	char key[DESKEYLEN];
+	char buf[512];
+	char *s, *user;
+
+	user = getuser();
+
+	ARGBEGIN{
+	}ARGEND
+
+	s = nil;
+	if(argc > 0){
+		user = argv[0];
+		s = strchr(user, '@');
+		if(s != nil)
+			*s++ = 0;
+		if(*user == 0)
+			user = getuser();
+	}
+
+	fd = authdial(nil, s);
+	if(fd < 0)
+		sysfatal("protocol botch: %r");
+
+	/* send ticket request to AS */
+	memset(&tr, 0, sizeof(tr));
+	strcpy(tr.uid, user);
+	tr.type = AuthPass;
+	convTR2M(&tr, buf);
+	if(write(fd, buf, TICKREQLEN) != TICKREQLEN)
+		sysfatal("protocol botch: %r");
+	if(asrdresp(fd, buf, TICKETLEN) < 0)
+		sysfatal("%r");
+	memmove(tbuf, buf, TICKETLEN);
+
+	/*
+	 *  get a password from the user and try to decrypt the
+	 *  ticket.  If it doesn't work we've got a bad password,
+	 *  give up.
+	 */
+	readln("Plan 9 Password", pr.old, sizeof pr.old, 1);
+	passtokey(key, pr.old);
+	convM2T(tbuf, &t, key);
+	if(t.num != AuthTp || strcmp(t.cuid, tr.uid))
+		sysfatal("bad password");
+
+	/* loop trying new passwords */
+	for(;;){
+		pr.changesecret = 0;
+		*pr.new = 0;
+		readln("change Plan 9 Password? (y/n)", buf, sizeof buf, 0);
+		if(*buf == 'y' || *buf == 'Y'){
+			readln("Password(8 to 31 characters)", pr.new,
+				sizeof pr.new, 1);
+			readln("Confirm", buf, sizeof buf, 1);
+			if(strcmp(pr.new, buf)){
+				print("!mismatch\n");
+				continue;
+			}
+		}
+		readln("change Inferno/POP password? (y/n)", buf, sizeof buf, 0);
+		if(*buf == 'y' || *buf == 'Y'){
+			pr.changesecret = 1;
+			readln("make it the same as your plan 9 password? (y/n)",
+				buf, sizeof buf, 0);
+			if(*buf == 'y' || *buf == 'Y'){
+				if(*pr.new == 0)
+					strcpy(pr.secret, pr.old);
+				else
+					strcpy(pr.secret, pr.new);
+			} else {
+				readln("Secret(0 to 256 characters)", pr.secret,
+					sizeof pr.secret, 1);
+				readln("Confirm", buf, sizeof buf, 1);
+				if(strcmp(pr.secret, buf)){
+					print("!mismatch\n");
+					continue;
+				}
+			}
+		}
+		pr.num = AuthPass;
+		convPR2M(&pr, buf, t.key);
+		if(write(fd, buf, PASSREQLEN) != PASSREQLEN)
+			sysfatal("AS protocol botch: %r");
+		if(asrdresp(fd, buf, 0) == 0)
+			break;
+		fprint(2, "refused: %r\n");
+	}
+	close(fd);
+
+	exits(0);
+}