@@ -31,17 +31,20 @@ static uint32_t string_split(uint32_t *minor_status, char sep,
31
31
p = memchr (str , sep , len );
32
32
if (!p ) return GSSERRS (0 , GSS_S_UNAVAILABLE );
33
33
34
- if (s1 ) {
35
- l = p - str ;
34
+ /* left side */
35
+ l = p - str ;
36
+ if (s1 && l != 0 ) {
36
37
r1 = strndup (str , l );
37
38
if (!r1 ) {
38
39
set_GSSERR (ENOMEM );
39
40
goto done ;
40
41
}
41
42
}
42
- if (s2 ) {
43
- p ++ ;
44
- l = len - (p - str );
43
+
44
+ /* right side */
45
+ p ++ ;
46
+ l = len - (p - str );
47
+ if (s2 && l != 0 ) {
45
48
r2 = strndup (p , l );
46
49
if (!r2 ) {
47
50
set_GSSERR (ENOMEM );
@@ -62,43 +65,169 @@ static uint32_t string_split(uint32_t *minor_status, char sep,
62
65
return GSSERR ();
63
66
}
64
67
68
+ /* Form of names allowed in GSSNTLMSSP now:
69
+ *
70
+ * Standard Forms:
71
+ * foo
72
+ * USERNAME: foo
73
+ * DOMAIN: <null>
74
+ *
75
+ * BAR\foo
76
+ * USERNAME: foo
77
+ * DOMAIN: BAR
78
+ *
79
+ * foo@BAR
80
+ * USERNAME: foo
81
+ * DOMAIN: BAR
82
+ *
83
+ * Enterprise name forms:
84
+ * foo\@bar.example.com
85
+
86
+ * DOMAIN: <null>
87
+ *
88
+ * foo\@bar.example.com@BAR
89
+
90
+ * DOMAIN: BAR
91
+ *
92
+
93
+
94
+ * DOMAIN: <null>
95
+ *
96
+
97
+
98
+ * DOMAIN: BAR
99
+ *
100
+
101
+
102
+ * DOMAIN: BAR@dom
103
+ *
104
+ * Invalid forms:
105
+ * BAR@dom\@foo..
106
+ * DOM\foo\@bar
107
+ * foo@bar\@baz
108
+ */
65
109
#define MAX_NAME_LEN 1024
66
- static uint32_t get_enterprise_name (uint32_t * minor_status ,
67
- const char * str , size_t len ,
68
- char * * username )
110
+ static uint32_t parse_user_name (uint32_t * minor_status ,
111
+ const char * str , size_t len ,
112
+ char * * domain , char * * username )
69
113
{
70
114
uint32_t retmaj ;
71
115
uint32_t retmin ;
72
- char * buf ;
73
- char * e ;
116
+ char * at , * sep ;
74
117
75
118
if (len > MAX_NAME_LEN ) {
76
119
return GSSERRS (ERR_NAMETOOLONG , GSS_S_BAD_NAME );
77
120
}
78
- buf = alloca (len + 1 );
79
121
80
- memcpy ( buf , str , len ) ;
81
- buf [ len ] = '\0' ;
122
+ * username = NULL ;
123
+ * domain = NULL ;
82
124
83
- e = strstr (buf , "\\@" );
84
- if (e ) {
85
- /* remove escape */
86
- memmove (e , e + 1 , len - (e - buf ));
87
- } else {
88
- /* check if domain part contains dot */
89
- e = strchr (buf , '@' );
90
- if (e ) {
91
- e = strchr (e , '.' );
125
+ /* let's check if there are '@' or '\' signs */
126
+ at = memchr (str , '@' , len );
127
+ sep = memchr (str , '\\' , len );
128
+
129
+ /* Check if enterprise name first */
130
+ if (at && sep ) {
131
+ /* we may have an enterprise name here */
132
+ char strbuf [len + 1 ];
133
+ char * buf = strbuf ;
134
+ bool domain_handled = false;
135
+
136
+ /* copy buf to manipulate it */
137
+ memcpy (buf , str , len );
138
+ buf [len ] = '\0' ;
139
+
140
+ /* adjust pointers relative to new buffer */
141
+ sep = buf + (sep - str );
142
+ at = buf + (at - str );
143
+
144
+ if (sep > at ) {
145
+ /* domain name contains an '@' sign ... */
146
+ if (* (sep + 1 ) == '@' ) {
147
+ /* invalid case of XXX@YYY\@ZZZ*/
148
+ set_GSSERR (EINVAL );
149
+ goto done ;
150
+ }
151
+ } else if (at - sep == 1 ) {
152
+ /* it's just a '\@' escape */
153
+ /* no leading domain */
154
+ sep = NULL ;
155
+ }
156
+
157
+ if (sep ) {
158
+ /* leading domain, copy if domain name is not empty */
159
+ domain_handled = true;
160
+
161
+ /* terminate and copy domain, even if empty */
162
+ /* NOTE: this is important for the Windbind integration case
163
+ * where we need to tell the machinery to *not* add the default
164
+ * domain name, it happens when the domain is NULL. */
165
+ * sep = '\0' ;
166
+ * domain = strdup (buf );
167
+ if (NULL == * domain ) {
168
+ set_GSSERR (ENOMEM );
169
+ goto done ;
170
+ }
171
+ /* point buf at username part */
172
+ len = len - (sep - buf ) - 1 ;
173
+ buf = sep + 1 ;
174
+ }
175
+
176
+ for (at = strchr (buf , '@' ); at != NULL ; at = strchr (at , '@' )) {
177
+ if (* (at - 1 ) == '\\' ) {
178
+ if (domain_handled ) {
179
+ /* Invalid forms like DOM\foo\@bar or foo@bar\@baz */
180
+ free (* domain );
181
+ * domain = NULL ;
182
+ set_GSSERR (EINVAL );
183
+ goto done ;
184
+ }
185
+ /* remove escape, moving all including terminating '\0' */
186
+ memmove (at - 1 , at , len - (at - buf ) + 1 );
187
+ } else if (!domain_handled ) {
188
+ /* an '@' without escape and no previous
189
+ * domain was split out.
190
+ * the rest of the string is the domain */
191
+ * at = '\0' ;
192
+ * domain = strdup (at + 1 );
193
+ if (NULL == * domain ) {
194
+ set_GSSERR (ENOMEM );
195
+ goto done ;
196
+ }
197
+ /* note we continue the loop to check if any invalid
198
+ * \@ escapes is found in the domain part */
199
+ }
200
+ at += 1 ;
92
201
}
202
+
203
+ * username = strdup (buf );
204
+ if (NULL == * username ) {
205
+ set_GSSERR (ENOMEM );
206
+ goto done ;
207
+ }
208
+
209
+ /* we got an enterprise name, return */
210
+ set_GSSERRS (0 , GSS_S_COMPLETE );
211
+ goto done ;
93
212
}
94
- if (!e ) return GSSERRS (0 , GSS_S_UNAVAILABLE );
95
213
96
- * username = strdup ( buf );
97
- if (NULL == * username ) {
98
- set_GSSERR ( ENOMEM );
214
+ /* Check if in classic DOMAIN\User windows format */
215
+ if (sep ) {
216
+ retmaj = string_split ( & retmin , '\\' , str , len , domain , username );
99
217
goto done ;
100
218
}
101
219
220
+ /* else accept a user@domain format too */
221
+ if (at ) {
222
+ retmaj = string_split (& retmin , '@' , str , len , username , domain );
223
+ goto done ;
224
+ }
225
+
226
+ /* finally, take string as simple user name */
227
+ * username = strndup (str , len );
228
+ if (NULL == * username ) {
229
+ set_GSSERR (ENOMEM );
230
+ }
102
231
set_GSSERRS (0 , GSS_S_COMPLETE );
103
232
104
233
done :
@@ -186,44 +315,11 @@ uint32_t gssntlm_import_name_by_mech(uint32_t *minor_status,
186
315
} else if (gss_oid_equal (input_name_type , GSS_C_NT_USER_NAME )) {
187
316
188
317
name -> type = GSSNTLM_NAME_USER ;
189
- name -> data .user .domain = NULL ;
190
-
191
- /* Check if enterprise name first */
192
- retmaj = get_enterprise_name (& retmin ,
193
- input_name_buffer -> value ,
194
- input_name_buffer -> length ,
195
- & name -> data .user .name );
196
- if ((retmaj == GSS_S_COMPLETE ) ||
197
- (retmaj != GSS_S_UNAVAILABLE )) {
198
- goto done ;
199
- }
200
- /* Check if in classic DOMAIN\User windows format */
201
- retmaj = string_split (& retmin , '\\' ,
202
- input_name_buffer -> value ,
203
- input_name_buffer -> length ,
204
- & name -> data .user .domain ,
205
- & name -> data .user .name );
206
- if ((retmaj == GSS_S_COMPLETE ) ||
207
- (retmaj != GSS_S_UNAVAILABLE )) {
208
- goto done ;
209
- }
210
- /* else accept a user@domain format too */
211
- retmaj = string_split (& retmin , '@' ,
212
- input_name_buffer -> value ,
213
- input_name_buffer -> length ,
214
- & name -> data .user .name ,
215
- & name -> data .user .domain );
216
- if ((retmaj == GSS_S_COMPLETE ) ||
217
- (retmaj != GSS_S_UNAVAILABLE )) {
218
- goto done ;
219
- }
220
- /* finally, take string as simple user name */
221
- name -> data .user .name = strndup (input_name_buffer -> value ,
222
- input_name_buffer -> length );
223
- if (!name -> data .user .name ) {
224
- set_GSSERR (ENOMEM );
225
- }
226
- retmaj = GSS_S_COMPLETE ;
318
+ retmaj = parse_user_name (& retmin ,
319
+ input_name_buffer -> value ,
320
+ input_name_buffer -> length ,
321
+ & name -> data .user .domain ,
322
+ & name -> data .user .name );
227
323
} else if (gss_oid_equal (input_name_type , GSS_C_NT_MACHINE_UID_NAME )) {
228
324
229
325
name -> type = GSSNTLM_NAME_USER ;
0 commit comments