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