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