]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/checktty.c
1 /* checktty.c - linked into login, checks user against /etc/usertty
2 Created 25-Aug-95 by Peter Orbaek <poe@daimi.aau.dk>
3 Fixed by JDS June 1996 to clear lists and close files
5 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
6 - added Native Language Support
10 #include <sys/types.h>
11 #include <sys/param.h>
23 #include <sys/syslog.h>
27 # include <sys/sysmacros.h>
28 # include <linux/major.h>
31 #include "pathnames.h"
36 struct hostent hostaddress
;
40 badlogin(const char *s
)
42 printf("badlogin: %s\n", s
);
48 printf("sleepexit %d\n", x
);
53 static gid_t mygroups
[NGROUPS
];
54 static int num_groups
;
58 /* linked list of names */
64 enum State
{ StateUsers
, StateGroups
, StateClasses
};
66 #define CLASSNAMELEN 32
69 struct grplist
*first
;
70 struct ttyclass
*next
;
71 char classname
[CLASSNAMELEN
];
74 struct ttyclass
*ttyclasses
= NULL
;
77 am_in_group(char *group
)
84 for (ge
= mygroups
; ge
< mygroups
+ num_groups
; ge
++) {
85 if (g
->gr_gid
== *ge
) return 1;
92 find_groups(gid_t defgrp
, const char *user
)
94 num_groups
= getgroups(NGROUPS
, mygroups
);
97 static struct ttyclass
*
98 new_class(char *class)
102 tc
= (struct ttyclass
*)malloc(sizeof(struct ttyclass
));
104 printf(_("login: memory low, login may fail\n"));
105 syslog(LOG_WARNING
, _("can't malloc for ttyclass"));
109 tc
->next
= ttyclasses
;
111 xstrncpy(tc
->classname
, class, CLASSNAMELEN
);
117 add_to_class(struct ttyclass
*tc
, char *tty
)
121 if (tc
== NULL
) return;
123 ge
= (struct grplist
*)malloc(sizeof(struct grplist
));
125 printf(_("login: memory low, login may fail\n"));
126 syslog(LOG_WARNING
, _("can't malloc for grplist"));
130 ge
->next
= tc
->first
;
131 xstrncpy(ge
->name
, tty
, NAMELEN
);
136 /* return true if tty is a pty. Very linux dependent */
138 isapty(const char *tty
)
143 /* avoid snprintf - old systems do not have it */
144 if (strlen(tty
) + 6 > sizeof(devname
))
146 sprintf(devname
, "/dev/%s", tty
);
148 #if defined(__linux__)
149 if((stat(devname
, &stb
) >= 0) && S_ISCHR(stb
.st_mode
)) {
150 int majordev
= major(stb
.st_rdev
);
152 /* this is for linux versions before 1.3: use major 4 */
153 if(majordev
== TTY_MAJOR
&& minor(stb
.st_rdev
) >= 192)
156 #if defined(PTY_SLAVE_MAJOR)
157 /* this is for linux 1.3 and newer: use major 3 */
158 if(majordev
== PTY_SLAVE_MAJOR
)
162 #if defined(UNIX98_PTY_SLAVE_MAJOR) && defined(UNIX98_PTY_MAJOR_COUNT)
163 /* this is for linux 2.1.116 and newer: use majors 136-143 */
164 if(majordev
>= UNIX98_PTY_SLAVE_MAJOR
&&
165 majordev
< UNIX98_PTY_SLAVE_MAJOR
+ UNIX98_PTY_MAJOR_COUNT
)
174 /* match the hostname hn against the pattern pat */
176 hnmatch(const char *hn
, const char *pat
)
178 int x1
, x2
, x3
, x4
, y1
, y2
, y3
, y4
;
179 unsigned long p
, mask
, a
;
183 if ((hn
== NULL
) && (strcmp(pat
, "localhost") == 0)) return 1;
184 if ((hn
== NULL
) || hn
[0] == 0) return 0;
186 if (pat
[0] >= '0' && pat
[0] <= '9') {
187 /* pattern is an IP QUAD address and a mask x.x.x.x/y.y.y.y */
188 sscanf(pat
, "%d.%d.%d.%d/%d.%d.%d.%d", &x1
, &x2
, &x3
, &x4
,
190 p
= (((unsigned long)x1
<<24)+((unsigned long)x2
<<16)
191 +((unsigned long)x3
<<8)+((unsigned long)x4
));
192 mask
= (((unsigned long)y1
<<24)+((unsigned long)y2
<<16)
193 +((unsigned long)y3
<<8)+((unsigned long)y4
));
195 if (!hostaddress
.h_addr_list
|| !hostaddress
.h_addr_list
[0])
198 ha
= (unsigned char *)hostaddress
.h_addr_list
[0];
199 a
= (((unsigned long)ha
[0]<<24)+((unsigned long)ha
[1]<<16)
200 +((unsigned long)ha
[2]<<8)+((unsigned long)ha
[3]));
201 return ((p
& mask
) == (a
& mask
));
203 /* pattern is a suffix of a FQDN */
207 return (strcasecmp(pat
, hn
+ m
- n
) == 0);
211 static char *wdays
[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
213 /* example timespecs:
217 meaning monday, tuesday or wednesday between 8:00 and 17:59
221 meaning fridays from 4:00 to 5:59 and from 13:00 to 13:59
224 timeok(struct tm
*t
, char *spec
)
233 while ((p
= strsep(&sp
, ":"))) {
234 if (*p
>= '0' && *p
<= '9') {
236 if (h
== t
->tm_hour
) hourok
= 1;
237 if ((q
= strchr(p
, '-')) && (q
[1] >= '0' && q
[1] <= '9')) {
239 if (h
<= t
->tm_hour
&& t
->tm_hour
<= h2
) hourok
= 1;
241 } else if (strcasecmp(wdays
[t
->tm_wday
], p
) == 0) {
246 return (dayok
&& hourok
);
249 /* return true if tty equals class or is in the class defined by class.
250 Also return true if hostname matches the hostname pattern, class
251 or a pattern in the class named by class. */
253 in_class(const char *tty
, char *class)
266 if (class[0] == '[') {
267 if ((p
= strchr(class, ']'))) {
269 xstrncpy(timespec
, class+1, sizeof(timespec
));
271 if(!timeok(tm
, timespec
)) return 0;
274 /* really ought to warn about syntax error */
277 if (strcmp(tty
, class) == 0) return 1;
279 if ((class[0] == '@') && isapty(tty
)
280 && hnmatch(hostname
, class+1)) return 1;
282 for (tc
= ttyclasses
; tc
; tc
= tc
->next
) {
283 if (strcmp(tc
->classname
, class) == 0) {
284 for (ge
= tc
->first
; ge
; ge
= ge
->next
) {
288 if ((p
= strchr(n
, ']'))) {
290 xstrncpy(timespec
, n
+1, sizeof(timespec
));
292 if(!timeok(tm
, timespec
)) continue;
295 /* really ought to warn about syntax error */
298 if (strcmp(n
, tty
) == 0) return 1;
300 if ((n
[0] == '@') && isapty(tty
)
301 && hnmatch(hostname
, n
+1)) return 1;
309 /* start JDS - SBA */
311 free_group(struct grplist
*ge
)
314 memset(ge
->name
, 0, NAMELEN
);
315 free_group(ge
->next
);
322 free_class(struct ttyclass
*tc
)
325 memset(tc
->classname
, 0, CLASSNAMELEN
);
326 free_group(tc
->first
);
328 free_class(tc
->next
);
337 free_class(ttyclasses
);
343 checktty(const char *user
, const char *tty
, struct passwd
*pwd
)
346 char buf
[256], defaultbuf
[256];
348 enum State state
= StateUsers
;
351 /* no /etc/usertty, default to allow access */
353 if (!(f
= fopen("usertty", "r"))) return;
355 if (!(f
= fopen(_PATH_USERTTY
, "r"))) return;
360 return; /* misspelled username handled elsewhere */
363 find_groups(pwd
->pw_gid
, user
);
366 while(fgets(buf
, 255, f
)) {
369 for(ptr
= buf
; ptr
< buf
+ 256; ptr
++)
370 if(*ptr
== '#') *ptr
= 0;
373 xstrncpy(defaultbuf
, buf
, 256);
377 if (strncmp("GROUPS", buf
, 6) == 0) {
380 } else if (strncmp("USERS", buf
, 5) == 0) {
383 } else if (strncmp("CLASSES", buf
, 7) == 0) {
384 state
= StateClasses
;
389 if((state
== StateUsers
&& (strncmp(user
, buf
, 8) == 0))
390 || (state
== StateGroups
&& am_in_group(buf
))) {
391 found_match
= 1; /* we found a line matching the user */
392 while((ptr
= strtok(NULL
, "\t\n "))) {
393 if (in_class(tty
, ptr
)) {
395 free_all(); /* JDS */
399 } else if (state
== StateClasses
) {
400 /* define a new tty/host class */
401 struct ttyclass
*tc
= new_class(buf
);
403 while ((ptr
= strtok(NULL
, "\t\n "))) {
404 add_to_class(tc
, ptr
);
410 /* user is not explicitly mentioned in /etc/usertty, if there was
411 a default rule, use that */
413 strtok(defaultbuf
, " \t");
414 while((ptr
= strtok(NULL
, "\t\n "))) {
415 if (in_class(tty
, ptr
)) {
416 free_all(); /* JDS */
421 /* there was a default rule, but user didn't match, reject! */
422 printf(_("Login on %s from %s denied by default.\n"), tty
, hostname
);
428 /* if we get here, /etc/usertty exists, there's a line
429 matching our username, but it doesn't contain the
430 name of the tty where the user is trying to log in.
433 printf(_("Login on %s from %s denied.\n"), tty
, hostname
);
438 /* users not matched in /etc/usertty are by default allowed access
440 free_all(); /* JDS */
444 main(int argc
, char *argv
[])
448 pw
= getpwnam(argv
[1]);
449 checktty(argv
[1], argv
[2], pw
);