chiark / gitweb /
debian/control: Add missing build-dependency on flex. Fixes FTBFS. Report from Aurel...
[userv.git] / debug.c
1 /*
2  * userv - ddebug.c
3  * routines which are different for -DDEBUG
4  *
5  * userv is
6  * Copyright 1996-2017 Ian Jackson <ian@davenant.greenend.org.uk>.
7  * Copyright 2000      Ben Harris <bjh21@cam.ac.uk>
8  * Copyright 2016-2017 Peter Benie <pjb1008@cam.ac.uk>
9  *
10  * This is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with userv; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <stdarg.h>
25 #include <syslog.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <grp.h>
31 #include <sys/types.h>
32
33 #include "config.h"
34 #include "common.h"
35 #include "daemon.h"
36 #include "lib.h"
37 #include "tokens.h"
38
39 static void fdwantdumprwhead(int *donehead, const char *whichstr, const char *rwstr) {
40   if (*donehead) return;
41   printf("fds %s%s%s:",whichstr,rwstr?" ":"",rwstr?rwstr:"");
42   *donehead= 1;
43 }
44
45 static void fdwantdumprw(const char *whichstr, int whichval,
46                          int rw, const char *rwstr) {
47   int donehead= 0;
48   int fd;
49   
50   for (fd=0; fd<fdarrayused; fd++) {
51     if (!(fdarray[fd].wantstate == whichval && fdarray[fd].wantrw == rw)) continue;
52     fdwantdumprwhead(&donehead,whichstr,rwstr);
53     printf(" %d",fd);
54   }
55   if (restfdwantstate == whichval && restfdwantrw == rw) {
56     fdwantdumprwhead(&donehead,whichstr,rwstr);
57     printf(" %d-",fdarrayused);
58   }
59   if (donehead) printf("\n");
60 }
61
62 static void fdwantdump(const char *whichstr, int whichval, const char *rwunspecstr) {
63   if (rwunspecstr) {
64     fdwantdumprw(whichstr,whichval,tokv_word_read,"read");
65     fdwantdumprw(whichstr,whichval,tokv_word_write,"write");
66     fdwantdumprw(whichstr,whichval,0,rwunspecstr);
67   } else {
68     fdwantdumprw(whichstr,whichval,0,0);
69   }
70 }
71
72 static void truefalsedump(const char *whichstr, int val) {
73   printf("%s: %s\n",whichstr,val?"yes":"no");
74 }
75
76 void always_dumpparameter(const char *parm, char **values) {
77   printf("config parameter `%s':",parm);
78   while (*values) printf(" `%s'",*values++);
79   printf("\n");
80 }
81
82 void always_dumpexecsettings(void) {
83   char **cpp;
84   
85   if (userrcfile) printf("user-rcfile: `%s'\n",userrcfile);
86   else printf("user-rcfile: <none>\n");
87   fdwantdump("required",tokv_word_requirefd,"ERROR");
88   fdwantdump("allowed",tokv_word_allowfd,"either");
89   fdwantdump("ignored",tokv_word_ignorefd,0);
90   fdwantdump("null",tokv_word_nullfd,"both");
91   fdwantdump("rejected",tokv_word_rejectfd,0);
92   fputs("execute: ",stdout);
93   switch (execute) {
94   case tokv_word_reject: printf("reject"); break;
95   case tokv_word_execute: printf("`%s'",execpath); break;
96   case tokv_word_executefromdirectory: printf("from directory, `%s'",execpath); break;
97   case tokv_word_executefrompath: printf("from path"); break;
98   case tokv_word_executebuiltin: printf("builtin %s",execpath); break;
99   default: abort();
100   }
101   if (execargs) {
102     fputs("\n" "no exec arguments\n",stdout);
103   } else {
104     fputs("\n" "exec arguments:",stdout);
105     for (cpp= execargs; cpp; cpp++) printf(" `%s'",*cpp);
106     putchar('\n');
107   }
108   truefalsedump("set-environment",setenvironment);
109   truefalsedump("suppress-args",suppressargs);
110   truefalsedump("disconnect-hup",disconnecthup);
111   truefalsedump("set-environment",setenvironment);
112 }
113
114 #ifdef DEBUG
115
116 static const char *sl_ident= "UNSET";
117 static int sl_option=0, sl_facility=0;
118
119 void openlog(const char *ident, int option, int facility) {
120   sl_ident= ident;
121   sl_option= option;
122   sl_facility= facility;
123 }
124
125 void syslog(int priority, const char *fmt, ...) {
126   va_list al;
127   fprintf(stderr,"syslog: %s<%d.%d>(%d): ",sl_ident,sl_facility,priority,sl_option);
128   va_start(al,fmt);
129   vfprintf(stderr,fmt,al);
130   va_end(al);
131   fputc('\n',stderr);
132 }
133
134 void closelog(void) {
135   sl_ident= "CLOSED";
136   sl_option= sl_facility= 0;
137 }
138
139 static void groupsdump(int ngids, const gid_t *gids, const char *const *groups) {
140   int i;
141   
142   for (i=0; i<ngids; i++) printf(" %ld(%s)",(long)gids[i],groups[i]);
143 }
144
145 void debug_dumprequest(pid_t mypid) {
146   int i, fd;
147   
148   printf("server pid: %ld\n"
149          "client pid: %ld\n"
150          "service: `%s'\n"
151          "service user: `%s'\n"
152          "service uid: %ld\n"
153          "service user shell: `%s'\n"
154          "service user dir: `%s'\n"
155          "service groups:",
156          (long)mypid, (long)request_mbuf.clientpid,
157          service, serviceuser, (long)serviceuser_uid,
158          serviceuser_shell, serviceuser_dir);
159   groupsdump(service_ngids,service_gids,service_groups);
160   printf("\n"
161          "calling user: `%s'\n"
162          "calling uid: %ld\n"
163          "calling user shell: `%s'\n"
164          "calling groups:",
165          loginname, (long)request_mbuf.callinguid,
166          callinguser_shell);
167   groupsdump(request_mbuf.ngids,calling_gids,calling_groups);
168   printf("\n"
169          "calling cwd: `%s'\n"
170          "fds:",
171          cwd);
172   for (fd=0; fd<fdarrayused; fd++)
173     if (fdarray[fd].iswrite != -1)
174       printf(" %d%s",fd,fdarray[fd].iswrite ? "w" : "r");
175   printf("\n" "arguments:");
176   for (i=0; i<request_mbuf.nargs; i++) printf(" `%s'",argarray[i]);
177   printf("\n" "variables:");
178   for (i=0; i<request_mbuf.nvars; i++)
179     printf(" `%s'=`%s'",defvararray[i].key,defvararray[i].value);
180   printf("\n");
181   if (overridedata) printf("override data: `%s'\n",overridedata);
182   else printf("not overridden\n");
183   if (getenv("USERVD_SLEEP")) sleep(atoi(getenv("USERVD_SLEEP")));
184 }
185
186 void debug_dumpexecsettings(void) {
187   printf("configuration parsed\n");
188   always_dumpexecsettings();
189 }
190
191 void debug_dumpparameter(const char *parm, char **values) {
192   always_dumpparameter(parm,values);
193 }
194
195 static int groupsallin(int na, const gid_t *lista,
196                        int nb, const gid_t *listb) {
197   int i,j;
198   for (i=0; i<na; i++) {
199     for (j=0; j<nb && listb[j] != lista[i]; j++);
200     if (j>=nb) return 0;
201   }
202   return 1;
203 }
204
205 int setgroups(size_t wantsize, const gid_t *wantlist) {
206   /* This is a bit of a hack really.  What we want when we're in debug mode is to
207    * have initgroups() be a no-op iff the groups are already set right (so that
208    * we notice if we're trying to change to the wrong user) but to fail if they're
209    * not.
210    *
211    * We can't just call initgroups() because it unconditionally calls
212    * setgroups, which always fails for non-root even if the two group
213    * lists are the same.  So here we have a faked-up setgroups which
214    * uses getgroups to see what the group list is and `succeeds' if
215    * the actual group list and the desired one have the same set of
216    * groups, and fails with EPERM if the real setgroups would have
217    * added group(s) or otherwise EINVAL if it would have removed some.
218    *
219    * The usual magic with dynamic linking makes the libc initgroups(3) call
220    * pick up our setgroups() rather than the real setgroups(2).
221    */
222   int realsize, e;
223   gid_t *reallist;
224
225   realsize= getgroups(0,0); if (realsize == -1) return -1;
226   reallist= malloc(sizeof(gid_t)*realsize); if (!reallist) return -1;
227   if (getgroups(realsize,reallist) != realsize)
228     { e= errno; free(reallist); errno= e; return -1; }
229   if (!groupsallin(wantsize,wantlist,realsize,reallist))
230     { free(reallist); errno= EPERM; return -1; }
231   if (!groupsallin(realsize,reallist,wantsize,wantlist))
232     { free(reallist); errno= EINVAL; return -1; }
233   free(reallist); return 0;
234 }
235
236 pid_t nondebug_fork(void) { return 0; }
237 const char *nondebug_serviceuserdir(const char *ifnondebug) { return SERVICEUSERDIR; }
238
239 #else
240
241 void debug_dumprequest(pid_t mypid) { }
242 void debug_dumpexecsettings(void) { }
243 void debug_dumpparameter(const char *parm, char **values) { }
244 pid_t nondebug_fork(void) { return fork(); }
245 const char *nondebug_serviceuserdir(const char *ifnondebug) { return ifnondebug; }
246
247 #endif