--- ../checkpassword-0.81-orig/Makefile	Fri Feb 11 15:32:45 2000
+++ Makefile	Fri Feb 11 13:38:18 2000
@@ -1,9 +1,54 @@
 # Don't edit Makefile! Use conf-* for configuration.
 
+MYSQL_LIBS=/usr/local/lib/mysql/libmysqlclient.a -lm
+MYSQL_INCLUDE=-I/usr/local/include
+LOGGING=-DO_NOT_LOG_SQL #-DO_NOT_LOG
+PASSWORDS=-DUSE_MYSQL_PASSWORDS
 SHELL=/bin/sh
 
 default: it
 
+init_mysql.o: compile init_mysql.c auto_qmail.h
+	./compile init_mysql.c $(MYSQL_INCLUDE)
+
+connect_mysql.o: compile connect_mysql.c
+	./compile connect_mysql.c $(MYSQL_INCLUDE)
+
+getpw_mysql.o: compile getpw_mysql.c mysql_queries.h
+	./compile getpw_mysql.c $(MYSQL_INCLUDE) $(LOGGING) $(PASSWORDS)
+
+do_query.o: compile do_query.c mysql_queries.h
+	./compile do_query.c $(MYSQL_INCLUDE) $(LOGGING)
+
+mkmsg.o: compile mkmsg.c
+	./compile mkmsg.c $(LOGGING)
+
+splog.o: compile splog.c
+	./compile splog.c $(LOGGING)
+
+ptest.o: compile ptest.c
+	./compile ptest.c
+
+ptest: load auto_qmail.o ptest.o init_mysql.o connect_mysql.o getpw_mysql.o \
+fmt_uint.o fmt_uint0.o fmt_ulong.o open_read.o \
+do_query.o mkmsg.o splog.o stralloc.a str.a getln.a substdio.a error.a alloc.a
+	./load ptest auto_qmail.o init_mysql.o connect_mysql.o getpw_mysql.o \
+	fmt_uint.o fmt_uint0.o fmt_ulong.o open_read.o \
+	do_query.o mkmsg.o splog.o getln.a substdio.a stralloc.a str.a error.a \
+	alloc.a /usr/local/lib/mysql/libmysqlclient.a -lm
+
+alloc.a: \
+makelib alloc.o alloc_re.o
+	./makelib alloc.a alloc.o alloc_re.o
+
+alloc.o: \
+compile alloc.c alloc.h error.h
+	./compile alloc.c
+
+alloc_re.o: \
+compile alloc_re.c alloc.h byte.h
+	./compile alloc_re.c
+
 auto-str: \
 load auto-str.o substdio.a error.a str.a
 	./load auto-str substdio.a error.a str.a 
@@ -20,6 +65,18 @@
 compile auto_home.c
 	./compile auto_home.c
 
+auto_qmail.c: \
+auto-str conf-qmail
+	./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c
+
+auto_qmail.o: \
+compile auto_qmail.c
+	./compile auto_qmail.c
+
+byte_chr.o: \
+compile byte_chr.c byte.h
+	./compile byte_chr.c
+
 byte_copy.o: \
 compile byte_copy.c byte.h
 	./compile byte_copy.c
@@ -28,14 +85,24 @@
 compile byte_cr.c byte.h
 	./compile byte_cr.c
 
+byte_diff.o: \
+compile byte_diff.c byte.h
+	./compile byte_diff.c
+
 check: \
 it instcheck
 	./instcheck
 
 checkpassword: \
-load checkpassword.o prot.o shadow.lib crypt.lib s.lib
-	./load checkpassword prot.o  `cat shadow.lib` `cat \
-	crypt.lib` `cat s.lib`
+load checkpassword.o auto_qmail.o init_mysql.o connect_mysql.o getpw_mysql.o \
+do_query.o fmt_uint.o fmt_uint0.o fmt_ulong.o open_read.o mkmsg.o splog.o \
+prot.o shadow.lib crypt.lib s.lib stralloc.a str.a getln.a substdio.a error.a \
+alloc.a
+	./load checkpassword auto_qmail.o init_mysql.o connect_mysql.o \
+	getpw_mysql.o do_query.o fmt_uint.o fmt_uint0.o fmt_ulong.o \
+	open_read.o mkmsg.o splog.o prot.o  `cat shadow.lib` `cat \
+	crypt.lib` `cat s.lib`getln.a substdio.a stralloc.a str.a  error.a \
+	alloc.a $(MYSQL_LIBS)
 
 checkpassword.0: \
 checkpassword.8
@@ -79,6 +146,30 @@
 compile error_str.c error.h
 	./compile error_str.c
 
+fmt_uint.o: \
+compile fmt_uint.c fmt.h
+	./compile fmt_uint.c
+
+fmt_uint0.o: \
+compile fmt_uint0.c fmt.h
+	./compile fmt_uint0.c
+
+fmt_ulong.o: \
+compile fmt_ulong.c fmt.h
+	./compile fmt_ulong.c
+
+getln.a: \
+makelib getln.o getln2.o
+	./makelib getln.a getln.o getln2.o
+
+getln.o: \
+compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h
+	./compile getln.c
+
+getln2.o: \
+compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h
+	./compile getln2.c
+
 hasshsgr.h: \
 chkshsgr warn-shsgr tryshsgr.c compile load
 	./chkshsgr || ( cat warn-shsgr; exit 1 )
@@ -173,7 +264,7 @@
 	./compile open_trunc.c
 
 prog: \
-checkpassword
+checkpassword ptest
 
 prot.o: \
 compile prot.c hasshsgr.h prot.h
@@ -198,12 +289,73 @@
 	rm -f tryshadow.o tryshadow
 
 str.a: \
-makelib str_len.o byte_copy.o byte_cr.o
-	./makelib str.a str_len.o byte_copy.o byte_cr.o
+makelib str_cpy.o str_diff.o str_len.o str_start.o byte_chr.o byte_diff.o \
+byte_copy.o byte_cr.o
+	./makelib str.a str_cpy.o str_diff.o str_len.o str_start.o byte_chr.o \
+	byte_diff.o byte_copy.o byte_cr.o
+
+str_cpy.o: \
+compile str_cpy.c str.h
+	./compile str_cpy.c
+
+str_diff.o: \
+compile str_diff.c str.h
+	./compile str_diff.c
 
 str_len.o: \
 compile str_len.c str.h
 	./compile str_len.c
+
+str_start.o: \
+compile str_start.c str.h
+	./compile str_start.c
+
+stralloc.a: \
+makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \
+stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \
+stralloc_catb.o stralloc_arts.o
+	./makelib stralloc.a stralloc_eady.o stralloc_pend.o \
+	stralloc_copy.o stralloc_opys.o stralloc_opyb.o \
+	stralloc_cat.o stralloc_cats.o stralloc_catb.o \
+	stralloc_arts.o
+
+stralloc_arts.o: \
+compile stralloc_arts.c byte.h str.h stralloc.h gen_alloc.h
+	./compile stralloc_arts.c
+
+stralloc_cat.o: \
+compile stralloc_cat.c byte.h stralloc.h gen_alloc.h
+	./compile stralloc_cat.c
+
+stralloc_catb.o: \
+compile stralloc_catb.c stralloc.h gen_alloc.h byte.h
+	./compile stralloc_catb.c
+
+stralloc_cats.o: \
+compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h
+	./compile stralloc_cats.c
+
+stralloc_copy.o: \
+compile stralloc_copy.c byte.h stralloc.h gen_alloc.h
+	./compile stralloc_copy.c
+
+stralloc_eady.o: \
+compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
+	./compile stralloc_eady.c
+
+stralloc_opyb.o: \
+compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h
+	./compile stralloc_opyb.c
+
+stralloc_opys.o: \
+compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h
+	./compile stralloc_opys.c
+
+stralloc_pend.o: \
+compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
+	./compile stralloc_pend.c
 
 strerr.a: \
 makelib strerr_sys.o strerr_die.o
--- ../checkpassword-0.81-orig/alloc.c	Fri Feb 11 15:32:45 2000
+++ alloc.c	Fri Feb 11 10:50:40 2000
@@ -0,0 +1,32 @@
+#include "alloc.h"
+#include "error.h"
+extern char *malloc();
+extern void free();
+
+#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
+#define SPACE 4096 /* must be multiple of ALIGNMENT */
+
+typedef union { char irrelevant[ALIGNMENT]; double d; } aligned;
+static aligned realspace[SPACE / ALIGNMENT];
+#define space ((char *) realspace)
+static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */
+
+/*@null@*//*@out@*/char *alloc(n)
+unsigned int n;
+{
+  char *x;
+  n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */
+  if (n <= avail) { avail -= n; return space + avail; }
+  x = malloc(n);
+  if (!x) errno = error_nomem;
+  return x;
+}
+
+void alloc_free(x)
+char *x;
+{
+  if (x >= space)
+    if (x < space + SPACE)
+      return; /* XXX: assuming that pointers are flat */
+  free(x);
+}
--- ../checkpassword-0.81-orig/alloc.h	Fri Feb 11 15:32:45 2000
+++ alloc.h	Fri Feb 11 10:50:41 2000
@@ -0,0 +1,8 @@
+#ifndef ALLOC_H
+#define ALLOC_H
+
+extern /*@null@*//*@out@*/char *alloc();
+extern void alloc_free();
+extern int alloc_re();
+
+#endif
--- ../checkpassword-0.81-orig/alloc_re.c	Fri Feb 11 15:32:45 2000
+++ alloc_re.c	Fri Feb 11 10:50:41 2000
@@ -0,0 +1,17 @@
+#include "alloc.h"
+#include "byte.h"
+
+int alloc_re(x,m,n)
+char **x;
+unsigned int m;
+unsigned int n;
+{
+  char *y;
+ 
+  y = alloc(n);
+  if (!y) return 0;
+  byte_copy(y,m,*x);
+  alloc_free(*x);
+  *x = y;
+  return 1;
+}
--- ../checkpassword-0.81-orig/auto_qmail.h	Fri Feb 11 15:32:45 2000
+++ auto_qmail.h	Fri Feb 11 10:28:42 2000
@@ -0,0 +1,6 @@
+#ifndef AUTO_QMAIL_H
+#define AUTO_QMAIL_H
+
+extern char auto_qmail[];
+
+#endif
--- ../checkpassword-0.81-orig/byte_chr.c	Fri Feb 11 15:32:45 2000
+++ byte_chr.c	Fri Feb 11 11:08:37 2000
@@ -0,0 +1,20 @@
+#include "byte.h"
+
+unsigned int byte_chr(s,n,c)
+char *s;
+register unsigned int n;
+int c;
+{
+  register char ch;
+  register char *t;
+
+  ch = c;
+  t = s;
+  for (;;) {
+    if (!n) break; if (*t == ch) break; ++t; --n;
+    if (!n) break; if (*t == ch) break; ++t; --n;
+    if (!n) break; if (*t == ch) break; ++t; --n;
+    if (!n) break; if (*t == ch) break; ++t; --n;
+  }
+  return t - s;
+}
--- ../checkpassword-0.81-orig/byte_diff.c	Fri Feb 11 15:32:45 2000
+++ byte_diff.c	Fri Feb 11 11:08:37 2000
@@ -0,0 +1,16 @@
+#include "byte.h"
+
+int byte_diff(s,n,t)
+register char *s;
+register unsigned int n;
+register char *t;
+{
+  for (;;) {
+    if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+    if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+    if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+    if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+  }
+  return ((int)(unsigned int)(unsigned char) *s)
+       - ((int)(unsigned int)(unsigned char) *t);
+}
--- ../checkpassword-0.81-orig/checkpassword.c	Fri Feb 11 15:32:45 2000
+++ checkpassword.c	Fri Feb 11 15:09:05 2000
@@ -1,15 +1,14 @@
 #include <errno.h>
+#include "stralloc.h"
 extern int errno;
 extern char *crypt();
 extern char *malloc();
+extern mkmsg();
 extern char **environ;
 
-int error_txtbsy =
-#ifdef ETXTBSY
-ETXTBSY;
-#else
--4;
-#endif
+stralloc message = { 0 };
+
+extern int error_txtbsy;
 
 #include "prot.h"
 #include <pwd.h>
@@ -28,14 +27,18 @@
 static struct userpw *upw;
 #endif
 
-void doit(login)
+int doit(login)
 char *login;
 {
   pw = getpwnam(login);
   if (pw)
     stored = pw->pw_passwd;
   else {
-    if (errno == error_txtbsy) _exit(111);
+    if (errno == error_txtbsy) {
+      mkmsg("couldn't get information for ", login);
+      _exit(111);
+    }
+    mkmsg("no such user ", login);
     _exit(1);
   }
 
@@ -44,7 +47,11 @@
   if (upw)
     stored = upw->upw_passwd;
   else
-    if (errno == error_txtbsy) _exit(111);
+    if (errno == error_txtbsy) {
+      _exit(111);
+      mkmsg("couldn't get information for ", login);
+      _exit(111);
+    }
 #endif
 
 #ifdef HASGETSPNAM
@@ -52,7 +59,11 @@
   if (spw)
     stored = spw->sp_pwdp;
   else
-    if (errno == error_txtbsy) _exit(111);
+    if (errno == error_txtbsy) {
+      _exit(111);
+      mkmsg("couldn't get information for ", login);
+      _exit(111);
+    }
 #endif
 }
 
@@ -104,17 +115,37 @@
   if (i == uplen) _exit(2);
   while (up[i++]) if (i == uplen) _exit(2);
 
-  doit(login);
- 
-  encrypted = crypt(password,stored);
- 
-  for (i = 0;i < sizeof(up);++i) up[i] = 0;
- 
-  if (!*stored || strcmp(encrypted,stored)) _exit(1);
+  pw = getpw_mysql(login, password);
+  if ((int) pw == -1) _exit(111);
+  if ((int) pw == 1) _exit(1);
+  if ((int) pw == 0) {
+    doit(login);
+    encrypted = crypt(password,stored);
+ 
+    for (i = 0;i < sizeof(up);++i) up[i] = 0;
+ 
+    if (!*stored) { 
+      mkmsg("no such user ", pw->pw_name);
+      _exit(1);
+    }
+    if (str_diff(encrypted,stored)) {
+      mkmsg(pw->pw_name, " got system password wrong");
+      _exit(1);
+    }
+  }
  
-  if (prot_gid((int) pw->pw_gid) == -1) _exit(1);
-  if (prot_uid((int) pw->pw_uid) == -1) _exit(1);
-  if (chdir(pw->pw_dir) == -1) _exit(111);
+  if (prot_gid((int) pw->pw_gid) == -1) {
+     mkmsg("evil gid for ", login);
+     _exit(1);
+  }
+  if (prot_uid((int) pw->pw_uid) == -1) {
+     mkmsg("evil uid for ", login);
+     _exit(1);
+  }
+  if (chdir(pw->pw_dir) == -1) {
+     mkmsg("can't cd ", pw->pw_dir);
+     _exit(111);
+  }
  
   numenv = 0;
   while (environ[numenv]) ++numenv;
--- ../checkpassword-0.81-orig/conf-qmail	Fri Feb 11 15:32:45 2000
+++ conf-qmail	Fri Feb 11 15:29:03 2000
@@ -0,0 +1 @@
+/var/qmail
--- ../checkpassword-0.81-orig/connect_mysql.c	Fri Feb 11 15:32:45 2000
+++ connect_mysql.c	Fri Feb 11 10:20:51 2000
@@ -0,0 +1,41 @@
+#include <mysql/mysql.h>
+#include  "stralloc.h"
+
+#define TRIES 3
+
+/* let's alloc our strallocs */
+extern stralloc DB_HOST;
+extern stralloc DB_USER;
+extern stralloc DB_PASS;
+extern stralloc DB_NAME;
+extern stralloc DB_SOCK;
+extern stralloc DB_PORT;
+
+extern MYSQL dbh, *mysql;
+
+/* connect to the database                                                    */
+int connect_mysql() {
+  char *sock;
+  int i, port;
+
+  if (mysql) return 1;
+  if (init_mysql() == -1) return -1;
+  if (DB_PORT.a > 0) port = atoi(DB_PORT.s);
+  else port = 0;
+  if (DB_SOCK.a > 0) sock = DB_SOCK.s;
+  else sock = (char) 0;
+  for (i = 0; i < TRIES; i++) {
+    mysql = mysql_real_connect(&dbh, DB_HOST.s, DB_USER.s, DB_PASS.s, DB_NAME.s,
+                               port, sock, 0);
+    if (mysql) break;
+    splog("mysql-error", mysql_error(&dbh));
+    sleep(3);
+  }
+
+  if (i < TRIES) return 1;
+  else return 0;
+}
+
+void disconnect_mysql() {
+  mysql_close(&dbh);
+}
--- ../checkpassword-0.81-orig/do_query.c	Fri Feb 11 15:32:45 2000
+++ do_query.c	Fri Feb 11 12:16:49 2000
@@ -0,0 +1,47 @@
+#include <mysql/mysql.h>
+#include "stralloc.h"
+
+extern MYSQL dbh, *mysql;
+extern MYSQL_RES *result;
+
+extern splog();
+
+/* run a given query and return 1 row only */
+MYSQL_ROW do_query(stralloc *query) {
+  int num;
+#ifndef O_NOT_LOG_SQL
+  int i;
+  char *x;
+  stralloc showme = { 0 };
+#endif
+
+  if (! connect_mysql()) return -1;
+#ifndef O_NOT_LOG_SQL
+  if (! stralloc_ready(&showme, query->a)) goto carryon;
+  num = i = 0;
+  for (x = query->s; num < 2; x++) {
+    if (*x == '(' || *x == ')') num++;
+    if (! num) i++;
+  }
+  if (! stralloc_catb(&showme, query->s, i)) goto carryon;
+  if (! stralloc_cats(&showme, x)) goto carryon;
+  if (! stralloc_0(&showme)) goto carryon;
+  splog("qmail-mysql", showme.s);
+carryon:
+#endif
+  if (mysql_real_query(mysql, query->s, query->len) < 0) {
+    splog("mysql-error", mysql_error(&dbh));
+    return -1;
+  }
+  if (! (result = mysql_store_result(mysql))) return -1;
+
+  num = mysql_num_rows(result);
+
+  if (num != 1) {
+    mysql_free_result(result);
+    return 0;
+  }
+
+  return mysql_fetch_row(result);
+}
+
--- ../checkpassword-0.81-orig/fmt.h	Fri Feb 11 15:32:45 2000
+++ fmt.h	Fri Feb 11 10:33:49 2000
@@ -0,0 +1,25 @@
+#ifndef FMT_H
+#define FMT_H
+
+#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
+#define FMT_LEN ((char *) 0) /* convenient abbreviation */
+
+extern unsigned int fmt_uint();
+extern unsigned int fmt_uint0();
+extern unsigned int fmt_xint();
+extern unsigned int fmt_nbbint();
+extern unsigned int fmt_ushort();
+extern unsigned int fmt_xshort();
+extern unsigned int fmt_nbbshort();
+extern unsigned int fmt_ulong();
+extern unsigned int fmt_xlong();
+extern unsigned int fmt_nbblong();
+
+extern unsigned int fmt_plusminus();
+extern unsigned int fmt_minus();
+extern unsigned int fmt_0x();
+
+extern unsigned int fmt_str();
+extern unsigned int fmt_strn();
+
+#endif
--- ../checkpassword-0.81-orig/fmt_uint.c	Fri Feb 11 15:32:45 2000
+++ fmt_uint.c	Fri Feb 11 11:10:38 2000
@@ -0,0 +1,6 @@
+#include "fmt.h"
+
+unsigned int fmt_uint(s,u) register char *s; register unsigned int u;
+{
+  register unsigned long l; l = u; return fmt_ulong(s,l);
+}
--- ../checkpassword-0.81-orig/fmt_uint0.c	Fri Feb 11 15:32:45 2000
+++ fmt_uint0.c	Fri Feb 11 11:10:21 2000
@@ -0,0 +1,10 @@
+#include "fmt.h"
+
+unsigned int fmt_uint0(s,u,n) char *s; unsigned int u; unsigned int n;
+{
+  unsigned int len;
+  len = fmt_uint(FMT_LEN,u);
+  while (len < n) { if (s) *s++ = '0'; ++len; }
+  if (s) fmt_uint(s,u);
+  return len;
+}
--- ../checkpassword-0.81-orig/fmt_ulong.c	Fri Feb 11 15:32:46 2000
+++ fmt_ulong.c	Fri Feb 11 11:10:21 2000
@@ -0,0 +1,13 @@
+#include "fmt.h"
+
+unsigned int fmt_ulong(s,u) register char *s; register unsigned long u;
+{
+  register unsigned int len; register unsigned long q;
+  len = 1; q = u;
+  while (q > 9) { ++len; q /= 10; }
+  if (s) {
+    s += len;
+    do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
+  }
+  return len;
+}
--- ../checkpassword-0.81-orig/gen_alloc.h	Fri Feb 11 15:32:46 2000
+++ gen_alloc.h	Fri Feb 11 10:25:26 2000
@@ -0,0 +1,7 @@
+#ifndef GEN_ALLOC_H
+#define GEN_ALLOC_H
+
+#define GEN_ALLOC_typedef(ta,type,field,len,a) \
+  typedef struct ta { type *field; unsigned int len; unsigned int a; } ta;
+
+#endif
--- ../checkpassword-0.81-orig/gen_allocdefs.h	Fri Feb 11 15:32:46 2000
+++ gen_allocdefs.h	Fri Feb 11 10:25:26 2000
@@ -0,0 +1,34 @@
+#ifndef GEN_ALLOC_DEFS_H
+#define GEN_ALLOC_DEFS_H
+
+#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \
+int ta_ready(x,n) register ta *x; register unsigned int n; \
+{ register unsigned int i; \
+  if (x->field) { \
+    i = x->a; \
+    if (n > i) { \
+      x->a = base + n + (n >> 3); \
+      if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
+      x->a = i; return 0; } \
+    return 1; } \
+  x->len = 0; \
+  return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
+
+#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \
+int ta_rplus(x,n) register ta *x; register unsigned int n; \
+{ register unsigned int i; \
+  if (x->field) { \
+    i = x->a; n += x->len; \
+    if (n > i) { \
+      x->a = base + n + (n >> 3); \
+      if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
+      x->a = i; return 0; } \
+    return 1; } \
+  x->len = 0; \
+  return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
+
+#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \
+int ta_append(x,i) register ta *x; register type *i; \
+{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
+
+#endif
--- ../checkpassword-0.81-orig/getln.c	Fri Feb 11 15:32:46 2000
+++ getln.c	Fri Feb 11 10:55:23 2000
@@ -0,0 +1,20 @@
+#include "substdio.h"
+#include "byte.h"
+#include "stralloc.h"
+#include "getln.h"
+
+int getln(ss,sa,match,sep)
+register substdio *ss;
+register stralloc *sa;
+int *match;
+int sep;
+{
+  char *cont;
+  unsigned int clen;
+
+  if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1;
+  if (!clen) { *match = 0; return 0; }
+  if (!stralloc_catb(sa,cont,clen)) return -1;
+  *match = 1;
+  return 0;
+}
--- ../checkpassword-0.81-orig/getln.h	Fri Feb 11 15:32:46 2000
+++ getln.h	Fri Feb 11 10:55:23 2000
@@ -0,0 +1,7 @@
+#ifndef GETLN_H
+#define GETLN_H
+
+extern int getln();
+extern int getln2();
+
+#endif
--- ../checkpassword-0.81-orig/getln2.c	Fri Feb 11 15:32:46 2000
+++ getln2.c	Fri Feb 11 10:55:23 2000
@@ -0,0 +1,31 @@
+#include "substdio.h"
+#include "stralloc.h"
+#include "byte.h"
+#include "getln.h"
+
+int getln2(ss,sa,cont,clen,sep)
+register substdio *ss;
+register stralloc *sa;
+/*@out@*/char **cont;
+/*@out@*/unsigned int *clen;
+int sep;
+{
+  register char *x;
+  register unsigned int i;
+  int n;
+ 
+  if (!stralloc_ready(sa,0)) return -1;
+  sa->len = 0;
+ 
+  for (;;) {
+    n = substdio_feed(ss);
+    if (n < 0) return -1;
+    if (n == 0) { *clen = 0; return 0; }
+    x = substdio_PEEK(ss);
+    i = byte_chr(x,n,sep);
+    if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; }
+    if (!stralloc_readyplus(sa,n)) return -1;
+    i = sa->len;
+    sa->len = i + substdio_get(ss,sa->s + i,n);
+  }
+}
--- ../checkpassword-0.81-orig/getpw_mysql.c	Fri Feb 11 15:32:46 2000
+++ getpw_mysql.c	Fri Feb 11 15:10:51 2000
@@ -0,0 +1,75 @@
+#include <mysql/mysql.h>
+#include <pwd.h>
+#include "mysql_queries.h"
+#include "str.h"
+#include "stralloc.h"
+
+stralloc user = { 0 };
+stralloc home = { 0 };
+stralloc shell = { 0 };
+
+extern MYSQL dbh, *mysql;
+extern MYSQL_RES *result;
+
+extern void splog();
+extern void mkmsg();
+extern MYSQL_ROW do_query(stralloc *query);
+
+struct passwd mypw;
+
+/* get a pw entry from the database                                           */
+/* returns: struct passwd if the user logged in, 1 if the user got password   */
+/* wrong or 2 if the user didn't exist (-1 on error)                          */
+struct passwd *getpw_mysql(char *username, char *pass) {
+  int len, uid, gid;
+  MYSQL_ROW row;
+  stralloc passwd = { 0 };
+  stralloc query = { 0 };
+
+  len = str_len(pass);
+  if (! stralloc_ready(&passwd, len)) return -1;
+  len = str_len(POPSEL) + str_len(username) +
+        mysql_escape_string(passwd.s, pass, len) + 2;
+  if (! stralloc_ready(&query, len)) return -1;
+  if (! stralloc_cats(&query, POPSEL1)) return -1;
+  if (! stralloc_cats(&query, POPSEL2)) return -1;
+  if (! stralloc_cats(&query, passwd.s)) return -1;
+  if (! stralloc_cats(&query, POPSEL3)) return -1;
+  if (! stralloc_cats(&query, username)) return -1;
+  if (! stralloc_append(&query, "'")) return -1;
+  if (! stralloc_0(&query)) return -1;
+  
+  row = do_query(&query);
+  if ((int) row == -1) return -1;
+  if ((int) row == 0) {
+    mkmsg(username, " does not exist in database");
+    return 0;
+  }
+
+  if (str_diff(row[0], row[5])) {
+    mkmsg(username, " got password wrong");
+    return 1;
+  }
+
+  /* OK so we're assuming the database really does return ints */
+  uid = atoi(row[1]);
+  gid = atoi(row[2]);
+
+  if (! stralloc_ready(&user, str_len(username))) return -1;
+  if (! stralloc_copys(&user, username)) return -1;
+  if (! stralloc_0(&user)) return -1;
+  if (! stralloc_ready(&home, str_len(row[3]))) return -1;
+  if (! stralloc_copys(&home, row[3])) return -1;
+  if (! stralloc_0(&home)) return -1;
+  if (! stralloc_ready(&shell, str_len(row[4]))) return -1;
+  if (! stralloc_copys(&shell, row[4])) return -1;
+  if (! stralloc_0(&shell)) return -1;
+
+  mypw.pw_name = user.s;
+  mypw.pw_uid = uid;
+  mypw.pw_gid = gid;
+  mypw.pw_dir = home.s;
+  mypw.pw_shell = shell.s;
+  mkmsg("login by ", username);
+  return &mypw;
+}
--- ../checkpassword-0.81-orig/init_mysql.c	Fri Feb 11 15:32:46 2000
+++ init_mysql.c	Fri Feb 11 10:29:06 2000
@@ -0,0 +1,113 @@
+#include <mysql/mysql.h>
+#include <stdio.h>
+#include "auto_qmail.h"
+#include "readwrite.h"
+#include "str.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "subfd.h"
+
+#define SQLSERVER "/control/sqlserver"
+
+/* let's alloc our strallocs */
+stralloc DB_HOST = { 0 };
+stralloc DB_USER = { 0 };
+stralloc DB_PASS = { 0 };
+stralloc DB_NAME = { 0 };
+stralloc DB_SOCK = { 0 };
+stralloc DB_PORT = { 0 };
+
+static char inbuf[64];
+MYSQL dbh, *mysql;
+MYSQL_RES *result;
+
+/* read the config file and decide which server the database is on, what      */
+/* username and password we need to connect to it and which database to use   */
+/* return -1 if a bad error occurred, 0 if everything was OK or 1 if not      */
+int init_mysql() {
+  int i, error, file, match;
+  substdio ss;
+  stralloc filename = { 0 };
+  stralloc buf = { 0 };
+  
+  mysql = mysql_init(&dbh);
+  if (! mysql) return -1;
+
+  /* get the filename of the sqlserver control file */
+  i = str_len(SQLSERVER) + str_len(auto_qmail) + 1;
+  if (! stralloc_ready(&filename, i)) return -1;
+  if (! stralloc_cats(&filename, auto_qmail)) return -1;
+  if (! stralloc_cats(&filename, SQLSERVER)) return -1;
+  if (! stralloc_0(&filename)) return -1;
+  
+  /* try to open the file - much code robbed from control.c*/
+  file = open_read(filename.s);
+  if (file == -1) {
+    substdio_puts(subfderr, "warning: could not open sqlserver file ");
+    substdio_puts(subfderr, filename.s);
+    substdio_putsflush(subfderr, "\n");
+    return 0;
+  }
+  substdio_fdbuf(&ss, read, file, inbuf, sizeof(inbuf));
+  
+  i = 0;
+  while (getln(&ss, &buf, &match, '\n') != -1) {
+    if (! match && ! buf.len) break;
+    buf.len--;
+    if (! stralloc_0(&buf)) break;
+    /* we consider only lines starting with the letters s,l,p or d */
+    switch (buf.s[0]) {
+      case 's':
+        if (buf.s[1] == 'e') error = getconfig(&buf, "server", &DB_HOST);
+        else error = getconfig(&buf, "socket", &DB_SOCK);
+        break;
+      case 'l': error = getconfig(&buf, "login", &DB_USER); break;
+      case 'p':
+        if (buf.s[1] == 'a') error = getconfig(&buf, "password", &DB_PASS);
+        else error = getconfig(&buf, "port", &DB_PORT);
+        break;
+      case 'd': error = getconfig(&buf, "db", &DB_NAME); break;
+      default: continue;
+    }
+    if (error == -1) {
+      i = -1;
+      continue;
+    }
+    else i += error;
+    if (! match) break;
+  }
+  close(file);
+
+  if (i == -1)
+    substdio_putsflush(subfderr, "warning: there were errors reading sqlserver file\n");
+  else if (i > 0) {
+    substdio_putsflush(subfderr, "warning: bogus lines in sqlserver file\n");
+    i = 0;
+  }
+  return i;
+}
+
+/* read lines in the config file and grok entries of the form "x=y" or "x y"  */
+/* got is the line in the file, expected is the parmeter we're checking for   */
+/* and store is a stralloc to put the result into if it was found             */
+int getconfig(stralloc *got, char *expected, stralloc *store) {
+  char *value, *x;
+
+  x = got->s + str_len(expected);
+  value = x + 1;
+  /* we got a meaningful value */
+  if (! stralloc_starts(&got, expected) && (*x == ' ' || *x == '=') && str_len(value) > 0) {
+    if (! stralloc_ready(store, str_len(value))) return -1;
+    if (! stralloc_cats(store, value)) return -1;
+    if (! stralloc_0(store)) return -1;
+    return 0;
+  }
+  /* oh dear, the line we got didn't contain what we expected it to */
+  substdio_puts(subfderr, "error reading sqlserver file: expected '");
+  substdio_puts(subfderr, expected);
+  substdio_puts(subfderr, "' but got '");
+  substdio_puts(subfderr, got);
+  substdio_putsflush(subfderr, "'\n");
+  /* of course, we might have been expecting the wrong thing... */
+  return 1;
+}
--- ../checkpassword-0.81-orig/mkmsg.c	Fri Feb 11 15:32:46 2000
+++ mkmsg.c	Fri Feb 11 13:28:06 2000
@@ -0,0 +1,13 @@
+#include "stralloc.h"
+extern stralloc message;
+
+void mkmsg(char *part1, char *part2) {
+#ifndef O_NOT_LOG
+    if (! stralloc_ready(&message, str_len(part1) + str_len(part2) + 1)) return;
+    message.len = 0;
+    if (! stralloc_cats(&message, part1)) return;
+    if (! stralloc_cats(&message, part2)) return;
+    if (! stralloc_0(&message)) return;
+    splog("checkpassword", message.s);
+#endif
+}
--- ../checkpassword-0.81-orig/mysql_queries.h	Fri Feb 11 15:32:46 2000
+++ mysql_queries.h	Fri Feb 11 14:34:22 2000
@@ -0,0 +1,17 @@
+/* choose whether to use MySQL passwords here */
+/* if you define CRYPT_SUCKS you must define USE_MYSQL_PASSWORDS or           */
+/* USE_PLAINTEXT_PASSWORDS                                                    */
+
+/* this select is for POP3 */
+#define POPSEL1 "select password, uid, gid, home, '/bin/false', "
+#ifdef USE_MYSQL_PASSWORDS
+#define POPSEL2 "password('"
+#else
+#ifdef USE_PLAINTEXT_PASSWORDS
+#define POPSEL2 "('"
+#else
+#define POPSEL2 "encrypt('"
+#endif
+#endif
+#define POPSEL3 "') from mailbox where username='"
+#define POPSEL POPSEL1 POPSEL2 POPSEL3
--- ../checkpassword-0.81-orig/ptest.c	Fri Feb 11 15:32:46 2000
+++ ptest.c	Fri Feb 11 15:00:55 2000
@@ -0,0 +1,24 @@
+#include <pwd.h>
+#include "stralloc.h"
+
+extern getpw_mysql();
+stralloc message = { 0 };
+
+int main(int argc, char **argv) {
+  struct passwd *pw;
+
+  if (argc < 3) {
+    puts("usage: ptest username password");
+    return die();
+  }
+  pw = getpw_mysql(argv[1], argv[2]);
+  if ((int) pw < 3) return die();
+  printf("%s:*:%d:%d:%s:%s\n", pw->pw_name, pw->pw_uid, pw->pw_gid,
+                               pw->pw_dir, pw->pw_shell);
+  return 0;
+}
+
+int die() {
+  if (message.len) puts(message.s);
+  return 111;
+}
--- ../checkpassword-0.81-orig/scan.h	Fri Feb 11 15:32:46 2000
+++ scan.h	Fri Feb 11 10:33:49 2000
@@ -0,0 +1,27 @@
+#ifndef SCAN_H
+#define SCAN_H
+
+extern unsigned int scan_uint();
+extern unsigned int scan_xint();
+extern unsigned int scan_nbbint();
+extern unsigned int scan_ushort();
+extern unsigned int scan_xshort();
+extern unsigned int scan_nbbshort();
+extern unsigned int scan_ulong();
+extern unsigned int scan_xlong();
+extern unsigned int scan_nbblong();
+
+extern unsigned int scan_plusminus();
+extern unsigned int scan_0x();
+
+extern unsigned int scan_whitenskip();
+extern unsigned int scan_nonwhitenskip();
+extern unsigned int scan_charsetnskip();
+extern unsigned int scan_noncharsetnskip();
+
+extern unsigned int scan_strncmp();
+extern unsigned int scan_memcmp();
+
+extern unsigned int scan_long();
+
+#endif
--- ../checkpassword-0.81-orig/splog.c	Fri Feb 11 15:32:46 2000
+++ splog.c	Fri Feb 11 09:41:50 2000
@@ -0,0 +1,75 @@
+#ifndef O_NOT_LOG
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include "error.h"
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+#include "str.h"
+#include "scan.h"
+#include "fmt.h"
+
+char buf[800]; /* syslog truncates long lines (or crashes); GPACIC */
+int bufpos = 0; /* 0 <= bufpos < sizeof(buf) */
+int flagcont = 0;
+int priority; /* defined if flagcont */
+char stamp[FMT_ULONG + FMT_ULONG + 3]; /* defined if flagcont */
+
+void stamp_make()
+{
+  struct timeval tv;
+  char *s;
+  gettimeofday(&tv,(struct timezone *) 0);
+  s = stamp;
+  s += fmt_ulong(s,(unsigned long) tv.tv_sec);
+  *s++ = '.';
+  s += fmt_uint0(s,(unsigned int) tv.tv_usec,6);
+  *s = 0;
+}
+
+void splogflush()
+{
+  if (bufpos) {
+    buf[bufpos] = 0;
+    if (flagcont)
+      syslog(priority,"%s+%s",stamp,buf); /* logger folds invisibly; GPACIC */
+    else {
+      stamp_make();
+      priority = LOG_INFO;
+      if (str_start(buf,"warning:")) priority = LOG_WARNING;
+      if (str_start(buf,"alert:")) priority = LOG_ALERT;
+      syslog(priority,"%s %s",stamp,buf);
+      flagcont = 1;
+    }
+  }
+  bufpos = 0;
+}
+
+void splog(char *splogger, char *message)
+{
+  int i;
+  int max = sizeof(buf) - 1;
+
+  openlog(splogger, 0, LOG_MAIL);
+  for (i = 0; *message != '\0' && i < max - 1; i++) {
+    if (*message == '\n') { splogflush(); flagcont = 0; continue; }
+    if (bufpos == max) splogflush();
+    if ((*message < 32) || (*message > 126))
+      *message = '?'; /* logger truncates at 0; GPACIC */
+    buf[bufpos++] = *message++;
+  }
+  if (bufpos < max) {
+    i++;
+    buf[bufpos++] = '\n';
+    splogflush();
+  }
+  closelog();
+  return;
+//if (i == max && *message != '\0') return 1;
+//return 0;
+}
+#else
+void splog(char *splogger, char *message) {
+}
+#endif
--- ../checkpassword-0.81-orig/str_cpy.c	Fri Feb 11 15:32:46 2000
+++ str_cpy.c	Fri Feb 11 13:38:24 2000
@@ -0,0 +1,16 @@
+#include "str.h"
+
+unsigned int str_copy(s,t)
+register char *s;
+register char *t;
+{
+  register int len;
+
+  len = 0;
+  for (;;) {
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+  }
+}
--- ../checkpassword-0.81-orig/str_diff.c	Fri Feb 11 15:32:46 2000
+++ str_diff.c	Fri Feb 11 11:04:32 2000
@@ -0,0 +1,17 @@
+#include "str.h"
+
+int str_diff(s,t)
+register char *s;
+register char *t;
+{
+  register char x;
+
+  for (;;) {
+    x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+    x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+    x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+    x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+  }
+  return ((int)(unsigned int)(unsigned char) x)
+       - ((int)(unsigned int)(unsigned char) *t);
+}
--- ../checkpassword-0.81-orig/str_start.c	Fri Feb 11 15:32:46 2000
+++ str_start.c	Fri Feb 11 11:05:52 2000
@@ -0,0 +1,15 @@
+#include "str.h"
+
+int str_start(s,t)
+register char *s;
+register char *t;
+{
+  register char x;
+
+  for (;;) {
+    x = *t++; if (!x) return 1; if (x != *s++) return 0;
+    x = *t++; if (!x) return 1; if (x != *s++) return 0;
+    x = *t++; if (!x) return 1; if (x != *s++) return 0;
+    x = *t++; if (!x) return 1; if (x != *s++) return 0;
+  }
+}
--- ../checkpassword-0.81-orig/stralloc.h	Fri Feb 11 15:32:46 2000
+++ stralloc.h	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,21 @@
+#ifndef STRALLOC_H
+#define STRALLOC_H
+
+#include "gen_alloc.h"
+
+GEN_ALLOC_typedef(stralloc,char,s,len,a)
+
+extern int stralloc_ready();
+extern int stralloc_readyplus();
+extern int stralloc_copy();
+extern int stralloc_cat();
+extern int stralloc_copys();
+extern int stralloc_cats();
+extern int stralloc_copyb();
+extern int stralloc_catb();
+extern int stralloc_append(); /* beware: this takes a pointer to 1 char */
+extern int stralloc_starts();
+
+#define stralloc_0(sa) stralloc_append(sa,"")
+
+#endif
--- ../checkpassword-0.81-orig/stralloc_arts.c	Fri Feb 11 15:32:46 2000
+++ stralloc_arts.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,12 @@
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_starts(sa,s)
+stralloc *sa;
+char *s;
+{
+  int len;
+  len = str_len(s);
+  return (sa->len >= len) && byte_equal(s,len,sa->s);
+}
--- ../checkpassword-0.81-orig/stralloc_cat.c	Fri Feb 11 15:32:46 2000
+++ stralloc_cat.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,9 @@
+#include "byte.h"
+#include "stralloc.h"
+
+int stralloc_cat(sato,safrom)
+stralloc *sato;
+stralloc *safrom;
+{
+  return stralloc_catb(sato,safrom->s,safrom->len);
+}
--- ../checkpassword-0.81-orig/stralloc_catb.c	Fri Feb 11 15:32:46 2000
+++ stralloc_catb.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,15 @@
+#include "stralloc.h"
+#include "byte.h"
+
+int stralloc_catb(sa,s,n)
+stralloc *sa;
+char *s;
+unsigned int n;
+{
+  if (!sa->s) return stralloc_copyb(sa,s,n);
+  if (!stralloc_readyplus(sa,n + 1)) return 0;
+  byte_copy(sa->s + sa->len,n,s);
+  sa->len += n;
+  sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
+  return 1;
+}
--- ../checkpassword-0.81-orig/stralloc_cats.c	Fri Feb 11 15:32:46 2000
+++ stralloc_cats.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,10 @@
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_cats(sa,s)
+stralloc *sa;
+char *s;
+{
+  return stralloc_catb(sa,s,str_len(s));
+}
--- ../checkpassword-0.81-orig/stralloc_copy.c	Fri Feb 11 15:32:46 2000
+++ stralloc_copy.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,9 @@
+#include "byte.h"
+#include "stralloc.h"
+
+int stralloc_copy(sato,safrom)
+stralloc *sato;
+stralloc *safrom;
+{
+  return stralloc_copyb(sato,safrom->s,safrom->len);
+}
--- ../checkpassword-0.81-orig/stralloc_eady.c	Fri Feb 11 15:32:46 2000
+++ stralloc_eady.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,6 @@
+#include "alloc.h"
+#include "stralloc.h"
+#include "gen_allocdefs.h"
+
+GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
+GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
--- ../checkpassword-0.81-orig/stralloc_opyb.c	Fri Feb 11 15:32:46 2000
+++ stralloc_opyb.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,14 @@
+#include "stralloc.h"
+#include "byte.h"
+
+int stralloc_copyb(sa,s,n)
+stralloc *sa;
+char *s;
+unsigned int n;
+{
+  if (!stralloc_ready(sa,n + 1)) return 0;
+  byte_copy(sa->s,n,s);
+  sa->len = n;
+  sa->s[n] = 'Z'; /* ``offensive programming'' */
+  return 1;
+}
--- ../checkpassword-0.81-orig/stralloc_opys.c	Fri Feb 11 15:32:46 2000
+++ stralloc_opys.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,10 @@
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_copys(sa,s)
+stralloc *sa;
+char *s;
+{
+  return stralloc_copyb(sa,s,str_len(s));
+}
--- ../checkpassword-0.81-orig/stralloc_pend.c	Fri Feb 11 15:32:46 2000
+++ stralloc_pend.c	Fri Feb 11 10:25:08 2000
@@ -0,0 +1,5 @@
+#include "alloc.h"
+#include "stralloc.h"
+#include "gen_allocdefs.h"
+
+GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
Binary files ../checkpassword-0.81-orig/strerr.a and strerr.a differ
Binary files ../checkpassword-0.81-orig/substdio.a and substdio.a differ
