File: chkname.c

package info (click to toggle)
shadow 1%3A4.17.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 66,752 kB
  • sloc: sh: 44,927; ansic: 34,406; xml: 12,252; exp: 3,691; makefile: 1,633; python: 722; yacc: 622; perl: 120; sed: 16
file content (146 lines) | stat: -rw-r--r-- 2,755 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// SPDX-FileCopyrightText: 1990-1994, Julianne Frances Haugh
// SPDX-FileCopyrightText: 1996-2000, Marek Michałkiewicz
// SPDX-FileCopyrightText: 2001-2005, Tomasz Kłoczko
// SPDX-FileCopyrightText: 2005-2008, Nicolas François
// SPDX-FileCopyrightText: 2023-2025, Alejandro Colomar <alx@kernel.org>
// SPDX-License-Identifier: BSD-3-Clause


/*
 * is_valid_user_name(), is_valid_group_name() - check the new user/group
 * name for validity;
 * return values:
 *   true  - OK
 *   false - bad name
 * errors:
 *   EINVAL	Invalid name characters or sequences
 *   EOVERFLOW	Name longer than maximum size
 */


#include <config.h>

#ident "$Id$"

#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <unistd.h>

#ifdef __GNU__
#ifndef LOGIN_NAME_MAX
#define LOGIN_NAME_MAX 256
#endif
#endif

#include "defines.h"
#include "chkname.h"
#include "string/ctype/strisascii/strisdigit.h"
#include "string/strcmp/streq.h"


#ifndef  LOGIN_NAME_MAX
# define LOGIN_NAME_MAX  256
#endif


int allow_bad_names = false;


size_t
login_name_max_size(void)
{
	long  conf;

	conf = sysconf(_SC_LOGIN_NAME_MAX);
	if (conf == -1)
		return LOGIN_NAME_MAX;

	return conf;
}


static bool
is_valid_name(const char *name)
{
	if (allow_bad_names) {
		return true;
	}

	/*
         * User/group names must match BRE regex:
         *    [a-zA-Z0-9_.][a-zA-Z0-9_.-]*$\?
         *
         * as a non-POSIX, extension, allow "$" as the last char for
         * sake of Samba 3.x "add machine script"
         *
         * Also do not allow fully numeric names or just "." or "..".
         */

	if (strisdigit(name)) {
		errno = EINVAL;
		return false;
	}

	if (streq(name, "") ||
	    streq(name, ".") ||
	    streq(name, "..") ||
	    !((*name >= 'a' && *name <= 'z') ||
	      (*name >= 'A' && *name <= 'Z') ||
	      (*name >= '0' && *name <= '9') ||
	      *name == '_' ||
	      *name == '.'))
	{
		errno = EINVAL;
		return false;
	}

	while (!streq(++name, "")) {
		if (!((*name >= 'a' && *name <= 'z') ||
		      (*name >= 'A' && *name <= 'Z') ||
		      (*name >= '0' && *name <= '9') ||
		      *name == '_' ||
		      *name == '.' ||
		      *name == '-' ||
		      streq(name, "$")
		     ))
		{
			errno = EINVAL;
			return false;
		}
	}

	return true;
}


bool
is_valid_user_name(const char *name)
{
	if (strlen(name) >= login_name_max_size()) {
		errno = EOVERFLOW;
		return false;
	}

	return is_valid_name(name);
}


bool
is_valid_group_name(const char *name)
{
	/*
	 * Arbitrary limit for group names.
	 * HP-UX 10 limits to 16 characters
	 */
	if (   (GROUP_NAME_MAX_LENGTH > 0)
	    && (strlen (name) > GROUP_NAME_MAX_LENGTH))
	{
		errno = EOVERFLOW;
		return false;
	}

	return is_valid_name (name);
}