1 /* cvm-qmail.c - qmail lookup-only CVM
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 <ctype.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include <bglibs/ibuf.h>
26 #include <bglibs/striter.h>
27 
28 #include "module.h"
29 #include "qmail.h"
30 
31 const char program[] = "cvm-qmail";
32 
33 static struct qmail_user user;
34 static str domain;
35 static str username;
36 static str ext;
37 static str programs;
38 static int check_perms = 0;
39 static uid_t saved_uid;
40 static gid_t saved_gid;
41 
cvm_module_init(void)42 int cvm_module_init(void)
43 {
44   const char* tmp;
45   if (qmail_lookup_init() == -1)
46     return CVME_IO;
47   if ((tmp = getenv("CVM_QMAIL_LOOKASIDE")) != 0) {
48     if (!str_copys(&programs, tmp))
49       return CVME_IO | CVME_FATAL;
50     str_subst(&programs, ' ', 0);
51   }
52 
53   if ((tmp = getenv("CVM_QMAIL_CHECK_PERMS")) != 0 && tmp[0] != 0) {
54     check_perms = (tmp[0] == '-') ? CVME_PERMFAIL : CVME_IO;
55     saved_uid = getuid();
56     saved_gid = getgid();
57   }
58 
59   return 0;
60 }
61 
lookup_programs(const str * path)62 static int lookup_programs(const str* path)
63 {
64   static str dotqmail;
65   striter line;
66   striter progname;
67   const char* start;
68   const char* end;
69   unsigned long left;
70 
71   if (!ibuf_openreadclose(path->s, &dotqmail))
72     return -1;
73   striter_loop(&line, &dotqmail, '\n') {
74     /* skip over spaces preceding '|' */
75     for (start = line.startptr, left = line.len;
76 	 left > 0 && isspace(*start);
77 	 --left, ++start)
78       ;
79     if (left > 0 && *start == '|') {
80       /* skip spaces preceding the program name */
81       for (++start, --left;
82 	   left > 0 && isspace(*start);
83 	   --left, ++start)
84 	;
85       /* the program name ends at the first space */
86       for (end = start;
87 	   left > 0 && !isspace(*end);
88 	   --left, ++end)
89 	;
90       if (end > start) {
91 	striter_loop(&progname, &programs, 0) {
92 	  if ((unsigned long)(end - start) == progname.len
93 	      && memcmp(progname.startptr, start, progname.len) == 0)
94 	    return 1;
95 	}
96       }
97     }
98   }
99   return 0;
100 }
101 
102 /* Account name is either "baseuser-virtuser" or "virtuser@domain" */
cvm_module_lookup(void)103 int cvm_module_lookup(void)
104 {
105   static str path;
106   int r;
107 
108   switch (qmail_lookup_cvm(&user, &domain, &username, &ext)) {
109   case -1:
110     return CVME_IO;
111   case 0:
112     break;
113   case 1:
114     cvm_module_fact_uint(CVM_FACT_OUTOFSCOPE, 1);
115     return CVME_PERMFAIL;
116   default:
117     cvm_module_fact_uint(CVM_FACT_OUTOFSCOPE, 0);
118     return CVME_PERMFAIL;
119   }
120 
121   if (check_perms) {
122     setegid(user.gid);
123     seteuid(user.uid);
124   }
125   r = qmail_dotfile_exists(&user, ext.s, &path);
126   if (check_perms) {
127     seteuid(saved_uid);
128     setegid(saved_gid);
129   }
130   switch (r) {
131   case -1:
132     if (errno == EACCES && check_perms == CVME_PERMFAIL) {
133       cvm_module_fact_uint(CVM_FACT_OUTOFSCOPE, 0);
134       return CVME_PERMFAIL;
135     }
136     return CVME_IO;
137   case 0:
138     cvm_module_fact_uint(CVM_FACT_OUTOFSCOPE, 0);
139     return CVME_PERMFAIL;
140   }
141 
142   if (programs.len > 0) {
143     switch (lookup_programs(&path)) {
144     case -1:
145       return CVME_IO;
146     case 0:
147       break;
148     default:
149       cvm_module_fact_uint(CVM_FACT_OUTOFSCOPE, 1);
150       return CVME_PERMFAIL;
151     }
152   }
153 
154   return 0;
155 }
156 
cvm_module_authenticate(void)157 int cvm_module_authenticate(void)
158 {
159   return CVME_CONFIG;
160 }
161 
cvm_module_results(void)162 int cvm_module_results(void)
163 {
164   cvm_fact_username = user.user.s;
165   cvm_fact_userid = user.uid;
166   cvm_fact_groupid = user.gid;
167   cvm_fact_realname = 0;
168   cvm_fact_directory = user.homedir.s;
169   cvm_fact_shell = 0;
170   cvm_fact_sys_username = user.user.s;
171   cvm_fact_sys_directory = user.homedir.s;
172   cvm_fact_domain = domain.s;
173   cvm_fact_mailbox = user.homedir.s;
174   return 0;
175 }
176 
cvm_module_stop(void)177 void cvm_module_stop(void)
178 {
179 }
180