preparing for release of alpha.2.5
[Samba.git] / source / nsswitch / winbindd_user.c
blobd1ea38dbcac3c0616e631e7dc4eb5a451e6a84f2
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.0
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.
24 #include "includes.h"
25 #include "nterr.h"
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)
33 fstring temp;
35 if ((pw == NULL) || (username == NULL) || (user_info == NULL)) {
36 return;
39 /* Fill in uid/gid */
41 pw->pw_uid = unix_uid;
42 pw->pw_gid = unix_gid;
44 /* Username */
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,
51 sizeof(temp) - 1);
54 strncpy(pw->pw_gecos, temp, sizeof(pw->pw_gecos) - 1);
56 /* Home directory */
58 unistr2_to_ascii(temp, &user_info->info.id21->uni_dir_drive,
59 sizeof(temp));
61 strncpy(pw->pw_dir, temp, sizeof(pw->pw_dir) - 1);
63 /* Password */
65 strncpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
67 /* Shell */
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;
80 POSIX_ID uid, gid;
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,
91 domain_controller)) {
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,
117 NULL, &user_info)) {
118 DEBUG(1, ("pwnam_from_user(): error getting user info for user '%s'\n",
119 name_user));
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,
147 &user_info);
149 /* Free user info */
151 free_samr_userinfo_ctr(&user_info);
153 return WINBINDD_OK;
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;
161 uint32 user_rid;
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)) {
191 fstring temp;
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,
204 NULL, &user_info)) {
205 DEBUG(1, ("pwnam_from_uid(): error getting user info for user '%s'\n",
206 username));
207 return WINBINDD_ERROR;
210 if (!winbindd_surs_sam_sid_to_unixid(&domain_user_sid, SID_NAME_USER,
211 &surs_uid)) {
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,
219 &surs_gid)) {
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);
229 /* Free user info */
231 free_samr_userinfo_ctr(&user_info);
233 return WINBINDD_OK;
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;
259 BOOL res;
261 /* No point looking up BUILTIN users as they don't exist */
263 if (strcmp(tmp->domain_name, "BUILTIN") == 0) {
264 continue;
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;
286 if (res) {
288 /* Add to list of open domains */
290 fstrcpy(domain_state->domain_name, tmp->domain_name);
291 DLIST_ADD(state->getpwent_state, domain_state);
293 } else {
295 /* Error opening sam pipes */
297 samr_close(&domain_state->sam_dom_handle);
298 samr_close(&domain_state->sam_handle);
300 free(domain_state);
305 return WINBINDD_OK;
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;
317 return WINBINDD_OK;
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;
336 do {
337 status =
338 samr_enum_dom_users(
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++;
361 continue;
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) {
380 return result;
383 /* Try next user */
385 DEBUG(1, ("could not getpwnam_from_user for username %s\n",
386 domain_user_name));
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;