#include <sys/types.h>
#include "config.h"
#ifdef CHECKLOGIN
# ifdef _SEQUENT_
# include <stdio.h>
# endif
# include <pwd.h>
# ifdef SHADOWPW
# include <shadow.h>
# endif
#endif
#ifndef NOSYSLOG
# include <syslog.h>
#endif
#include "screen.h"
#include "extern.h"
extern struct comm comms[];
extern struct win *windows, *wtab[];
extern char NullStr[];
extern char SockPath[];
extern struct display *display, *displays;
struct acluser *users;
#ifdef MULTIUSER
int maxusercount = 0;
static AclBits userbits;
static char default_w_bit[ACL_BITS_PER_WIN] =
{
1,
1,
1
};
static char default_c_bit[ACL_BITS_PER_CMD] =
{
0
};
static int GrowBitfield __P((AclBits *, int, int, int));
static struct aclusergroup **FindGroupPtr __P((struct aclusergroup **, struct acluser *, int));
static int AclSetPermCmd __P((struct acluser *, char *, struct comm *));
static int AclSetPermWin __P((struct acluser *, struct acluser *, char *, struct win *));
static int UserAcl __P((struct acluser *, struct acluser **, int, char **));
static int UserAclCopy __P((struct acluser **, struct acluser **));
static int
GrowBitfield(bfp, len, delta, defaultbit)
AclBits *bfp;
int len, delta, defaultbit;
{
AclBits n, o = *bfp;
int i;
if (!(n = (AclBits)calloc(1, (unsigned long)(&ACLBYTE((char *)0, len + delta + 1)))))
return -1;
for (i = 0; i < (len + delta); i++)
{
if (((i < len) && (ACLBIT(i) & ACLBYTE(o, i))) ||
((i >= len) && (defaultbit)))
ACLBYTE(n, i) |= ACLBIT(i);
}
if (len)
free((char *)o);
*bfp = n;
return 0;
}
#endif
struct acluser **
FindUserPtr(name)
char *name;
{
struct acluser **u;
for (u = &users; *u; u = &(*u)->u_next)
if (!strcmp((*u)->u_name, name))
break;
#ifdef MULTIUSER
debug3("FindUserPtr %s %sfound, id %d\n", name, (*u)?"":"not ",
(*u)?(*u)->u_id:-1);
#else
debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not ");
#endif
return u;
}
int DefaultEsc = -1;
int DefaultMetaEsc = -1;
int
UserAdd(name, pass, up)
char *name, *pass;
struct acluser **up;
{
#ifdef MULTIUSER
int j;
#endif
if (!up)
up = FindUserPtr(name);
if (*up)
{
if (pass)
(*up)->u_password = SaveStr(pass);
return 1;
}
if (strcmp("none", name))
*up = (struct acluser *)calloc(1, sizeof(struct acluser));
if (!*up)
return -1;
#ifdef COPY_PASTE
(*up)->u_plop.buf = NULL;
(*up)->u_plop.len = 0;
# ifdef ENCODINGS
(*up)->u_plop.enc = 0;
# endif
#endif
(*up)->u_Esc = DefaultEsc;
(*up)->u_MetaEsc = DefaultMetaEsc;
strncpy((*up)->u_name, name, 20);
(*up)->u_password = NULL;
if (pass)
(*up)->u_password = SaveStr(pass);
if (!(*up)->u_password)
(*up)->u_password = NullStr;
(*up)->u_detachwin = -1;
(*up)->u_detachotherwin = -1;
#ifdef MULTIUSER
(*up)->u_group = NULL;
for ((*up)->u_id = 0; (*up)->u_id < maxusercount; (*up)->u_id++)
if (!(ACLBIT((*up)->u_id) & ACLBYTE(userbits, (*up)->u_id)))
break;
debug2("UserAdd %s id %d\n", name, (*up)->u_id);
if ((*up)->u_id == maxusercount)
{
int j;
struct win *w;
struct acluser *u;
debug2("growing all bitfields %d += %d\n", maxusercount, USER_CHUNK);
if (GrowBitfield(&userbits, maxusercount, USER_CHUNK, 0))
{
free((char *)*up); *up = NULL; return -1;
}
for (j = 0; j <= RC_LAST; j++)
{
int i;
for (i = 0; i < ACL_BITS_PER_CMD; i++)
if (GrowBitfield(&comms[j].userbits[i], maxusercount, USER_CHUNK,
default_c_bit[i]))
{
free((char *)*up); *up = NULL; return -1;
}
}
for (u = users; u != *up; u = u->u_next)
{
for (j = 0; j < ACL_BITS_PER_WIN; j++)
{
if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK,
default_w_bit[j]))
{
free((char *)*up); *up = NULL; return -1;
}
}
}
for (w = windows; w; w = w->w_next)
{
for (j = 0; j < ACL_BITS_PER_WIN; j++)
if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK,
default_w_bit[j]))
{
free((char *)*up); *up = NULL; return -1;
}
if (GrowBitfield(&w->w_mon_notify, maxusercount, USER_CHUNK, 0) ||
GrowBitfield(&w->w_lio_notify, maxusercount, USER_CHUNK, 0))
{
free((char *)*up); *up = NULL; return -1;
}
}
maxusercount += USER_CHUNK;
}
ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id);
if ((*up)->u_id == 0)
AclSetPerm(NULL, *up, "+a", "#?");
if (!strcmp((*up)->u_name, "nobody"))
{
AclSetPerm(NULL, *up, "-rwx", "#?");
AclSetPerm(NULL, *up, "+x", "su");
AclSetPerm(NULL, *up, "+x", "detach");
AclSetPerm(NULL, *up, "+x", "displays");
AclSetPerm(NULL, *up, "+x", "version");
}
for (j = 0; j < ACL_BITS_PER_WIN; j++)
{
if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount,
default_w_bit[j]))
{
free((char *)*up); *up = NULL; return -1;
}
ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id);
}
#else
debug1("UserAdd %s\n", name);
#endif
return 0;
}
#if 0
int
UserSetPass(name, pass, up)
char *name, *pass;
struct acluser **up;
{
if (!up)
up = FindUserPtr(name);
if (!*up)
return UserAdd(name, pass, up);
if (!strcmp(name, "nobody"))
return -1;
strncpy((*up)->u_password, pass ? pass : "", 20);
(*up)->u_password[20] = '\0';
return 0;
}
#endif
int
UserDel(name, up)
char *name;
struct acluser **up;
{
struct acluser *u;
#ifdef MULTIUSER
int i;
#endif
struct display *old, *next;
if (!up)
up = FindUserPtr(name);
if (!(u = *up))
return -1;
old = display;
for (display = displays; display; display = next)
{
next = display->d_next;
if (D_user != u)
continue;
if (display == old)
old = NULL;
Detach(D_REMOTE);
}
display = old;
*up = u->u_next;
#ifdef MULTIUSER
for (up = &users; *up; up = &(*up)->u_next)
{
struct aclusergroup **g = &(*up)->u_group;
while (*g)
{
if ((*g)->u == u)
{
struct aclusergroup *next = (*g)->next;
free((char *)(*g));
*g = next;
}
else
g = &(*g)->next;
}
}
ACLBYTE(userbits, u->u_id) &= ~ACLBIT(u->u_id);
AclSetPerm(NULL, u, default_w_bit[ACL_READ] ? "+r" : "-r", "#");
AclSetPerm(NULL, u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#");
AclSetPerm(NULL, u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#");
AclSetPerm(NULL, u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?");
for (i = 0; i < ACL_BITS_PER_WIN; i++)
free((char *)u->u_umask_w_bits[i]);
#endif
debug1("FREEING user structure for %s\n", u->u_name);
#ifdef COPY_PASTE
UserFreeCopyBuffer(u);
#endif
free((char *)u);
if (!users)
{
debug("Last user deleted. Feierabend.\n");
Finit(0);
}
return 0;
}
#ifdef COPY_PASTE
int
UserFreeCopyBuffer(u)
struct acluser *u;
{
struct win *w;
struct paster *pa;
if (!u->u_plop.buf)
return 1;
for (w = windows; w; w = w->w_next)
{
pa = &w->w_paster;
if (pa->pa_pasteptr >= u->u_plop.buf &&
pa->pa_pasteptr - u->u_plop.buf < u->u_plop.len)
FreePaster(pa);
}
free((char *)u->u_plop.buf);
u->u_plop.len = 0;
u->u_plop.buf = 0;
return 0;
}
#endif
#ifdef MULTIUSER
static struct aclusergroup **
FindGroupPtr(gp, u, recursive)
struct aclusergroup **gp;
struct acluser *u;
int recursive;
{
struct aclusergroup **g;
ASSERT(recursive < 1000);
while (*gp)
{
if ((*gp)->u == u)
return gp;
if (recursive &&
*(g = FindGroupPtr(&(*gp)->u->u_group, u, recursive + 1)))
return g;
gp = &(*gp)->next;
}
return gp;
}
int
AclLinkUser(from, to)
char *from, *to;
{
struct acluser **u1, **u2;
struct aclusergroup **g;
if (!*(u1 = FindUserPtr(from)) && UserAdd(from, NULL, u1))
return -1;
if (!*(u2 = FindUserPtr(to)) && UserAdd(to, NULL, u2))
return -1;
if (*FindGroupPtr(&(*u2)->u_group, *u1, 1))
return 1;
if (*(g = FindGroupPtr(&(*u1)->u_group, *u2, 0)))
return 2;
if (!(*g = (struct aclusergroup *)malloc(sizeof(struct aclusergroup))))
return -1;
(*g)->u = (*u2);
(*g)->next = NULL;
return 0;
}
char *
DoSu(up, name, pw1, pw2)
struct acluser **up;
char *name, *pw1, *pw2;
{
struct acluser *u;
int sorry = 0;
if (!(u = *FindUserPtr(name)))
sorry++;
else
{
#ifdef CHECKLOGIN
struct passwd *pp;
#ifdef SHADOWPW
struct spwd *ss;
int t, c;
#endif
char *pass = "";
if (!(pp = getpwnam(name)))
{
debug1("getpwnam(\"%s\") failed\n", name);
if (!(pw1 && *pw1 && *pw1 != '\377'))
{
debug("no unix account, no screen passwd\n");
sorry++;
}
}
else
pass = pp->pw_passwd;
#ifdef SHADOWPW
for (t = 0; t < 13; t++)
{
c = pass[t];
if (!(c == '.' || c == '/' ||
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z')))
break;
}
if (t < 13)
{
if (!(ss = getspnam(name)))
{
debug1("getspnam(\"%s\") failed\n", name);
sorry++;
}
else
pass = ss->sp_pwdp;
}
#endif
if (pw2 && *pw2 && *pw2 != '\377')
{
if (!*pass ||
strcmp(crypt(pw2, pass), pass))
{
debug("System password mismatch\n");
sorry++;
}
}
else
if (*pass)
sorry++;
#endif
if (pw1 && *pw1 && *pw1 != '\377')
{
if (!*u->u_password ||
strcmp(crypt(pw1, u->u_password), u->u_password))
{
debug("screen password mismatch\n");
sorry++;
}
}
else
if (*u->u_password)
sorry++;
}
debug2("syslog(LOG_NOTICE, \"screen %s: \"su %s\" ", SockPath, name);
debug2("%s for \"%s\"\n", sorry ? "failed" : "succeded", (*up)->u_name);
#ifndef NOSYSLOG
# ifdef BSD_42
openlog("screen", LOG_PID);
# else
openlog("screen", LOG_PID, LOG_AUTH);
# endif
syslog(LOG_NOTICE, "%s: \"su %s\" %s for \"%s\"", SockPath, name,
sorry ? "failed" : "succeded", (*up)->u_name);
closelog();
#else
debug("NOT LOGGED.\n");
#endif
if (sorry)
return "Sorry.";
else
*up = u;
return NULL;
}
#endif
#ifdef MULTIUSER
int
NewWindowAcl(w, u)
struct win *w;
struct acluser *u;
{
int i, j;
debug2("NewWindowAcl %s's umask_w_bits for window %d\n",
u ? u->u_name : "everybody", w->w_number);
if (GrowBitfield(&w->w_mon_notify, 0, maxusercount, 0) ||
GrowBitfield(&w->w_lio_notify, 0, maxusercount, 0))
return -1;
for (j = 0; j < ACL_BITS_PER_WIN; j++)
{
if (GrowBitfield(&w->w_userbits[j], 0, maxusercount, 0))
{
while (--j >= 0)
free((char *)w->w_userbits[j]);
free((char *)w->w_mon_notify);
free((char *)w->w_lio_notify);
return -1;
}
for (i = 0; i < maxusercount; i++)
if (u ? (ACLBIT(i) & ACLBYTE(u->u_umask_w_bits[j], i)) :
default_w_bit[j])
ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i);
}
return 0;
}
void
FreeWindowAcl(w)
struct win *w;
{
int i;
for (i = 0; i < ACL_BITS_PER_WIN; i++)
free((char *)w->w_userbits[i]);
free((char *)w->w_mon_notify);
free((char *)w->w_lio_notify);
}
static int
AclSetPermCmd(u, mode, cmd)
struct acluser *u;
char *mode;
struct comm *cmd;
{
int neg = 0;
char *m = mode;
while (*m)
{
switch (*m++)
{
case '-':
neg = 1;
continue;
case '+':
neg = 0;
continue;
case 'a':
case 'e':
case 'x':
if (neg)
ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) &= ~ACLBIT(u->u_id);
else
ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) |= ACLBIT(u->u_id);
break;
case 'r':
case 'w':
break;
default:
return -1;
}
}
return 0;
}
static int
AclSetPermWin(uu, u, mode, win)
struct acluser *u, *uu;
char *mode;
struct win *win;
{
int neg = 0;
int bit, bits;
AclBits *bitarray;
char *m = mode;
if (uu)
{
debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode);
bitarray = uu->u_umask_w_bits;
}
else
{
ASSERT(win);
bitarray = win->w_userbits;
debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
}
while (*m)
{
switch (*m++)
{
case '-':
neg = 1;
continue;
case '+':
neg = 0;
continue;
case 'r':
bits = (1 << ACL_READ);
break;
case 'w':
bits = (1 << ACL_WRITE);
break;
case 'x':
bits = (1 << ACL_EXEC);
break;
case 'a':
bits = (1 << ACL_BITS_PER_WIN) - 1;
break;
default:
return -1;
}
for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
{
if (!(bits & (1 << bit)))
continue;
if (neg)
ACLBYTE(bitarray[bit], u->u_id) &= ~ACLBIT(u->u_id);
else
ACLBYTE(bitarray[bit], u->u_id) |= ACLBIT(u->u_id);
if (!uu && (win->w_wlockuser == u) && neg && (bit == ACL_WRITE))
{
debug2("%s lost writelock on win %d\n", u->u_name, win->w_number);
win->w_wlockuser = NULL;
if (win->w_wlock == WLOCK_ON)
win->w_wlock = WLOCK_AUTO;
}
}
}
if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0')
{
if (win)
{
debug1("AclSetPermWin: default_w_bits '%s'.\n", mode);
for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
default_w_bit[bit] =
(ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
}
else
{
debug1("AclSetPermWin: default_c_bits '%s'.\n", mode);
for (bit = 0; bit < ACL_BITS_PER_CMD; bit++)
default_c_bit[bit] =
(ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
}
UserDel(u->u_name, NULL);
}
return 0;
}
int
AclSetPerm(uu, u, mode, s)
struct acluser *uu, *u;
char *mode, *s;
{
struct win *w;
int i;
char *p, ch;
debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n",
u->u_name, mode, s);
while (*s)
{
switch (*s)
{
case '*':
return AclSetPerm(uu, u, mode, "#?");
case '#':
if (uu)
AclSetPermWin(uu, u, mode, (struct win *)1);
else
for (w = windows; w; w = w->w_next)
AclSetPermWin((struct acluser *)0, u, mode, w);
s++;
break;
case '?':
if (uu)
AclSetPermWin(uu, u, mode, (struct win *)0);
else
for (i = 0; i <= RC_LAST; i++)
AclSetPermCmd(u, mode, &comms[i]);
s++;
break;
default:
for (p = s; *p && *p != ' ' && *p != '\t' && *p != ','; p++)
;
if ((ch = *p))
*p++ = '\0';
if ((i = FindCommnr(s)) != RC_ILLEGAL)
AclSetPermCmd(u, mode, &comms[i]);
else if (((i = WindowByNoN(s)) >= 0) && wtab[i])
AclSetPermWin((struct acluser *)0, u, mode, wtab[i]);
else
return -1;
if (ch)
p[-1] = ch;
s = p;
}
}
return 0;
}
static int
UserAcl(uu, u, argc, argv)
struct acluser *uu, **u;
int argc;
char **argv;
{
if ((*u && !strcmp((*u)->u_name, "nobody")) ||
(argc > 1 && !strcmp(argv[0], "nobody")))
return -1;
switch (argc)
{
case 1+1+2:
debug2("UserAcl: user '%s', password '%s':", argv[0], argv[1]);
return (UserAdd(argv[0], argv[1], u) < 0) ||
AclSetPerm(uu, *u, argv[2], argv[3]);
case 1+2:
debug1("UserAcl: user '%s', no password:", argv[0]);
return (UserAdd(argv[0], NULL, u) < 0) ||
AclSetPerm(uu, *u, argv[1], argv[2]);
case 1+1:
debug2("UserAcl: user '%s', password '%s'\n", argv[0], argv[1]);
return UserAdd(argv[0], argv[1], u) < 0;
case 1:
debug1("UserAcl: user '%s', no password:", argv[0]);
return (UserAdd(argv[0], NULL, u) < 0) ||
AclSetPerm(uu, *u, "+a", "#?");
default:
return -1;
}
}
static int
UserAclCopy(to_up, from_up)
struct acluser **to_up, **from_up;
{
struct win *w;
int i, j, to_id, from_id;
if (!*to_up || !*from_up)
return -1;
debug2("UserAclCopy: from user '%s' to user '%s'\n",
(*from_up)->u_name, (*to_up)->u_name);
if ((to_id = (*to_up)->u_id) == (from_id = (*from_up)->u_id))
return -1;
for (w = windows; w; w = w->w_next)
{
for (i = 0; i < ACL_BITS_PER_WIN; i++)
{
if (ACLBYTE(w->w_userbits[i], from_id) & ACLBIT(from_id))
ACLBYTE(w->w_userbits[i], to_id) |= ACLBIT(to_id);
else
{
ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id);
if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE))
{
debug2("%s lost wlock on win %d\n",
(*to_up)->u_name, w->w_number);
w->w_wlockuser = NULL;
if (w->w_wlock == WLOCK_ON)
w->w_wlock = WLOCK_AUTO;
}
}
}
}
for (j = 0; j <= RC_LAST; j++)
{
for (i = 0; i < ACL_BITS_PER_CMD; i++)
{
if (ACLBYTE(comms[j].userbits[i], from_id) & ACLBIT(from_id))
ACLBYTE(comms[j].userbits[i], to_id) |= ACLBIT(to_id);
else
ACLBYTE(comms[j].userbits[i], to_id) &= ~ACLBIT(to_id);
}
}
return 0;
}
int
UsersAcl(uu, argc, argv)
struct acluser *uu;
int argc;
char **argv;
{
char *s;
int r;
struct acluser **cf_u = NULL;
if (argc == 1)
{
char *p = NULL;
s = argv[0];
while (*s)
if (*s++ == '=') p = s;
if (p)
{
p[-1] = '\0';
cf_u = FindUserPtr(p);
}
}
if (argv[0][0] == '*' && argv[0][1] == '\0')
{
struct acluser **u;
debug("all users acls.\n");
for (u = &users; *u; u = &(*u)->u_next)
if (strcmp("nobody", (*u)->u_name) &&
((cf_u) ?
((r = UserAclCopy(u, cf_u)) < 0) :
((r = UserAcl(uu, u, argc, argv)) < 0)))
return -1;
return 0;
}
do
{
for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++)
;
*s ? (*s++ = '\0') : (*s = '\0');
debug2("UsersAcl(uu, \"%s\", argc=%d)\n", argv[0], argc);
if ((cf_u) ?
((r = UserAclCopy(FindUserPtr(argv[0]), cf_u)) < 0) :
((r = UserAcl(uu, FindUserPtr(argv[0]), argc, argv)) < 0))
return -1;
} while (*(argv[0] = s));
return 0;
}
int
AclUmask(u, str, errp)
struct acluser *u;
char *str;
char **errp;
{
char mode[16];
char *av[3];
char *p, c = '\0';
for (p = str; *p; p++)
if ((c = *p) == '+' || c == '-')
break;
if (!*p)
{
*errp = "Bad argument. Should be ``[user[,user...]{+|-}rwxn''.";
return -1;
}
strncpy(mode, p, 15);
mode[15] = '\0';
*p = '\0';
if (!strcmp("??", str))
{
str++;
av[2] = "?";
}
else
av[2] = "#";
av[1] = mode;
av[0] = *str ? str : "*";
if (UsersAcl(u, 3, av))
{
*errp = "UsersAcl failed. Hmmm.";
*p = c;
return -1;
}
*p = c;
return 0;
}
void
AclWinSwap(a, b)
int a, b;
{
debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
}
struct acluser *EffectiveAclUser = NULL;
int
AclCheckPermWin(u, mode, w)
struct acluser *u;
int mode;
struct win *w;
{
int ok;
if (mode < 0 || mode >= ACL_BITS_PER_WIN)
return -1;
if (EffectiveAclUser)
{
debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name);
u = EffectiveAclUser;
}
ok = ACLBYTE(w->w_userbits[mode], u->u_id) & ACLBIT(u->u_id);
debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number);
if (!ok)
{
struct aclusergroup **g = &u->u_group;
struct acluser *saved_eff = EffectiveAclUser;
EffectiveAclUser = NULL;
while (*g)
{
if (!AclCheckPermWin((*g)->u, mode, w))
break;
g = &(*g)->next;
}
EffectiveAclUser = saved_eff;
if (*g)
ok = 1;
}
debug1("%d\n", !ok);
return !ok;
}
int
AclCheckPermCmd(u, mode, c)
struct acluser *u;
int mode;
struct comm *c;
{
int ok;
if (mode < 0 || mode >= ACL_BITS_PER_CMD)
return -1;
if (EffectiveAclUser)
{
debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name);
u = EffectiveAclUser;
}
ok = ACLBYTE(c->userbits[mode], u->u_id) & ACLBIT(u->u_id);
debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name);
if (!ok)
{
struct aclusergroup **g = &u->u_group;
struct acluser *saved_eff = EffectiveAclUser;
EffectiveAclUser = NULL;
while (*g)
{
if (!AclCheckPermCmd((*g)->u, mode, c))
break;
g = &(*g)->next;
}
EffectiveAclUser = saved_eff;
if (*g)
ok = 1;
}
debug1("%d\n", !ok);
return !ok;
}
#endif