1 /* vmautoconvert.c - Automatically convert passwords for vmailmgr.
2  * Copyright (C) 2010  Bruce Guenter <bruce@untroubled.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 #include <bglibs/sysdeps.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 
24 #include <bglibs/cdb.h>
25 #include <bglibs/iobuf.h>
26 #include <bglibs/path.h>
27 #include <bglibs/str.h>
28 #include <vmailmgr/vpwentry.h>
29 #include <bglibs/uint32.h>
30 
31 #include "module.h"
32 #include "qmail.h"
33 #include "cvm-vmailmgr.h"
34 
read_start(ibuf * in,uint32 * end)35 static int read_start(ibuf* in, uint32* end)
36 {
37   unsigned char buf[2048];
38   if (!ibuf_read(in, (char*)buf, sizeof buf))
39     return 0;
40   *end = uint32_get_lsb(buf);
41   return 1;
42 }
43 
read_cdb_pair(ibuf * in,str * key,str * data)44 static int read_cdb_pair(ibuf* in, str* key, str* data)
45 {
46   unsigned char buf[8];
47   uint32 keylen;
48   uint32 datalen;
49   if (!ibuf_read(in, (char*)buf, sizeof buf))
50     return 0;
51   keylen = uint32_get_lsb(buf);
52   datalen = uint32_get_lsb(buf+4);
53   if (!str_ready(key, keylen)
54       || !str_ready(data, datalen)
55       || !ibuf_read(in, key->s, keylen)
56       || !ibuf_read(in, data->s, datalen))
57     return 0;
58   key->s[key->len = keylen] = 0;
59   data->s[data->len = datalen] = 0;
60   return 1;
61 }
62 
63 static str tmppwfile;
64 static str key;
65 static str data;
66 
convert_data(void)67 static int convert_data(void)
68 {
69   struct vpwentry vpw;
70   int status = 1;
71   memset(&vpw, 0, sizeof vpw);
72   if (!vpwentry_import(&vpw, &virtuser, &data))
73     return 0;
74   status = str_copyb(&vpw.pass, "$0$", 3)
75     && str_cat(&vpw.pass, &cvm_module_credentials[CVM_CRED_PASSWORD])
76     && vpwentry_export(&vpw, &data);
77   vpwentry_free(&vpw);
78   return status;
79 }
80 
vmailmgr_autoconvert(void)81 int vmailmgr_autoconvert(void)
82 {
83   int writefd = -1;
84   ibuf reader;
85   struct cdb_make writer;
86   int error = 0;
87   int readall = 0;
88   int writerr = 0;
89   if ((writefd = path_mktemp(pwfile, &tmppwfile)) != -1) {
90 
91     if (cdb_make_start(&writer, writefd) != 0)
92       error = CVME_IO | CVME_FATAL;
93     else {
94 
95       if (ibuf_open(&reader, pwfile, 0)) {
96 
97 	uint32 end;
98 	struct stat st;
99 	if (fstat(reader.io.fd, &st) == 0
100 	    && fchmod(writefd, st.st_mode) == 0
101 	    && fchown(writefd, st.st_uid, st.st_gid) == 0
102 	    && read_start(&reader, &end)) {
103 	  while (ibuf_tell(&reader) < end) {
104 	    if (!read_cdb_pair(&reader, &key, &data))
105 	      break;
106 	    if (str_diff(&key, &virtuser) == 0)
107 	      if (!convert_data()) {
108 		writerr = 1;
109 		break;
110 	      }
111 	    if (cdb_make_add(&writer, key.s, key.len, data.s, data.len) != 0) {
112 	      writerr = 1;
113 	      break;
114 	    }
115 	  }
116 	  readall = ibuf_tell(&reader) == end;
117 	}
118 	ibuf_close(&reader);
119       }
120       if (cdb_make_finish(&writer) != 0)
121 	error |= CVME_FATAL;
122       else
123 	if (readall && !writerr)
124 	  rename(tmppwfile.s, pwfile);
125     }
126     close(writefd);
127     unlink(tmppwfile.s);
128   }
129   return error;
130 }
131