3 * routines which are different for -DDEBUG
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>
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.
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.
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/>.
31 #include <sys/types.h>
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:"");
45 static void fdwantdumprw(const char *whichstr, int whichval,
46 int rw, const char *rwstr) {
50 for (fd=0; fd<fdarrayused; fd++) {
51 if (!(fdarray[fd].wantstate == whichval && fdarray[fd].wantrw == rw)) continue;
52 fdwantdumprwhead(&donehead,whichstr,rwstr);
55 if (restfdwantstate == whichval && restfdwantrw == rw) {
56 fdwantdumprwhead(&donehead,whichstr,rwstr);
57 printf(" %d-",fdarrayused);
59 if (donehead) printf("\n");
62 static void fdwantdump(const char *whichstr, int whichval, const char *rwunspecstr) {
64 fdwantdumprw(whichstr,whichval,tokv_word_read,"read");
65 fdwantdumprw(whichstr,whichval,tokv_word_write,"write");
66 fdwantdumprw(whichstr,whichval,0,rwunspecstr);
68 fdwantdumprw(whichstr,whichval,0,0);
72 static void truefalsedump(const char *whichstr, int val) {
73 printf("%s: %s\n",whichstr,val?"yes":"no");
76 void always_dumpparameter(const char *parm, char **values) {
77 printf("config parameter `%s':",parm);
78 while (*values) printf(" `%s'",*values++);
82 void always_dumpexecsettings(void) {
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);
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;
102 fputs("\n" "no exec arguments\n",stdout);
104 fputs("\n" "exec arguments:",stdout);
105 for (cpp= execargs; cpp; cpp++) printf(" `%s'",*cpp);
108 truefalsedump("set-environment",setenvironment);
109 truefalsedump("suppress-args",suppressargs);
110 truefalsedump("disconnect-hup",disconnecthup);
111 truefalsedump("set-environment",setenvironment);
116 static const char *sl_ident= "UNSET";
117 static int sl_option=0, sl_facility=0;
119 void openlog(const char *ident, int option, int facility) {
122 sl_facility= facility;
125 void syslog(int priority, const char *fmt, ...) {
127 fprintf(stderr,"syslog: %s<%d.%d>(%d): ",sl_ident,sl_facility,priority,sl_option);
129 vfprintf(stderr,fmt,al);
134 void closelog(void) {
136 sl_option= sl_facility= 0;
139 static void groupsdump(int ngids, const gid_t *gids, const char *const *groups) {
142 for (i=0; i<ngids; i++) printf(" %ld(%s)",(long)gids[i],groups[i]);
145 void debug_dumprequest(pid_t mypid) {
148 printf("server pid: %ld\n"
151 "service user: `%s'\n"
153 "service user shell: `%s'\n"
154 "service user dir: `%s'\n"
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);
161 "calling user: `%s'\n"
163 "calling user shell: `%s'\n"
165 loginname, (long)request_mbuf.callinguid,
167 groupsdump(request_mbuf.ngids,calling_gids,calling_groups);
169 "calling cwd: `%s'\n"
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);
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")));
186 void debug_dumpexecsettings(void) {
187 printf("configuration parsed\n");
188 always_dumpexecsettings();
191 void debug_dumpparameter(const char *parm, char **values) {
192 always_dumpparameter(parm,values);
195 static int groupsallin(int na, const gid_t *lista,
196 int nb, const gid_t *listb) {
198 for (i=0; i<na; i++) {
199 for (j=0; j<nb && listb[j] != lista[i]; j++);
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
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.
219 * The usual magic with dynamic linking makes the libc initgroups(3) call
220 * pick up our setgroups() rather than the real setgroups(2).
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;
236 pid_t nondebug_fork(void) { return 0; }
237 const char *nondebug_serviceuserdir(const char *ifnondebug) { return SERVICEUSERDIR; }
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; }