1 /*
2  * $Id: vcdb.c 1014 2011-02-03 16:04:37Z volz0r $
3  * Copyright (C) 1999-2009 Inter7 Internet Technologies, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  */
19 /******************************************************************************
20 **
21 ** $Id: vcdb.c 1014 2011-02-03 16:04:37Z volz0r $
22 ** Change a domain's password file to a CDB database
23 **
24 ** Chris Johnson, July 1998
25 **
26 ******************************************************************************/
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <pwd.h>
34 #include <sys/time.h>
35 #include <time.h>
36 #include <utime.h>
37 #include <sys/types.h>
38 #include <cdbmake.h>
39 #include "config.h"
40 #include "vpopmail.h"
41 #include "vauth.h"
42 #include "vcdb.h"
43 #include "file_lock.h"
44 #include "vlimits.h"
45 
46 #define TOKENS " \n"
47 
48 char *dc_filename(char *domain, uid_t uid, gid_t gid);
49 void vcdb_strip_char( char *instr );
50 
51 char sqlerr[MAX_BUFF] = "";
52 char *last_query = NULL;
53 
54 extern int cdb_seek();
55 
56 static char vpasswd_file[MAX_BUFF];
57 static char vpasswd_bak_file[MAX_BUFF];
58 static char vpasswd_cdb_file[MAX_BUFF];
59 static char vpasswd_cdb_tmp_file[MAX_BUFF];
60 static char vpasswd_lock_file[MAX_BUFF];
61 static char vpasswd_dir[MAX_BUFF];
62 static char TmpBuf1[MAX_BUFF];
63 
make_vpasswd_cdb(char * domain)64 int make_vpasswd_cdb(char *domain)
65 {
66  char pwline[256];
67  char packbuf[8];
68  char *key;
69  char *data;
70  char *ptr;
71  int i,j,h;
72  int len;
73  long unsigned keylen,datalen;
74  uint32 pos,op;
75  struct cdbmake cdbm;
76  FILE *pwfile, *tmfile;
77  char Dir[156];
78  uid_t uid;
79  gid_t gid;
80  char *tmpstr;
81  mode_t oldmask;
82 
83     /* If we don't optimize the index this time, just return */
84     if ( NoMakeIndex == 1 ) return(0);
85 
86     if ((pwfile = fopen(vpasswd_file,"r")) == NULL) {
87         return(-1);
88     }
89 
90     cdbmake_init(&cdbm);
91 
92     /* temporarily set umask (no group/other access) and open temp file */
93     oldmask = umask(VPOPMAIL_UMASK);
94     tmfile = fopen(vpasswd_cdb_tmp_file,"w");
95     umask(oldmask);
96 
97     if (tmfile == NULL) {
98         fprintf(stderr,"Error: could not create/open temporary file\n");
99         return(-1);
100     }
101 
102     for (i=0; i < (int)sizeof(cdbm.final); i++) {
103         if (putc(' ',tmfile) == EOF) {
104                 fprintf(stderr,"Error:error writing temp file\n");
105             return(-1);
106         }
107     }
108     pos = sizeof(cdbm.final);
109 
110     /* creation **/
111     fgets(pwline,sizeof(pwline),pwfile);
112     while (!feof(pwfile)) {
113         key = pwline; ptr = pwline;
114         while (*ptr != ':') { ptr++; }
115         *ptr = 0; data = ptr; data++;
116         while (*ptr != '\n') { ptr++; }
117         *ptr = 0;
118         keylen = strlen(key); datalen = strlen(data);
119 #ifdef VPOPMAIL_DEBUG
120         fprintf (stderr,"Got entry: keylen = %lu, key = %s\n           datalen = %lu, data = %s\n",keylen,key,datalen,data);
121 #endif
122 
123         cdbmake_pack(packbuf, (uint32)keylen);
124         cdbmake_pack(packbuf + 4, (uint32)datalen);
125         if (fwrite(packbuf,1,8,tmfile) < 8) {
126             fprintf(stderr,"Error: error writing temp file\n");
127             return(-1);
128         }
129 
130         h = CDBMAKE_HASHSTART;
131         for (i=0; i < (int)keylen; i++) {
132             h = cdbmake_hashadd(h,key[i]);
133             if (putc(key[i],tmfile) == EOF) {
134                 fprintf (stderr,"Error: error temp file\n");
135                 return(-1);
136             }
137         }
138         for (i=0; i < (int)datalen; i++) {
139             if (putc(data[i],tmfile) == EOF) {
140                 fprintf (stderr,"Error: write error temp file");
141                 return(-1);
142             }
143         }
144         if (!cdbmake_add(&cdbm,h,pos,malloc)) {
145             fprintf(stderr, "Error: out of memory\n");
146             return(-1);
147         }
148 
149         op = pos;
150         pos += (uint32)8;
151         pos += (uint32)keylen;
152         pos += (uint32)datalen;
153         if (pos < op) {
154             fprintf(stderr,"Error: too much data\n");
155             return(-1);
156         }
157         if (!cdbmake_split(&cdbm,malloc)) {
158             fprintf(stderr,"Error: out of memory\n");
159             return(-1);
160         }
161         fgets(pwline,sizeof(pwline),pwfile);
162         free(cdbm.split);
163     }
164     fclose(pwfile);
165 
166     if (!cdbmake_split(&cdbm,malloc)) {
167         fprintf(stderr, "Error: out of memory\n");
168         return(-1);
169     }
170 
171     for (i=0; i < 256; i++) {
172         len = cdbmake_throw(&cdbm,pos,i);
173         for (j=0; j < len; j++) {
174             cdbmake_pack(packbuf,cdbm.hash[j].h);
175             cdbmake_pack(packbuf + 4, cdbm.hash[j].p);
176             if (fwrite(packbuf,1,8,tmfile) < 8) {
177                 fprintf(stderr,"Error 1: error temp file\n");
178                 return(-1);
179             }
180             op = pos;
181             pos += (uint32)8;
182             if (pos < op) {
183                 fprintf (stderr, "Error 12: too much data\n");
184                 return(-1);
185             }
186         }
187     }
188     if (fflush(tmfile) == EOF) {
189         fprintf (stderr,"Error 20: write error temp file\n");
190         return(-1);
191     }
192     rewind(tmfile);
193     if (fwrite(cdbm.final,1,sizeof(cdbm.final),tmfile)<sizeof(cdbm.final)){
194         fprintf(stderr,"Error 21: write error temp file\n");
195         return(-1);
196     }
197     if (fflush(tmfile) == EOF) {
198         fprintf(stderr,"Error 22: write error temp file\n");
199         return(-1);
200     }
201 
202     if (close(fileno(tmfile)) == -1) {
203         fprintf(stderr,"Error 24: error with close()\n");
204         return(-1);
205     }
206     if (rename(vpasswd_cdb_tmp_file,vpasswd_cdb_file)) {
207         fprintf(stderr,
208             "Error 25: could not rename cdb.tmp to vpasswd.cdb\n");
209         return(-1);
210     }
211     free(cdbm.head);
212     free(cdbm.split);
213 
214     tmpstr = vget_assign(domain, Dir, 156, &uid, &gid );
215     chown(vpasswd_cdb_file, uid, gid);
216     chown(vpasswd_lock_file, uid, gid);
217     chown(vpasswd_file, uid, gid);
218 
219     return 0;
220 }
221 
vauth_getpw(char * user,char * domain)222 struct vqpasswd *vauth_getpw(char *user, char *domain)
223 {
224  char in_domain[156];
225  static struct vqpasswd pwent;
226  static char line[2048];
227  char *ptr = NULL, *uid = NULL, *gid = NULL;
228  uid_t myuid;
229  uid_t tuid;
230  gid_t tgid;
231  uint32 dlen;
232  int pwf;
233 #ifdef FILE_LOCKING
234  int lock_fd;
235 #endif
236 
237     verrori = 0;
238     lowerit(user);
239     lowerit(domain);
240 
241     if (vget_assign(domain,NULL,0,&tuid,&tgid) == NULL) {
242         /* domain does not exist */
243         return(NULL);
244     }
245 
246     myuid = geteuid();
247     if ( myuid != 0 && myuid != tuid ) {
248 	return(NULL);
249     }
250 
251     strncpy( in_domain, domain, sizeof(in_domain));
252     in_domain[sizeof(in_domain)-1] = '\0';  /* ensure NULL termination */
253 
254     set_vpasswd_files( in_domain );
255 
256     if ((pwf = open(vpasswd_cdb_file,O_RDONLY)) < 0 ) {
257 #ifdef FILE_LOCKING
258 		if ( (lock_fd=open(vpasswd_lock_file, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
259 			return(NULL);
260 		}
261 		get_write_lock( lock_fd );
262 #endif
263         make_vpasswd_cdb(domain);
264 #ifdef FILE_LOCKING
265 		unlock_lock(lock_fd, 0, SEEK_SET, 0);
266 		close(lock_fd);
267 #endif
268         if ((pwf = open(vpasswd_cdb_file,O_RDONLY)) < 0 ) {
269             return(NULL);
270         }
271     }
272 
273     strncpy(line,user,sizeof(line));
274     strncat(line,":",sizeof(line));
275     ptr = line;
276     while (*ptr != ':') { ptr++; }
277     ptr++;
278     switch (cdb_seek(pwf,user,strlen(user),&dlen)) {
279         case -1:
280         case 0:
281             close(pwf);
282             return NULL;
283     }
284     if (read(pwf, ptr,dlen) != (int)dlen) {
285         close(pwf);
286         return NULL;
287     }
288     close(pwf);
289     line[(dlen+strlen(user)+1)] = 0;
290 
291     pwent.pw_name   = "";
292     pwent.pw_passwd = "";
293     pwent.pw_gecos  = "";
294     pwent.pw_dir    = "";
295     pwent.pw_shell  = "";
296     pwent.pw_clear_passwd  = "";
297 
298     ptr = line;
299     pwent.pw_name    = line;
300     while (*ptr!=0&&*ptr != ':') { ptr++; }
301     if ( *ptr!=0 ){ *ptr = 0; ptr++; pwent.pw_passwd = ptr; }
302     while (*ptr!=0&&*ptr != ':') { ptr++; }
303     if ( *ptr!=0 ){ *ptr = 0; ptr++; uid = ptr; }
304     while (*ptr!=0&&*ptr != ':') { ptr++; }
305     if ( *ptr!=0 ){ *ptr = 0; ptr++; gid = ptr; }
306     while (*ptr!=0&&*ptr != ':') { ptr++; }
307     if ( *ptr!=0 ){ *ptr = 0; ptr++; pwent.pw_gecos = ptr; }
308     while (*ptr!=0&&*ptr != ':') { ptr++; }
309     if ( *ptr!=0 ){ *ptr = 0; ptr++; pwent.pw_dir = ptr; }
310     while (*ptr!=0&&*ptr != ':') { ptr++; }
311     if ( *ptr!=0 ){ *ptr = 0; ptr++; pwent.pw_shell = ptr; }
312     while (*ptr!=0&&*ptr != ':') { ptr++; }
313     if ( *ptr!=0 ){ *ptr = 0; ptr++; pwent.pw_clear_passwd = ptr; }
314 
315     if (!*uid) { pwent.pw_uid = 0; } else { pwent.pw_uid = atoi(uid); }
316     if (!*gid) { pwent.pw_gid = 0; } else { pwent.pw_gid = atoi(gid); }
317 
318     vlimits_setflags (&pwent, in_domain);
319 
320 #ifdef VPOPMAIL_DEBUG
321     if( dump_data ) {
322     fprintf (stderr,"vgetpw: db: results: pw_name   = %s\n",pwent.pw_name);
323     fprintf (stderr,"                     pw_passwd = %s\n",pwent.pw_passwd);
324     fprintf (stderr,"                     pw_uid    = %d\n",pwent.pw_uid);
325     fprintf (stderr,"                     pw_gid    = %d\n",pwent.pw_gid);
326     fprintf (stderr,"                     pw_flags  = %d\n",pwent.pw_flags);
327     fprintf (stderr,"                     pw_gecos  = %s\n",pwent.pw_gecos);
328     fprintf (stderr,"                     pw_dir    = %s\n",pwent.pw_dir);
329     fprintf (stderr,"                     pw_shell  = %s\n",pwent.pw_shell);
330     }
331 #endif
332 
333     return(&pwent);
334 }
335 
336 
vauth_getall(char * domain,int first,int sortit)337 struct vqpasswd *vauth_getall(char *domain, int first, int sortit)
338 {
339  static FILE *fsv = NULL;
340  struct vqpasswd *tmpwd;
341 
342     set_vpasswd_files( domain );
343     if ( first == 1 ) {
344         if ( fsv != NULL ) fclose(fsv);
345         set_vpasswd_files( domain );
346         if ((fsv = fopen(vpasswd_file, "r")) == NULL) return(NULL);
347     } else if ( fsv == NULL ) {
348 		return(NULL);
349 	}
350     tmpwd = vgetent(fsv);
351     if ( tmpwd == NULL ) {
352 		fclose(fsv);
353 		fsv = NULL;
354 	}
355     if(tmpwd) vlimits_setflags(tmpwd,domain) ;
356     return(tmpwd);
357 }
358 
vauth_end_getall()359 void vauth_end_getall()
360 {
361 }
362 
set_vpasswd_files(char * domain)363 void set_vpasswd_files( char *domain )
364 {
365  char *tmpstr;
366  uid_t uid;
367  gid_t gid;
368  char Dir[156];
369 
370     vset_default_domain( domain );
371     tmpstr = vget_assign(domain, Dir, 156, &uid, &gid );
372     memset(vpasswd_dir, 0, MAX_BUFF);
373     memset(vpasswd_file, 0, MAX_BUFF);
374     memset(vpasswd_cdb_file, 0, MAX_BUFF);
375     memset(vpasswd_cdb_tmp_file, 0, MAX_BUFF);
376     memset(vpasswd_lock_file, 0, MAX_BUFF);
377 
378     if ( domain == NULL || domain[0] == 0 ) {
379         snprintf(vpasswd_dir, MAX_BUFF, "%s/users", VPOPMAILDIR);
380     } else {
381         snprintf(vpasswd_dir, MAX_BUFF, "%s", Dir);
382     }
383     snprintf(vpasswd_file, MAX_BUFF, "%s/%s", vpasswd_dir,VPASSWD_FILE);
384     snprintf(vpasswd_bak_file, MAX_BUFF, "%s/%s.%d",
385         vpasswd_dir,VPASSWD_BAK_FILE, getpid());
386     snprintf(vpasswd_cdb_file, MAX_BUFF,
387         "%s/%s", vpasswd_dir,VPASSWD_CDB_FILE);
388     snprintf(vpasswd_cdb_tmp_file, MAX_BUFF,
389         "%s/%s",vpasswd_dir,VPASSWD_CDB_TMP_FILE);
390     snprintf(vpasswd_lock_file, MAX_BUFF,
391         "%s/%s", vpasswd_dir,VPASSWD_LOCK_FILE);
392 }
393 
vauth_adduser(char * user,char * domain,char * pass,char * gecos,char * dir,int apop)394 int vauth_adduser(char *user, char *domain, char *pass, char *gecos, char *dir, int apop )
395 {
396  static char tmpbuf1[MAX_BUFF];
397  static char tmpbuf2[MAX_BUFF];
398  char *tmpstr;
399  int added = 0;
400  FILE *fs1;
401  FILE *fs2;
402 #ifdef FILE_LOCKING
403  int fd3;
404 #endif
405 
406     /* do not trod on the vpasswd file */
407     if ( strcmp( "vpasswd", user ) == 0 ) {
408       return( VA_ILLEGAL_USERNAME );
409     }
410 
411     set_vpasswd_files( domain );
412 
413     /* if the gecos field is null, set it to user name */
414     if ( gecos==0 || gecos[0]==0) gecos=user;
415     vcdb_strip_char( gecos );
416 
417 #ifdef FILE_LOCKING
418     fd3 = open(vpasswd_lock_file, O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR);
419     if ( get_write_lock(fd3) < 0 ) return(-2);
420 #endif
421 
422     fs1 = fopen(vpasswd_bak_file, "w+");
423     if ( (fs2 = fopen(vpasswd_file, "r+")) == NULL ) {
424     	fs2 = fopen(vpasswd_file, "w+");
425 	}
426 
427     if ( fs1 == NULL || fs2 == NULL ) {
428 		if ( fs1 != NULL ) fclose(fs1);
429 		if ( fs2 != NULL ) fclose(fs2);
430 #ifdef FILE_LOCKING
431 		unlock_lock(fd3, 0, SEEK_SET, 0);
432 		close(fd3);
433 #endif
434         return(-1);
435     }
436 
437     while (fgets(tmpbuf1,MAX_BUFF,fs2)!=NULL){
438         strncpy(tmpbuf2, tmpbuf1, MAX_BUFF);
439         tmpstr = strtok(tmpbuf2,":");
440         if ( added == 0 && strcmp(user, tmpstr) < 0 ) {
441             added = 1;
442             vauth_adduser_line( fs1, user, pass, domain,gecos,dir, apop);
443         }
444         fputs(tmpbuf1, fs1);
445     }
446     if ( added == 0 ) {
447         vauth_adduser_line( fs1, user, pass, domain,gecos,dir,apop);
448     }
449     fclose(fs1);
450     fclose(fs2);
451 
452     rename(vpasswd_bak_file, vpasswd_file);
453     make_vpasswd_cdb(domain);
454 
455 #ifdef FILE_LOCKING
456 	unlock_lock(fd3, 0, SEEK_SET, 0);
457 	close(fd3);
458 #endif
459 
460     return(0);
461 
462 }
463 
vauth_adddomain(char * domain)464 int vauth_adddomain( char *domain )
465 {
466     return(0);
467 }
468 
vauth_deldomain(char * domain)469 int vauth_deldomain( char *domain )
470 {
471     return(0);
472 }
473 
vauth_deluser(char * user,char * domain)474 int vauth_deluser( char *user, char *domain )
475 {
476  static char tmpbuf1[MAX_BUFF];
477  static char tmpbuf2[MAX_BUFF];
478  char *tmpstr;
479  FILE *fs1;
480  FILE *fs2;
481 #ifdef FILE_LOCKING
482  int fd3;
483 #endif
484 
485     set_vpasswd_files( domain );
486 
487 #ifdef FILE_LOCKING
488 	fd3 = open(vpasswd_lock_file, O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR);
489 	if ( get_write_lock(fd3) < 0 ) return(-2);
490 #endif
491 
492     fs1 = fopen(vpasswd_bak_file, "w+");
493     if ( (fs2 = fopen(vpasswd_file, "r+")) == NULL ) {
494     	fs2 = fopen(vpasswd_file, "w+");
495 	}
496 
497     if ( fs1 == NULL || fs2 == NULL ) {
498 		if ( fs1 != NULL ) fclose(fs1);
499 		if ( fs2 != NULL ) fclose(fs2);
500 #ifdef FILE_LOCKING
501 		unlock_lock(fd3, 0, SEEK_SET, 0);
502 		close(fd3);
503 #endif
504         return(-1);
505     }
506 
507     while (fgets(tmpbuf1,MAX_BUFF,fs2)!=NULL){
508         strncpy(tmpbuf2, tmpbuf1, MAX_BUFF);
509         tmpstr = strtok(tmpbuf2,":");
510 
511         if ( strcmp(user, tmpstr) != 0) {
512             fputs(tmpbuf1, fs1);
513         }
514     }
515     fclose(fs1);
516     fclose(fs2);
517 
518     rename(vpasswd_bak_file, vpasswd_file);
519     make_vpasswd_cdb(domain);
520 
521 #ifdef FILE_LOCKING
522 	unlock_lock(fd3, 0, SEEK_SET, 0);
523 	close(fd3);
524 #endif
525 
526     return(0);
527 }
528 
529 /* Utility function to set the users quota
530  *
531  * Calls underlying vauth_getpw and vauth_setpw
532  * to actually change the users information
533  */
vauth_setquota(char * username,char * domain,char * quota)534 int vauth_setquota( char *username, char *domain, char *quota)
535 {
536  struct vqpasswd *vpw;
537 
538     if ( strlen(username) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
539 #ifdef USERS_BIG_DIR
540     if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME);
541 #endif
542     if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
543     if ( strlen(quota) > MAX_PW_QUOTA )    return(VA_QUOTA_TOO_LONG);
544 
545     vpw = vauth_getpw( username, domain );
546     if ( vpw==NULL ) return(VA_USER_DOES_NOT_EXIST);
547     vpw->pw_shell = quota;
548     return(vauth_setpw(vpw,domain));
549 
550 }
551 
vauth_setpw(struct vqpasswd * inpw,char * domain)552 int vauth_setpw( struct vqpasswd *inpw, char *domain )
553 {
554  static char tmpbuf1[MAX_BUFF];
555  static char tmpbuf2[MAX_BUFF];
556  char *tmpstr;
557  FILE *fs1;
558  FILE *fs2;
559 #ifdef FILE_LOCKING
560  int fd3;
561 #endif
562  uid_t myuid;
563  uid_t uid;
564  gid_t gid;
565  int ret;
566 
567     ret = vcheck_vqpw(inpw, domain);
568     if ( ret != 0 ) return(ret);
569 
570 	/* get the owner of the domain */
571 	vget_assign(domain,NULL,0,&uid,&gid);
572 
573 	/* get the current effective user */
574     myuid = geteuid();
575 
576 	/*
577 	 * if it is not the owner, vpopmail or root
578 	 * then reject this operation
579 	 */
580     if ( myuid != 0 && myuid != uid ) {
581 		return(VA_BAD_UID);
582     }
583 
584     set_vpasswd_files( domain );
585 #ifdef FILE_LOCKING
586 	fd3 = open(vpasswd_lock_file, O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR);
587 	if ( get_write_lock(fd3) < 0 ) return(-2);
588 #endif
589 
590     fs1 = fopen(vpasswd_bak_file, "w+");
591     if ( (fs2 = fopen(vpasswd_file, "r+")) == NULL ) {
592     	fs2 = fopen(vpasswd_file, "w+");
593 	}
594 
595     if ( fs1 == NULL || fs2 == NULL ) {
596 		if ( fs1 != NULL ) fclose(fs1);
597 		if ( fs2 != NULL ) fclose(fs2);
598 
599 #ifdef FILE_LOCKING
600 		unlock_lock(fd3, 0, SEEK_SET, 0);
601 		close(fd3);
602 #endif
603         return(-1);
604     }
605     vcdb_strip_char( inpw->pw_gecos );
606 #ifndef CLEAR_PASS
607     vcdb_strip_char( inpw->pw_clear_passwd );
608 #endif
609 
610     while (fgets(tmpbuf1,MAX_BUFF,fs2)!=NULL){
611         strncpy(tmpbuf2, tmpbuf1, MAX_BUFF);
612         tmpstr = strtok(tmpbuf2,":\n");
613 
614         if ( strcmp(inpw->pw_name, tmpstr) != 0) {
615             fputs(tmpbuf1, fs1);
616         } else {
617 #ifndef CLEAR_PASS
618             fprintf(fs1, "%s:%s:%d:%d:%s:%s:%s\n",
619                 inpw->pw_name,
620                 inpw->pw_passwd,
621                 inpw->pw_uid,
622                 inpw->pw_gid,
623                 inpw->pw_gecos,
624                 inpw->pw_dir,
625                 inpw->pw_shell);
626 #else
627             fprintf(fs1, "%s:%s:%d:%d:%s:%s:%s:%s\n",
628                 inpw->pw_name,
629                 inpw->pw_passwd,
630                 inpw->pw_uid,
631                 inpw->pw_gid,
632                 inpw->pw_gecos,
633                 inpw->pw_dir,
634                 inpw->pw_shell, inpw->pw_clear_passwd);
635 #endif
636         }
637     }
638     fclose(fs1);
639     fclose(fs2);
640 
641     rename(vpasswd_bak_file, vpasswd_file);
642     make_vpasswd_cdb(domain);
643 
644 #ifdef FILE_LOCKING
645 	unlock_lock(fd3, 0, SEEK_SET, 0);
646 	close(fd3);
647 #endif
648 
649 #ifdef SQWEBMAIL_PASS
650 	tmpstr = vget_assign(domain, NULL, 0, &uid, &gid );
651     vsqwebmail_pass( inpw->pw_dir, inpw->pw_passwd, uid, gid);
652 #endif
653 
654 #ifdef ONCHANGE_SCRIPT
655     if( allow_onchange ) {
656        /* tell other programs that data has changed */
657        snprintf ( onchange_buf, MAX_BUFF, "%s@%s", inpw->pw_name, domain ) ;
658        call_onchange ( "mod_user" ) ;
659        }
660 #endif
661 
662     return(0);
663 }
664 
vauth_adduser_line(FILE * fs1,char * user,char * pass,char * domain,char * gecos,char * dir,int apop)665 int vauth_adduser_line( FILE *fs1,
666     char *user,
667     char *pass,
668     char *domain,
669     char *gecos,
670     char *dir, int apop )
671 {
672  char Dir[156];
673  uid_t uid;
674  gid_t gid;
675  char crypted[100];
676 
677 	if ( vget_assign(domain, Dir, 156, &uid, &gid ) == NULL ) {
678 		strcpy(Dir, VPOPMAILDIR);
679         }
680 
681         if ( pass[0] != 0 ) {
682             mkpasswd3(pass,crypted, 100);
683         } else {
684             crypted[0] = 0;
685         }
686 
687         fprintf(fs1,"%s:", user );
688 
689         if ( apop == USE_POP ) fprintf(fs1, "%s:1:", crypted);
690         else fprintf(fs1, "%s:2:", crypted);
691 
692         fprintf(fs1, "0:%s:%s", gecos, Dir);
693 
694         if ( strlen(domain) <= 0 ) {
695             if ( strlen(dir) > 0 ) {
696                 fprintf(fs1, "/users/%s/%s:", dir, user);
697             } else {
698                 fprintf(fs1, "/users/%s:", user);
699             }
700         } else {
701             if ( strlen(dir) > 0 ) {
702                 fprintf(fs1,"/%s/%s:", dir,user);
703             } else {
704                 fprintf(fs1, "/%s:", user);
705             }
706         }
707 
708         fprintf(fs1, "NOQUOTA");
709 
710 #ifndef CLEAR_PASS
711         fprintf(fs1, "\n");
712 #else
713         fprintf(fs1, ":%s\n", pass);
714 #endif
715 
716         return(0);
717 }
718 
719 
vmkpasswd(char * domain)720 int vmkpasswd( char *domain )
721 {
722 #ifdef FILE_LOCKING
723  int fd3;
724 #endif
725  char Dir[156];
726  uid_t uid;
727  gid_t gid;
728  char *tmpstr;
729 
730     getcwd(TmpBuf1, MAX_BUFF);
731 	tmpstr = vget_assign(domain, Dir, 156, &uid, &gid );
732 
733     if ( chdir(Dir) != 0 ) return(VA_BAD_DIR);
734 
735     lowerit(domain);
736     set_vpasswd_files( domain );
737 #ifdef FILE_LOCKING
738 	fd3 = open(vpasswd_lock_file, O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR);
739 	if ( get_write_lock(fd3) < 0 ) return(-2);
740 #endif
741 
742     make_vpasswd_cdb(domain);
743 #ifdef FILE_LOCKING
744 	unlock_lock(fd3, 0, SEEK_SET, 0);
745 	close(fd3);
746 #endif
747 
748     return(0);
749 }
750 
751 /*   Verify the connection to the authentication database   */
752 
vauth_open(int will_update)753 int vauth_open( int will_update ) {
754 
755 #ifdef VPOPMAIL_DEBUG
756 show_trace = ( getenv("VPSHOW_TRACE") != NULL);
757 show_query = ( getenv("VPSHOW_QUERY") != NULL);
758 dump_data  = ( getenv("VPDUMP_DATA")  != NULL);
759 #endif
760 
761 #ifdef VPOPMAIL_DEBUG
762     if( show_trace ) {
763         fprintf( stderr, "vauth_open()\n");
764     }
765 #endif
766 
767 
768 /*
769  *  If the connection to this authentication database can fail
770  *  you should test access here.  If it works, return 0, else
771  *  return VA_NO_AUTH_CONNECTION.  You can also set the string
772  *  sqlerr to some short descriptive text about the problem,
773  *  and allocate a much longer string, pointed to by last_query
774  *  that can be displayed in an error message returned because
775  *  of this problem.
776  *
777  */
778 
779     return( 0 );
780 }
781 
vclose()782 void vclose()
783 {
784 
785 }
786 
787 #ifdef IP_ALIAS_DOMAINS
vget_ip_map(char * ip,char * domain,int domain_size)788 int vget_ip_map( char *ip, char *domain, int domain_size)
789 {
790  FILE *fs;
791  char tmpbuf[156];
792  char *tmpstr;
793 
794 	if ( ip == NULL || strlen(ip) <= 0 ) return(-1);
795 
796 	/* open the ip_alias_map file */
797 	snprintf(tmpbuf, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE);
798 	if ( (fs = fopen(tmpbuf,"r")) == NULL ) return(-1);
799 
800 	while( fgets(tmpbuf, 156, fs) != NULL ) {
801 		tmpstr = strtok(tmpbuf, IP_ALIAS_TOKENS);
802 		if ( tmpstr == NULL ) continue;
803 		if ( strcmp(ip, tmpstr) != 0 ) continue;
804 
805 		tmpstr = strtok(NULL, IP_ALIAS_TOKENS);
806 		if ( tmpstr == NULL ) continue;
807 		strncpy(domain, tmpstr, domain_size);
808 		fclose(fs);
809 		return(0);
810 
811 	}
812 	fclose(fs);
813 	return(-1);
814 }
815 
816 /*
817  * Add an ip to domain mapping
818  * It will remove any duplicate entry before adding it
819  *
820  */
vadd_ip_map(char * ip,char * domain)821 int vadd_ip_map( char *ip, char *domain)
822 {
823  FILE *fs;
824  char tmpbuf[156];
825 
826 	if ( ip == NULL || strlen(ip) <= 0 ) return(-1);
827 	if ( domain == NULL || strlen(domain) <= 0 ) return(-10);
828 
829 	vdel_ip_map( ip, domain );
830 
831 	snprintf(tmpbuf, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE);
832 	if ( (fs = fopen(tmpbuf,"a+")) == NULL ) return(-1);
833 	fprintf( fs, "%s %s\n", ip, domain);
834 	fclose(fs);
835 
836 	return(0);
837 }
838 
vdel_ip_map(char * ip,char * domain)839 int vdel_ip_map( char *ip, char *domain)
840 {
841  FILE *fs;
842  FILE *fs1;
843  char file1[156];
844  char file2[156];
845  char tmpbuf[156];
846  char tmpbuf1[156];
847  char *ip_f;
848  char *domain_f;
849 
850 	if ( ip == NULL || strlen(ip) <= 0 ) return(-1);
851 	if ( domain == NULL || strlen(domain) <= 0 ) return(-1);
852 
853 	snprintf(file1, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE);
854 	if ( (fs = fopen(file1,"r")) == NULL ) return(-1);
855 
856 	snprintf(file2, 156,
857             "%s/%s.%d", VPOPMAILDIR, IP_ALIAS_MAP_FILE, getpid());
858 	if ( (fs1 = fopen(file2,"w")) == NULL ) {
859 		fclose(fs);
860 		return(-1);
861 	}
862 
863 	while( fgets(tmpbuf, 156, fs) != NULL ) {
864 		strncpy(tmpbuf1,tmpbuf, 156);
865 
866 		ip_f = strtok(tmpbuf, IP_ALIAS_TOKENS);
867 		if ( ip_f == NULL ) continue;
868 
869 		domain_f = strtok(NULL, IP_ALIAS_TOKENS);
870 		if ( domain_f == NULL ) continue;
871 
872 		if ( strcmp(ip, ip_f) == 0 && strcmp(domain,domain_f) == 0)
873 			continue;
874 
875 		fprintf(fs1, tmpbuf1);
876 
877 	}
878 	fclose(fs);
879 	fclose(fs1);
880 
881 	if ( rename( file2, file1) < 0 ) return(-1);
882 
883 	return(0);
884 }
885 
vshow_ip_map(int first,char * ip,char * domain)886 int vshow_ip_map( int first, char *ip, char *domain)
887 {
888  static FILE *fs = NULL;
889  char tmpbuf[156];
890  char *tmpstr;
891 
892 	if ( ip == NULL ) return(-1);
893 	if ( domain == NULL ) return(-1);
894 
895 	if ( first == 1 ) {
896 		if ( fs != NULL ) {
897 			fclose(fs);
898 			fs = NULL;
899 		}
900 		snprintf(tmpbuf, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE);
901 		if ( (fs = fopen(tmpbuf,"r")) == NULL ) return(-1);
902 	}
903 	if ( fs == NULL ) return(-1);
904 
905 	while (1) {
906 		if (fgets(tmpbuf, 156, fs) == NULL ) {
907 			fclose(fs);
908 			fs = NULL;
909 			return(0);
910 		}
911 
912 		tmpstr = strtok(tmpbuf, IP_ALIAS_TOKENS);
913 		if ( tmpstr == NULL ) continue;
914 		strcpy( ip, tmpstr);
915 
916 		tmpstr = strtok(NULL, IP_ALIAS_TOKENS);
917 		if ( tmpstr == NULL ) continue;
918 		strcpy( domain, tmpstr);
919 
920 		return(1);
921 	}
922 	return(-1);
923 
924 }
925 #endif
926 
vread_dir_control(vdir_type * vdir,char * domain,uid_t uid,gid_t gid)927 int vread_dir_control(vdir_type *vdir, char *domain, uid_t uid, gid_t gid)
928 {
929  FILE *fs;
930  char dir_control_file[MAX_DIR_NAME];
931  int i;
932 
933     strncpy(dir_control_file,dc_filename(domain, uid, gid),MAX_DIR_NAME);
934 
935 
936     if ( (fs = fopen(dir_control_file, "r")) == NULL ) {
937         vdir->cur_users = 0;
938         for(i=0;i<MAX_DIR_LEVELS;++i){
939             vdir->level_start[i] = 0;
940             vdir->level_end[i] = MAX_DIR_LIST-1;
941             vdir->level_index[i] = 0;
942         }
943         vdir->level_mod[0] = 0;
944         vdir->level_mod[1] = 2;
945         vdir->level_mod[2] = 4;
946         vdir->level_cur = 0;
947         vdir->level_max = MAX_DIR_LEVELS;
948         vdir->the_dir[0] = 0;
949         return(-1);
950     }
951 
952     fgets(dir_control_file, MAX_DIR_NAME, fs );
953     vdir->cur_users = atol(dir_control_file);
954 
955     fgets(dir_control_file, MAX_DIR_NAME, fs );
956     vdir->level_cur = atoi(dir_control_file);
957 
958     fgets(dir_control_file, MAX_DIR_NAME, fs );
959     vdir->level_max = atoi(dir_control_file);
960 
961     fgets(dir_control_file, MAX_DIR_NAME, fs );
962     vdir->level_start[0] = atoi(dir_control_file);
963     for(i=0;dir_control_file[i]!=' ';++i); ++i;
964     vdir->level_start[1] = atoi(&dir_control_file[i]);
965     for(i=0;dir_control_file[i]!=' ';++i); ++i;
966     vdir->level_start[2] = atoi(&dir_control_file[i]);
967 
968     fgets(dir_control_file, MAX_DIR_NAME, fs );
969     vdir->level_end[0] = atoi(dir_control_file);
970     for(i=0;dir_control_file[i]!=' ';++i); ++i;
971     vdir->level_end[1] = atoi(&dir_control_file[i]);
972     for(i=0;dir_control_file[i]!=' ';++i); ++i;
973     vdir->level_end[2] = atoi(&dir_control_file[i]);
974 
975     fgets(dir_control_file, MAX_DIR_NAME, fs );
976     vdir->level_mod[0] = atoi(dir_control_file);
977     for(i=0;dir_control_file[i]!=' ';++i); ++i;
978     vdir->level_mod[1] = atoi(&dir_control_file[i]);
979     for(i=0;dir_control_file[i]!=' ';++i); ++i;
980     vdir->level_mod[2] = atoi(&dir_control_file[i]);
981 
982     fgets(dir_control_file, MAX_DIR_NAME, fs );
983     vdir->level_index[0] = atoi(dir_control_file);
984     for(i=0;dir_control_file[i]!=' ';++i); ++i;
985     vdir->level_index[1] = atoi(&dir_control_file[i]);
986     for(i=0;dir_control_file[i]!=' ';++i); ++i;
987     vdir->level_index[2] = atoi(&dir_control_file[i]);
988 
989     fgets(dir_control_file, MAX_DIR_NAME, fs );
990     for(i=0;dir_control_file[i]!=0;++i) {
991         if (dir_control_file[i] == '\n') {
992             dir_control_file[i] = 0;
993         }
994     }
995 
996     fgets(dir_control_file, MAX_DIR_NAME, fs );
997     for(i=0;dir_control_file[i]!=0;++i) {
998         if (dir_control_file[i] == '\n') {
999             dir_control_file[i] = 0;
1000         }
1001     }
1002     strncpy(vdir->the_dir, dir_control_file, MAX_DIR_NAME);
1003 
1004     fclose(fs);
1005 
1006     return(0);
1007 }
1008 
vwrite_dir_control(vdir_type * vdir,char * domain,uid_t uid,gid_t gid)1009 int vwrite_dir_control(vdir_type *vdir, char *domain, uid_t uid, gid_t gid)
1010 {
1011  FILE *fs;
1012  char dir_control_file[MAX_DIR_NAME];
1013  char dir_control_tmp_file[MAX_DIR_NAME];
1014 
1015     strncpy(dir_control_file,dc_filename(domain, uid, gid),MAX_DIR_NAME);
1016     snprintf(dir_control_tmp_file, MAX_DIR_NAME,
1017         "%s.%d", dir_control_file, getpid());
1018 
1019     if ( (fs = fopen(dir_control_tmp_file, "w+")) == NULL ) {
1020         return(-1);
1021     }
1022 
1023     fprintf(fs, "%lu\n", vdir->cur_users);
1024     fprintf(fs, "%d\n", vdir->level_cur);
1025     fprintf(fs, "%d\n", vdir->level_max);
1026     fprintf(fs, "%d %d %d\n",
1027         vdir->level_start[0],
1028         vdir->level_start[1],
1029         vdir->level_start[2]);
1030     fprintf(fs, "%d %d %d\n",
1031         vdir->level_end[0],
1032         vdir->level_end[1],
1033         vdir->level_end[2]);
1034     fprintf(fs, "%d %d %d\n",
1035         vdir->level_mod[0],
1036         vdir->level_mod[1],
1037         vdir->level_mod[2]);
1038     fprintf(fs, "%d %d %d\n",
1039         vdir->level_index[0],
1040         vdir->level_index[1],
1041         vdir->level_index[2]);
1042     fprintf(fs, "%s\n", vdir->the_dir);
1043 
1044     fclose(fs);
1045 
1046     rename( dir_control_tmp_file, dir_control_file);
1047 
1048     chown(dir_control_file,uid, gid);
1049 
1050     return(0);
1051 }
1052 
vdel_dir_control(char * domain)1053 int vdel_dir_control(char *domain)
1054 {
1055  char dir_control_file[MAX_DIR_NAME];
1056 
1057     vget_assign(domain, dir_control_file, 156, NULL,NULL);
1058     strncat(dir_control_file,"/.dir-control", MAX_DIR_NAME);
1059     return(unlink(dir_control_file));
1060 }
1061 
1062 #ifdef ENABLE_AUTH_LOGGING
vset_lastauth(char * user,char * domain,char * remoteip)1063 int vset_lastauth(char *user, char *domain, char *remoteip )
1064 {
1065  char *tmpbuf;
1066  FILE *fs;
1067  struct vqpasswd *vpw;
1068  uid_t uid;
1069  gid_t gid;
1070 
1071     if( (vpw = vauth_getpw( user, domain )) == NULL) return(0);
1072 
1073 	tmpbuf = malloc(MAX_BUFF);
1074 	snprintf(tmpbuf, MAX_BUFF, "%s/lastauth", vpw->pw_dir);
1075 	if ( (fs = fopen(tmpbuf,"w+")) == NULL ) {
1076 	  free(tmpbuf);
1077 	  return(-1);
1078 	}
1079 	fprintf(fs, "%s", remoteip);
1080 	fclose(fs);
1081 
1082         vget_assign(domain,NULL,0,&uid,&gid);
1083         chown(tmpbuf,uid,gid);
1084 	free(tmpbuf);
1085 	return(0);
1086 }
1087 
vget_lastauth(struct vqpasswd * pw,char * domain)1088 time_t vget_lastauth( struct vqpasswd *pw, char *domain)
1089 {
1090  char *tmpbuf;
1091  struct stat mystatbuf;
1092 
1093 	tmpbuf = malloc(MAX_BUFF);
1094 	snprintf(tmpbuf, MAX_BUFF, "%s/lastauth", pw->pw_dir);
1095 	if ( stat(tmpbuf,&mystatbuf) == -1 ) {
1096 		free(tmpbuf);
1097 		return(0);
1098 	}
1099 	free(tmpbuf);
1100 	return(mystatbuf.st_mtime);
1101 }
1102 
vget_lastauthip(struct vqpasswd * pw,char * domain)1103 char *vget_lastauthip( struct vqpasswd *pw, char *domain)
1104 {
1105  static char tmpbuf[MAX_BUFF];
1106  FILE *fs;
1107 
1108 	snprintf(tmpbuf, MAX_BUFF, "%s/lastauth", pw->pw_dir);
1109         if ( (fs=fopen(tmpbuf,"r"))==NULL) return(NULL);
1110         fgets(tmpbuf,MAX_BUFF,fs);
1111         fclose(fs);
1112         return(tmpbuf);
1113 }
1114 #endif /* ENABLE_AUTH_LOGGING */
1115 
dc_filename(char * domain,uid_t uid,gid_t gid)1116 char *dc_filename(char *domain, uid_t uid, gid_t gid)
1117 {
1118  static char dir_control_file[MAX_DIR_NAME];
1119  struct passwd *pw;
1120 
1121     /* if we are lucky the domain is in the assign file */
1122     if ( vget_assign(domain,dir_control_file,MAX_DIR_NAME,NULL,NULL)!=NULL ) {
1123 	strncat(dir_control_file, "/.dir-control", MAX_DIR_NAME);
1124 
1125     /* it isn't in the assign file so we have to get it from /etc/passwd */
1126     } else {
1127 
1128         /* save some time if this is the vpopmail user */
1129         if ( uid == VPOPMAILUID ) {
1130             strncpy(dir_control_file, VPOPMAILDIR, MAX_DIR_NAME);
1131 
1132         /* for other users, look them up in /etc/passwd */
1133         } else if ( (pw=getpwuid(uid))!=NULL ) {
1134             strncpy(dir_control_file, pw->pw_dir, MAX_DIR_NAME);
1135 
1136         /* all else fails return a blank string */
1137         } else {
1138             return("");
1139         }
1140 
1141         /* stick on the rest of the path */
1142         strncat(dir_control_file, "/" DOMAINS_DIR "/.dir-control", MAX_DIR_NAME);
1143     }
1144     return(dir_control_file);
1145 }
1146 
vcdb_strip_char(char * instr)1147 void vcdb_strip_char( char *instr )
1148 {
1149  char *nextstr;
1150 
1151     nextstr = instr;
1152     while (*instr != 0 ) {
1153        if ( *instr == ':' ) ++instr;
1154        if ( nextstr != instr ) *nextstr = *instr;
1155        ++nextstr;
1156        ++instr;
1157     }
1158 
1159 }
1160 
vauth_crypt(char * user,char * domain,char * clear_pass,struct vqpasswd * vpw)1161 int vauth_crypt(char *user,char *domain,char *clear_pass,struct vqpasswd *vpw)
1162 {
1163   if ( vpw == NULL ) return(-1);
1164 
1165   return(strcmp(crypt(clear_pass,vpw->pw_passwd),vpw->pw_passwd));
1166 }
1167