2 Unix SMB/Netbios implementation.
5 Winbind daemon - user related function
7 Copyright (C) Tim Potter 2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 /* Fill a pwent structure with information we have obtained */
29 static void winbindd_fill_pwent(struct winbindd_pw
*pw
, char *username
,
30 uid_t unix_uid
, gid_t unix_gid
,
31 SAM_USERINFO_CTR
*user_info
)
35 if ((pw
== NULL
) || (username
== NULL
) || (user_info
== NULL
)) {
41 pw
->pw_uid
= unix_uid
;
42 pw
->pw_gid
= unix_gid
;
46 strncpy(pw
->pw_name
, username
, sizeof(pw
->pw_name
) - 1);
48 /* Full name (gecos) */
50 unistr2_to_ascii(temp
, &user_info
->info
.id21
->uni_full_name
,
54 strncpy(pw
->pw_gecos
, temp
, sizeof(pw
->pw_gecos
) - 1);
58 unistr2_to_ascii(temp
, &user_info
->info
.id21
->uni_dir_drive
,
61 strncpy(pw
->pw_dir
, temp
, sizeof(pw
->pw_dir
) - 1);
65 strncpy(pw
->pw_passwd
, "*", sizeof(pw
->pw_passwd
) - 1);
69 strncpy(pw
->pw_shell
, "/dev/null", sizeof(pw
->pw_shell
) - 1);
72 /* Return a password structure from a username */
74 enum winbindd_result
winbindd_getpwnam_from_user(struct winbindd_state
*state
)
76 uint32 name_type
, user_rid
;
77 SAM_USERINFO_CTR user_info
;
78 DOM_SID domain_sid
, user_sid
, group_sid
, tmp_sid
;
79 fstring name_domain
, name_user
, tmp_name
, domain_controller
;
82 /* Look for user domain name */
84 fstrcpy(tmp_name
, state
->request
.data
.username
);
85 fstrcpy(name_domain
, strtok(tmp_name
, "/\\"));
86 fstrcpy(name_user
, strtok(NULL
, ""));
88 /* Get domain sid for the domain */
90 if (!find_domain_sid_from_name(name_domain
, &domain_sid
,
92 DEBUG(0, ("Could not get domain sid for domain %s\n", name_domain
));
93 return WINBINDD_ERROR
;
96 /* Get rid and name type from name */
98 if (!winbindd_lookup_by_name(domain_controller
, &domain_sid
, name_user
,
99 &user_sid
, &name_type
)) {
100 DEBUG(1, ("user '%s' does not exist\n", name_user
));
101 return WINBINDD_ERROR
;
104 if (name_type
!= SID_NAME_USER
) {
105 DEBUG(1, ("name '%s' is not a user name: %d\n", name_user
, name_type
));
106 return WINBINDD_ERROR
;
109 /* Get some user info. Split the user rid from the sid obtained from
110 the winbind_lookup_by_name() call and use it in a
111 winbind_lookup_userinfo() */
113 sid_copy(&tmp_sid
, &user_sid
);
114 sid_split_rid(&tmp_sid
, &user_rid
);
116 if (!winbindd_lookup_userinfo(domain_controller
, &domain_sid
, user_rid
,
118 DEBUG(1, ("pwnam_from_user(): error getting user info for user '%s'\n",
120 return WINBINDD_ERROR
;
123 /* Resolve the uid number */
125 sid_copy(&user_sid
, &domain_sid
);
126 sid_append_rid(&user_sid
, user_info
.info
.id21
->user_rid
);
128 if (!winbindd_surs_sam_sid_to_unixid(&user_sid
, SID_NAME_USER
, &uid
)) {
129 DEBUG(1, ("error getting user id for user\n"));
130 return WINBINDD_ERROR
;
133 /* Resolve the gid number */
135 sid_copy(&group_sid
, &domain_sid
);
136 sid_append_rid(&group_sid
, user_info
.info
.id21
->group_rid
);
138 if (!winbindd_surs_sam_sid_to_unixid(&group_sid
, SID_NAME_DOM_GRP
, &gid
)) {
139 DEBUG(1, ("error getting group id for user %s\n", name_user
));
140 return WINBINDD_ERROR
;
143 /* Now take all this information and fill in a passwd structure */
145 winbindd_fill_pwent(&state
->response
.data
.pw
,
146 state
->request
.data
.username
, uid
.id
, gid
.id
,
151 free_samr_userinfo_ctr(&user_info
);
156 /* Return a password structure given a uid number */
158 enum winbindd_result
winbindd_getpwnam_from_uid(struct winbindd_state
*state
)
160 DOM_SID domain_sid
, tmp_sid
, domain_user_sid
;
162 fstring username
, domain_controller
;
163 enum SID_NAME_USE name_type
;
164 SAM_USERINFO_CTR user_info
;
165 POSIX_ID surs_uid
, surs_gid
;
167 /* Get sid from uid */
169 surs_uid
.id
= state
->request
.data
.uid
;
170 surs_uid
.type
= SURS_POSIX_UID_AS_USR
;
172 if (!winbindd_surs_unixid_to_sam_sid(&surs_uid
, &domain_user_sid
, True
)) {
173 DEBUG(1, ("Could not convert uid %d to domain sid\n",
174 state
->request
.data
.uid
));
175 return WINBINDD_ERROR
;
178 /* Find domain controller and domain sid */
180 if (!find_domain_sid_from_uid(state
->request
.data
.uid
, &domain_sid
,
181 NULL
, domain_controller
)) {
182 DEBUG(0, ("Could not find domain for uid %d\n",
183 state
->request
.data
.uid
));
184 return WINBINDD_ERROR
;
187 /* Get name and name type from rid */
189 if (!winbindd_lookup_by_sid(domain_controller
, &domain_sid
,
190 &domain_user_sid
, username
, &name_type
)) {
193 sid_to_string(temp
, &domain_user_sid
);
194 DEBUG(1, ("Could not lookup sid %s\n", temp
));
195 return WINBINDD_ERROR
;
198 /* Get some user info */
200 sid_copy(&tmp_sid
, &domain_user_sid
);
201 sid_split_rid(&tmp_sid
, &user_rid
);
203 if (!winbindd_lookup_userinfo(domain_controller
, &domain_sid
, user_rid
,
205 DEBUG(1, ("pwnam_from_uid(): error getting user info for user '%s'\n",
207 return WINBINDD_ERROR
;
210 if (!winbindd_surs_sam_sid_to_unixid(&domain_user_sid
, SID_NAME_USER
,
212 DEBUG(1, ("error sursing unix uid\n"));
213 return WINBINDD_ERROR
;
216 /* ??? Should be domain_group_sid??? */
218 if (!winbindd_surs_sam_sid_to_unixid(&domain_user_sid
, SID_NAME_DOM_GRP
,
220 DEBUG(1, ("error sursing gid\n"));
221 return WINBINDD_ERROR
;
224 /* Fill in password structure */
226 winbindd_fill_pwent(&state
->response
.data
.pw
, username
, surs_uid
.id
,
227 surs_gid
.id
, &user_info
);
231 free_samr_userinfo_ctr(&user_info
);
237 * set/get/endpwent functions
240 /* Rewind file pointer for ntdom passwd database */
242 enum winbindd_result
winbindd_setpwent(struct winbindd_state
*state
)
244 struct winbindd_domain
*tmp
;
246 if (state
== NULL
) return WINBINDD_ERROR
;
248 /* Free old static data if it exists */
250 if (state
->getpwent_state
!= NULL
) {
251 free_getent_state(state
->getpwent_state
);
252 state
->getpwent_state
= NULL
;
255 /* Create sam pipes for each domain we know about */
257 for(tmp
= domain_list
; tmp
!= NULL
; tmp
= tmp
->next
) {
258 struct getent_state
*domain_state
;
261 /* No point looking up BUILTIN users as they don't exist */
263 if (strcmp(tmp
->domain_name
, "BUILTIN") == 0) {
267 /* Create a state record for this domain */
269 if ((domain_state
= (struct getent_state
*)
270 malloc(sizeof(struct getent_state
))) == NULL
) {
272 return WINBINDD_ERROR
;
275 ZERO_STRUCTP(domain_state
);
277 /* Connect to sam database */
279 res
= samr_connect(tmp
->domain_controller
, SEC_RIGHTS_MAXIMUM_ALLOWED
,
280 &domain_state
->sam_handle
);
282 res
= res
? samr_open_domain(&domain_state
->sam_handle
,
283 0x304, &tmp
->domain_sid
,
284 &domain_state
->sam_dom_handle
) : False
;
288 /* Add to list of open domains */
290 fstrcpy(domain_state
->domain_name
, tmp
->domain_name
);
291 DLIST_ADD(state
->getpwent_state
, domain_state
);
295 /* Error opening sam pipes */
297 samr_close(&domain_state
->sam_dom_handle
);
298 samr_close(&domain_state
->sam_handle
);
308 /* Close file pointer to ntdom passwd database */
310 enum winbindd_result
winbindd_endpwent(struct winbindd_state
*state
)
312 if (state
== NULL
) return WINBINDD_ERROR
;
314 free_getent_state(state
->getpwent_state
);
315 state
->getpwent_state
= NULL
;
320 /* Fetch next passwd entry from ntdom database */
322 enum winbindd_result
winbindd_getpwent(struct winbindd_state
*state
)
324 if (state
== NULL
) return WINBINDD_ERROR
;
326 /* Process the current head of the getent_state list */
328 while(state
->getpwent_state
!= NULL
) {
329 struct getent_state
*ent
= state
->getpwent_state
;
331 /* Get list of user entries for this pipe */
333 if (!ent
->got_sam_entries
) {
334 uint32 status
, start_ndx
= 0;
339 &ent
->sam_dom_handle
, &start_ndx
, 0, 0, 0x10000,
340 &ent
->sam_entries
, &ent
->num_sam_entries
);
341 } while (status
== STATUS_MORE_ENTRIES
);
343 samr_close(&ent
->sam_dom_handle
);
344 samr_close(&ent
->sam_handle
);
346 ent
->got_sam_entries
= True
;
349 /* Send back a user */
351 while (ent
->sam_entry_index
< ent
->num_sam_entries
) {
352 enum winbindd_result result
;
353 fstring domain_user_name
;
354 char *user_name
= (ent
->sam_entries
)
355 [ent
->sam_entry_index
].acct_name
;
357 /* Don't bother with machine accounts */
359 if (user_name
[strlen(user_name
) - 1] == '$') {
360 ent
->sam_entry_index
++;
364 /* Prepend domain to name */
366 fstrcpy(domain_user_name
, ent
->domain_name
);
367 fstrcat(domain_user_name
, "/");
368 fstrcat(domain_user_name
, user_name
);
370 /* Get passwd entry from user name */
372 fstrcpy(state
->request
.data
.username
, domain_user_name
);
373 result
= winbindd_getpwnam_from_user(state
);
375 ent
->sam_entry_index
++;
377 /* Return if user lookup worked */
379 if (result
== WINBINDD_OK
) {
385 DEBUG(1, ("could not getpwnam_from_user for username %s\n",
389 /* We've exhausted all users for this pipe - close it down and
390 start on the next one. */
392 if (ent
->sam_entries
!= NULL
) free(ent
->sam_entries
);
393 ent
->sam_entries
= NULL
;
395 DLIST_REMOVE(state
->getpwent_state
, state
->getpwent_state
);
398 /* Out of pipes so we're done */
400 return WINBINDD_ERROR
;