| 1 | #include <sys/types.h> |
| 2 | #include <sys/stat.h> |
| 3 | #include "substdio.h" |
| 4 | #include "readwrite.h" |
| 5 | #include "subfd.h" |
| 6 | #include "sgetopt.h" |
| 7 | #include "control.h" |
| 8 | #include "constmap.h" |
| 9 | #include "stralloc.h" |
| 10 | #include "fmt.h" |
| 11 | #include "str.h" |
| 12 | #include "scan.h" |
| 13 | #include "open.h" |
| 14 | #include "error.h" |
| 15 | #include "getln.h" |
| 16 | #include "auto_break.h" |
| 17 | #include "auto_qmail.h" |
| 18 | #include "auto_usera.h" |
| 19 | |
| 20 | void die_chdir() |
| 21 | { |
| 22 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to chdir\n"); |
| 23 | _exit(111); |
| 24 | } |
| 25 | void die_nomem() |
| 26 | { |
| 27 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: out of memory\n"); |
| 28 | _exit(111); |
| 29 | } |
| 30 | void die_read() |
| 31 | { |
| 32 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to read input\n"); |
| 33 | _exit(111); |
| 34 | } |
| 35 | void die_write() |
| 36 | { |
| 37 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to write output\n"); |
| 38 | _exit(111); |
| 39 | } |
| 40 | void die_control() |
| 41 | { |
| 42 | substdio_putsflush(subfderr,"qmail-pw2u: fatal: unable to read controls\n"); |
| 43 | _exit(111); |
| 44 | } |
| 45 | void die_alias() |
| 46 | { |
| 47 | substdio_puts(subfderr,"qmail-pw2u: fatal: unable to find "); |
| 48 | substdio_puts(subfderr,auto_usera); |
| 49 | substdio_puts(subfderr," user\n"); |
| 50 | substdio_flush(subfderr); |
| 51 | _exit(111); |
| 52 | } |
| 53 | void die_home(fn) char *fn; |
| 54 | { |
| 55 | substdio_puts(subfderr,"qmail-pw2u: fatal: unable to stat "); |
| 56 | substdio_puts(subfderr,fn); |
| 57 | substdio_puts(subfderr,"\n"); |
| 58 | substdio_flush(subfderr); |
| 59 | _exit(111); |
| 60 | } |
| 61 | void die_user(s,len) char *s; unsigned int len; |
| 62 | { |
| 63 | substdio_puts(subfderr,"qmail-pw2u: fatal: unable to find "); |
| 64 | substdio_put(subfderr,s,len); |
| 65 | substdio_puts(subfderr," user for subuser\n"); |
| 66 | substdio_flush(subfderr); |
| 67 | _exit(111); |
| 68 | } |
| 69 | |
| 70 | char *dashcolon = "-:"; |
| 71 | int flagalias = 0; |
| 72 | int flagnoupper = 1; |
| 73 | int homestrategy = 2; |
| 74 | /* 2: skip if home does not exist; skip if home is not owned by user */ |
| 75 | /* 1: stop if home does not exist; skip if home is not owned by user */ |
| 76 | /* 0: don't worry about home */ |
| 77 | |
| 78 | int okincl; stralloc incl = {0}; struct constmap mapincl; |
| 79 | int okexcl; stralloc excl = {0}; struct constmap mapexcl; |
| 80 | int okmana; stralloc mana = {0}; struct constmap mapmana; |
| 81 | |
| 82 | stralloc allusers = {0}; struct constmap mapuser; |
| 83 | |
| 84 | stralloc uugh = {0}; |
| 85 | stralloc user = {0}; |
| 86 | stralloc uidstr = {0}; |
| 87 | stralloc gidstr = {0}; |
| 88 | stralloc home = {0}; |
| 89 | unsigned long uid; |
| 90 | |
| 91 | stralloc line = {0}; |
| 92 | |
| 93 | void doaccount() |
| 94 | { |
| 95 | struct stat st; |
| 96 | int i; |
| 97 | char *mailnames; |
| 98 | char *x; |
| 99 | unsigned int xlen; |
| 100 | |
| 101 | if (byte_chr(line.s,line.len,'\0') < line.len) return; |
| 102 | |
| 103 | x = line.s; xlen = line.len; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 104 | if (!stralloc_copyb(&user,x,i)) die_nomem(); |
| 105 | if (!stralloc_0(&user)) die_nomem(); |
| 106 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 107 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 108 | if (!stralloc_copyb(&uidstr,x,i)) die_nomem(); |
| 109 | if (!stralloc_0(&uidstr)) die_nomem(); |
| 110 | scan_ulong(uidstr.s,&uid); |
| 111 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 112 | if (!stralloc_copyb(&gidstr,x,i)) die_nomem(); |
| 113 | if (!stralloc_0(&gidstr)) die_nomem(); |
| 114 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 115 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 116 | if (!stralloc_copyb(&home,x,i)) die_nomem(); |
| 117 | if (!stralloc_0(&home)) die_nomem(); |
| 118 | |
| 119 | if (!uid) return; |
| 120 | if (flagnoupper) |
| 121 | for (i = 0;i < user.len;++i) |
| 122 | if ((user.s[i] >= 'A') && (user.s[i] <= 'Z')) |
| 123 | return; |
| 124 | if (okincl) |
| 125 | if (!constmap(&mapincl,user.s,user.len - 1)) |
| 126 | return; |
| 127 | if (okexcl) |
| 128 | if (constmap(&mapexcl,user.s,user.len - 1)) |
| 129 | return; |
| 130 | if (homestrategy) { |
| 131 | if (stat(home.s,&st) == -1) { |
| 132 | if (errno != error_noent) die_home(home.s); |
| 133 | if (homestrategy == 1) die_home(home.s); |
| 134 | return; |
| 135 | } |
| 136 | if (st.st_uid != uid) return; |
| 137 | } |
| 138 | |
| 139 | if (!stralloc_copys(&uugh,":")) die_nomem(); |
| 140 | if (!stralloc_cats(&uugh,user.s)) die_nomem(); |
| 141 | if (!stralloc_cats(&uugh,":")) die_nomem(); |
| 142 | if (!stralloc_cats(&uugh,uidstr.s)) die_nomem(); |
| 143 | if (!stralloc_cats(&uugh,":")) die_nomem(); |
| 144 | if (!stralloc_cats(&uugh,gidstr.s)) die_nomem(); |
| 145 | if (!stralloc_cats(&uugh,":")) die_nomem(); |
| 146 | if (!stralloc_cats(&uugh,home.s)) die_nomem(); |
| 147 | if (!stralloc_cats(&uugh,":")) die_nomem(); |
| 148 | |
| 149 | /* XXX: avoid recording in allusers unless sub actually needs it */ |
| 150 | if (!stralloc_cats(&allusers,user.s)) die_nomem(); |
| 151 | if (!stralloc_cats(&allusers,":")) die_nomem(); |
| 152 | if (!stralloc_catb(&allusers,uugh.s,uugh.len)) die_nomem(); |
| 153 | if (!stralloc_0(&allusers)) die_nomem(); |
| 154 | |
| 155 | if (str_equal(user.s,auto_usera)) { |
| 156 | if (substdio_puts(subfdout,"+") == -1) die_write(); |
| 157 | if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write(); |
| 158 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); |
| 159 | if (substdio_puts(subfdout,":\n") == -1) die_write(); |
| 160 | flagalias = 1; |
| 161 | } |
| 162 | |
| 163 | mailnames = 0; |
| 164 | if (okmana) |
| 165 | mailnames = constmap(&mapmana,user.s,user.len - 1); |
| 166 | if (!mailnames) |
| 167 | mailnames = user.s; |
| 168 | |
| 169 | for (;;) { |
| 170 | while (*mailnames == ':') ++mailnames; |
| 171 | if (!*mailnames) break; |
| 172 | |
| 173 | i = str_chr(mailnames,':'); |
| 174 | |
| 175 | if (substdio_puts(subfdout,"=") == -1) die_write(); |
| 176 | if (substdio_put(subfdout,mailnames,i) == -1) die_write(); |
| 177 | if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write(); |
| 178 | if (substdio_puts(subfdout,"::\n") == -1) die_write(); |
| 179 | |
| 180 | if (*auto_break) { |
| 181 | if (substdio_puts(subfdout,"+") == -1) die_write(); |
| 182 | if (substdio_put(subfdout,mailnames,i) == -1) die_write(); |
| 183 | if (substdio_put(subfdout,auto_break,1) == -1) die_write(); |
| 184 | if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write(); |
| 185 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); |
| 186 | if (substdio_puts(subfdout,":\n") == -1) die_write(); |
| 187 | } |
| 188 | |
| 189 | mailnames += i; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | stralloc sub = {0}; |
| 194 | |
| 195 | void dosubuser() |
| 196 | { |
| 197 | int i; |
| 198 | char *x; |
| 199 | unsigned int xlen; |
| 200 | char *uugh; |
| 201 | |
| 202 | x = line.s; xlen = line.len; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 203 | if (!stralloc_copyb(&sub,x,i)) die_nomem(); |
| 204 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 205 | uugh = constmap(&mapuser,x,i); |
| 206 | if (!uugh) die_user(x,i); |
| 207 | ++i; x += i; xlen -= i; i = byte_chr(x,xlen,':'); if (i == xlen) return; |
| 208 | |
| 209 | if (substdio_puts(subfdout,"=") == -1) die_write(); |
| 210 | if (substdio_put(subfdout,sub.s,sub.len) == -1) die_write(); |
| 211 | if (substdio_puts(subfdout,uugh) == -1) die_write(); |
| 212 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); |
| 213 | if (substdio_put(subfdout,x,i) == -1) die_write(); |
| 214 | if (substdio_puts(subfdout,":\n") == -1) die_write(); |
| 215 | |
| 216 | if (*auto_break) { |
| 217 | if (substdio_puts(subfdout,"+") == -1) die_write(); |
| 218 | if (substdio_put(subfdout,sub.s,sub.len) == -1) die_write(); |
| 219 | if (substdio_put(subfdout,auto_break,1) == -1) die_write(); |
| 220 | if (substdio_puts(subfdout,uugh) == -1) die_write(); |
| 221 | if (substdio_puts(subfdout,dashcolon) == -1) die_write(); |
| 222 | if (substdio_put(subfdout,x,i) == -1) die_write(); |
| 223 | if (substdio_puts(subfdout,"-:\n") == -1) die_write(); |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | int fd; |
| 228 | substdio ss; |
| 229 | char ssbuf[SUBSTDIO_INSIZE]; |
| 230 | |
| 231 | void main(argc,argv) |
| 232 | int argc; |
| 233 | char **argv; |
| 234 | { |
| 235 | int opt; |
| 236 | int match; |
| 237 | |
| 238 | while ((opt = getopt(argc,argv,"/ohHuUc:C")) != opteof) |
| 239 | switch(opt) { |
| 240 | case '/': dashcolon = "-/:"; break; |
| 241 | case 'o': homestrategy = 2; break; |
| 242 | case 'h': homestrategy = 1; break; |
| 243 | case 'H': homestrategy = 0; break; |
| 244 | case 'u': flagnoupper = 0; break; |
| 245 | case 'U': flagnoupper = 1; break; |
| 246 | case 'c': *auto_break = *optarg; break; |
| 247 | case 'C': *auto_break = 0; break; |
| 248 | case '?': |
| 249 | default: |
| 250 | _exit(100); |
| 251 | } |
| 252 | |
| 253 | if (chdir(auto_qmail) == -1) die_chdir(); |
| 254 | |
| 255 | /* no need for control_init() */ |
| 256 | |
| 257 | okincl = control_readfile(&incl,"users/include",0); |
| 258 | if (okincl == -1) die_control(); |
| 259 | if (okincl) if (!constmap_init(&mapincl,incl.s,incl.len,0)) die_nomem(); |
| 260 | |
| 261 | okexcl = control_readfile(&excl,"users/exclude",0); |
| 262 | if (okexcl == -1) die_control(); |
| 263 | if (okexcl) if (!constmap_init(&mapexcl,excl.s,excl.len,0)) die_nomem(); |
| 264 | |
| 265 | okmana = control_readfile(&mana,"users/mailnames",0); |
| 266 | if (okmana == -1) die_control(); |
| 267 | if (okmana) if (!constmap_init(&mapmana,mana.s,mana.len,1)) die_nomem(); |
| 268 | |
| 269 | if (!stralloc_copys(&allusers,"")) die_nomem(); |
| 270 | |
| 271 | for (;;) { |
| 272 | if (getln(subfdin,&line,&match,'\n') == -1) die_read(); |
| 273 | doaccount(); |
| 274 | if (!match) break; |
| 275 | } |
| 276 | if (!flagalias) die_alias(); |
| 277 | |
| 278 | fd = open_read("users/subusers"); |
| 279 | if (fd == -1) { |
| 280 | if (errno != error_noent) die_control(); |
| 281 | } |
| 282 | else { |
| 283 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); |
| 284 | |
| 285 | if (!constmap_init(&mapuser,allusers.s,allusers.len,1)) die_nomem(); |
| 286 | |
| 287 | for (;;) { |
| 288 | if (getln(&ss,&line,&match,'\n') == -1) die_read(); |
| 289 | dosubuser(); |
| 290 | if (!match) break; |
| 291 | } |
| 292 | |
| 293 | close(fd); |
| 294 | } |
| 295 | |
| 296 | fd = open_read("users/append"); |
| 297 | if (fd == -1) { |
| 298 | if (errno != error_noent) die_control(); |
| 299 | } |
| 300 | else { |
| 301 | substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); |
| 302 | for (;;) { |
| 303 | if (getln(&ss,&line,&match,'\n') == -1) die_read(); |
| 304 | if (substdio_put(subfdout,line.s,line.len) == -1) die_write(); |
| 305 | if (!match) break; |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | if (substdio_puts(subfdout,".\n") == -1) die_write(); |
| 310 | if (substdio_flush(subfdout) == -1) die_write(); |
| 311 | _exit(0); |
| 312 | } |