check_group.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /*
10  * This is a helper for the external ACL interface for Squid Cache
11  * Copyright (C) 2002 Rodrigo Albani de Campos (rodrigo@geekbunker.org)
12  *
13  * It reads STDIN looking for a username that matches a specified group
14  * Returns `OK' if the user belongs to the group or `ERR' otherwise, as
15  * described on http://devel.squid-cache.org/external_acl/config.html
16  * To compile this program, use:
17  *
18  * gcc -o check_group check_group.c
19  *
20  * Author: Rodrigo Albani de Campos
21  * E-Mail: rodrigo@geekbunker.org
22  *
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation; either version 2 of the License, or
26  * (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36  *
37  * Change Log:
38  * 2010-02-24 hno
39  * Removed group number limitation and fixed related uninitialized
40  * pointer reference (Bug #2813)
41  *
42  * Revision 1.7 2004/08/15 00:29:33 hno
43  * helper protocol changed to URL-escaped strings in Squid-3.0
44  *
45  * Revision 1.6 2002/08/12 15:48:32 hno
46  * imported strwordtok from Squid, added man page, some minor fixes
47  *
48  * Revision 1.5 2002/07/27 14:26:49 rcampos
49  * allow groups to be sent on stdin
50  *
51  * Revision 1.4 2002/04/17 01:58:48 camposr
52  * minor corrections in the getopt
53  *
54  * Revision 1.3 2002/04/17 01:43:17 camposr
55  * ready for action
56  *
57  * Revision 1.2 2002/04/17 01:32:16 camposr
58  * all main routines ready
59  *
60  * Revision 1.1 2002/04/16 05:02:32 camposr
61  * Initial revision
62  *
63  */
64 #include "squid.h"
66 #include "rfc1738.h"
67 #include "util.h"
68 
69 #include <cctype>
70 #include <cstring>
71 #if HAVE_GRP_H
72 #include <grp.h>
73 #endif
74 #if HAVE_UNISTD_H
75 #include <unistd.h>
76 #endif
77 #if HAVE_PWD_H
78 #include <pwd.h>
79 #endif
80 
81 /*
82  * Verify if user's primary group matches groupname
83  * Returns 0 if user is not on the group
84  * Returns 1 otherwise
85  */
86 static int
87 validate_user_pw(char *username, char *groupname)
88 {
89  struct passwd *p;
90  struct group *g;
91 
92  if ((p = getpwnam(username)) == nullptr) {
93  /* Returns an error if user does not exist in the /etc/passwd */
94  fprintf(stderr, "ERROR: User does not exist '%s'\n", username);
95  return 0;
96  } else {
97  /* Verify if the this is the primary user group */
98  if ((g = getgrgid(p->pw_gid)) != nullptr) {
99  if ((strcmp(groupname, g->gr_name)) == 0)
100  return 1;
101  }
102  }
103 
104  return 0;
105 }
106 
107 static int
108 validate_user_gr(char *username, char *groupname)
109 {
110  /*
111  * Verify if the user belongs to groupname as listed in the
112  * /etc/group file
113  */
114  struct group *g;
115 
116  if ((g = getgrnam(groupname)) == nullptr) {
117  fprintf(stderr, "ERROR: Group does not exist '%s'\n", groupname);
118  return 0;
119  } else {
120  while (*(g->gr_mem) != nullptr) {
121  if (strcmp(*((g->gr_mem)++), username) == 0) {
122  return 1;
123  }
124  }
125  }
126  return 0;
127 }
128 
129 static void
130 usage(char *program)
131 {
132  fprintf(stderr, "Usage: %s -g group1 [-g group2 ...] [-p] [-s]\n\n",
133  program);
134  fprintf(stderr, "-g group\n");
135  fprintf(stderr,
136  " The group name or id that the user must belong in order to\n");
137  fprintf(stderr,
138  " be allowed to authenticate.\n");
139  fprintf(stderr,
140  "-p Verify primary user group as well\n");
141  fprintf(stderr,
142  "-s Strip NT domain from usernames\n");
143  fprintf(stderr,
144  "-r Strip Kerberos realm from usernames\n");
145 }
146 
147 int
148 main(int argc, char *argv[])
149 {
150  char *user, *suser, *p;
151  char buf[HELPER_INPUT_BUFFER];
152  char **grents = nullptr;
153  int check_pw = 0, ch, ngroups = 0, i, j = 0, strip_dm = 0, strip_rm = 0;
154 
155  /* make standard output line buffered */
156  setvbuf(stdout, nullptr, _IOLBF, 0);
157 
158  /* get user options */
159  while ((ch = getopt(argc, argv, "dsrpg:")) != -1) {
160  switch (ch) {
161  case 'd':
162  debug_enabled = 1;
163  break;
164  case 's':
165  strip_dm = 1;
166  break;
167  case 'r':
168  strip_rm = 1;
169  break;
170  case 'p':
171  check_pw = 1;
172  break;
173  case 'g':
174  grents = (char**)realloc(grents, sizeof(*grents) * (ngroups+1));
175  grents[ngroups] = optarg;
176  ++ngroups;
177  break;
178  case '?':
179  if (xisprint(optopt)) {
180  fprintf(stderr, "Unknown option '-%c'.\n", optopt);
181  } else {
182  fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
183  }
184  [[fallthrough]];
185  default:
186  usage(argv[0]);
187  exit(EXIT_FAILURE);
188  }
189  }
190  if (optind < argc) {
191  fprintf(stderr, "FATAL: Unknown option '%s'\n", argv[optind]);
192  usage(argv[0]);
193  exit(EXIT_FAILURE);
194  }
195  while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
196  j = 0;
197  if ((p = strchr(buf, '\n')) == nullptr) {
198  /* too large message received.. skip and deny */
199  fprintf(stderr, "ERROR: %s: Too large: %s\n", argv[0], buf);
200  while (fgets(buf, sizeof(buf), stdin)) {
201  fprintf(stderr, "ERROR: %s: Too large..: %s\n", argv[0], buf);
202  if (strchr(buf, '\n') != nullptr)
203  break;
204  }
205  SEND_BH(HLP_MSG("Username Input too large."));
206  continue;
207  }
208  *p = '\0';
209  if ((p = strtok(buf, " ")) == nullptr) {
210  SEND_BH(HLP_MSG("No username given."));
211  continue;
212  } else {
213  user = p;
214  rfc1738_unescape(user);
215  if (strip_dm) {
216  suser = strchr(user, '\\');
217  if (!suser) suser = strchr(user, '/');
218  if (suser && suser[1]) user = suser + 1;
219  }
220  if (strip_rm) {
221  suser = strchr(user, '@');
222  if (suser) *suser = '\0';
223  }
224  /* check groups supplied by Squid */
225  while ((p = strtok(nullptr, " ")) != nullptr) {
226  rfc1738_unescape(p);
227  if (check_pw == 1)
228  j += validate_user_pw(user, p);
229  j += validate_user_gr(user, p);
230  }
231  }
232 
233  /* check groups supplied on the command line */
234  for (i = 0; i < ngroups; ++i) {
235  if (check_pw == 1) {
236  j += validate_user_pw(user, grents[i]);
237  }
238  j += validate_user_gr(user, grents[i]);
239  }
240 
241  if (j > 0) {
242  SEND_OK("");
243  } else {
244  SEND_ERR("");
245  }
246  }
247  return EXIT_SUCCESS;
248 }
249 
#define xisprint(x)
Definition: xis.h:22
char * optarg
Definition: getopt.c:51
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
static int validate_user_pw(char *username, char *groupname)
Definition: check_group.cc:87
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
#define SEND_ERR(x)
int debug_enabled
Definition: debug.cc:13
#define SEND_BH(x)
static void usage(char *program)
Definition: check_group.cc:130
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:24
int optopt
Definition: getopt.c:49
int optind
Definition: getopt.c:48
int main(int argc, char *argv[])
Definition: check_group.cc:148
#define HLP_MSG(text)
#define SEND_OK(x)
static int validate_user_gr(char *username, char *groupname)
Definition: check_group.cc:108

 

Introduction

Documentation

Support

Miscellaneous