2 * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
3 * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
4 * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se>
5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 675
19 * Mass Ave, Cambridge, MA 02139, USA.
25 #include <rpcsvc/nis.h>
27 extern int DEBUGLEVEL;
31 /***************************************************************
33 the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
62 ****************************************************************/
66 #define NPF_USER_RID 2
67 #define NPF_SMB_GRPID 3
68 #define NPF_GROUP_RID 4
73 #define NPF_LOGOFF_T 9
75 #define NPF_PWDLSET_T 11
76 #define NPF_PWDLCHG_T 12
77 #define NPF_PWDMCHG_T 13
78 #define NPF_FULL_NAME 14
79 #define NPF_HOME_DIR 15
80 #define NPF_DIR_DRIVE 16
81 #define NPF_LOGON_SCRIPT 17
82 #define NPF_PROFILE_PATH 18
83 #define NPF_ACCT_DESC 19
84 #define NPF_WORKSTATIONS 20
87 /***************************************************************
88 Signal function to tell us we timed out.
89 ****************************************************************/
90 static void gotalarm_sig(void)
95 /***************************************************************
96 make_nisname_from_user_rid
97 ****************************************************************/
98 static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
100 static pstring nisname;
102 safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
103 slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
104 safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
105 safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
110 /***************************************************************
111 make_nisname_from_uid
112 ****************************************************************/
113 static char *make_nisname_from_uid(int uid, char *pfile)
115 static pstring nisname;
117 safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
118 slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
119 safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
120 safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
125 /***************************************************************
126 make_nisname_from_name
127 ****************************************************************/
128 static char *make_nisname_from_name(char *user_name, char *pfile)
130 static pstring nisname;
132 safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
133 safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
134 safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
135 safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
140 /***************************************************************
141 Start to enumerate the nisplus passwd list. Returns a void pointer
142 to ensure no modification outside this module.
144 do not call this function directly. use passdb.c instead.
146 ****************************************************************/
147 static void *startnisppwent(BOOL update)
152 /***************************************************************
153 End enumeration of the nisplus passwd list.
154 ****************************************************************/
155 static void endnisppwent(void *vp)
159 /*************************************************************************
160 Routine to return the next entry in the nisplus passwd list.
161 this function is a nice, messy combination of reading:
162 - the nisplus passwd file
163 - the unix password database
164 - nisp.conf options (not done at present).
166 do not call this function directly. use passdb.c instead.
168 *************************************************************************/
169 static struct sam_passwd *getnisp21pwent(void *vp)
174 /*************************************************************************
175 Return the current position in the nisplus passwd list as an unsigned long.
176 This must be treated as an opaque token.
178 do not call this function directly. use passdb.c instead.
180 *************************************************************************/
181 static unsigned long getnisppwpos(void *vp)
186 /*************************************************************************
187 Set the current position in the nisplus passwd list from unsigned long.
188 This must be treated as an opaque token.
190 do not call this function directly. use passdb.c instead.
192 *************************************************************************/
193 static BOOL setnisppwpos(void *vp, unsigned long tok)
198 /*************************************************************************
199 sets a NIS+ attribute
200 *************************************************************************/
201 static void set_single_attribute(nis_object *new_obj, int col,
202 char *val, int len, int flags)
204 if (new_obj == NULL) return;
206 ENTRY_VAL(new_obj, col) = val;
207 ENTRY_LEN(new_obj, col) = len;
211 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
215 /************************************************************************
216 Routine to add an entry to the nisplus passwd file.
218 do not call this function directly. use passdb.c instead.
220 *************************************************************************/
221 static BOOL add_nisp21pwd_entry(struct sam_passwd *newpwd)
225 nis_result *nis_user;
226 nis_result *result = NULL,
229 nis_object new_obj, *obj;
244 bzero(logon_t , sizeof(logon_t ));
245 bzero(logoff_t , sizeof(logoff_t ));
246 bzero(kick_t , sizeof(kick_t ));
247 bzero(pwdlset_t, sizeof(pwdlset_t));
248 bzero(pwdlchg_t, sizeof(pwdlchg_t));
249 bzero(pwdmchg_t, sizeof(pwdmchg_t));
251 pfile = lp_smb_passwd_file();
253 nisname = make_nisname_from_name(newpwd->smb_name, pfile);
254 result = nis_list(nisname, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP,NULL,NULL);
255 if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
257 DEBUG(3, ( "add_nisppwd_entry: nis_list failure: %s: %s\n",
258 nisname, nis_sperrno(result->status)));
259 nis_freeresult(nis_user);
260 nis_freeresult(result);
264 if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
266 DEBUG(3, ("add_nisppwd_entry: User already exists in NIS+ password db: %s\n",
268 nis_freeresult(result);
269 nis_freeresult(nis_user);
274 /* User not found. */
277 DEBUG(3, ("add_nisppwd_entry: User not found in NIS+ password db: %s\n",
279 nis_freeresult(result);
280 nis_freeresult(nis_user);
286 tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
287 if (tblresult->status != NIS_SUCCESS)
289 nis_freeresult(result);
290 nis_freeresult(nis_user);
291 nis_freeresult(tblresult);
292 DEBUG(3, ( "add_nisppwd_entry: nis_lookup failure: %s\n",
293 nis_sperrno(tblresult->status)));
297 new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
298 new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
299 new_obj.zo_owner = NIS_RES_OBJECT(nis_user)->zo_owner;
300 new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
301 new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
302 new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
304 new_obj.zo_data.zo_type = ENTRY_OBJ;
306 new_obj.zo_data.objdata_u.en_data.en_type = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_type;
307 new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_maxcol;
308 new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val = calloc(new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len, sizeof(entry_col));
311 pdb_set_logon_time (logon_t , sizeof(logon_t ), newpwd->logon_time );
312 pdb_set_logoff_time (logoff_t , sizeof(logoff_t ), newpwd->logoff_time );
313 pdb_set_kickoff_time (kickoff_t, sizeof(kickoff_t), newpwd->kickoff_time );
315 pdb_set_last_set_time (pwdlset_t, sizeof(pwdlset_t), newpwd->pass_last_set_time );
317 pdb_set_can_change_time (pwdlchg_t, sizeof(pwdlchg_t), newpwd->pass_can_change_time );
318 pdb_set_must_change_time(pwdmchg_t, sizeof(pwdmchg_t), newpwd->pass_must_change_time);
321 slprintf(uid, sizeof(uid), "%u", newpwd->smb_userid);
322 slprintf(user_rid, sizeof(user_rid), "0x%x", newpwd->user_rid);
323 slprintf(smb_grpid, sizeof(smb_grpid), "%u", newpwd->smb_grpid);
324 slprintf(group_rid, sizeof(group_rid), "0x%x", newpwd->group_rid);
326 safe_strcpy(acb, pdb_encode_acct_ctrl(newpwd->acct_ctrl), sizeof(acb));
328 set_single_attribute(&new_obj, NPF_NAME , newpwd->smb_name , strlen(newpwd->smb_name) , 0);
329 set_single_attribute(&new_obj, NPF_UID , uid , strlen(uid) , 0);
330 set_single_attribute(&new_obj, NPF_USER_RID , user_rid , strlen(user_rid) , 0);
331 set_single_attribute(&new_obj, NPF_SMB_GRPID , smb_grpid , strlen(smb_grpid) , 0);
332 set_single_attribute(&new_obj, NPF_GROUP_RID , group_rid , strlen(group_rid) , 0);
333 set_single_attribute(&new_obj, NPF_ACB , acb , strlen(acb) , 0);
334 set_single_attribute(&new_obj, NPF_LMPWD , newpwd->smb_passwd , newpwd->smb_passwd != NULL ? 16 : 0 , EN_CRYPT);
335 set_single_attribute(&new_obj, NPF_NTPWD , newpwd->smb_nt_passwd, newpwd->smb_nt_passwd != NULL ? 16 : 0, EN_CRYPT);
336 set_single_attribute(&new_obj, NPF_LOGON_T , logon_t , strlen(logon_t) , 0);
337 set_single_attribute(&new_obj, NPF_LOGOFF_T , logoff_t , strlen(logoff_t) , 0);
338 set_single_attribute(&new_obj, NPF_KICK_T , kick_t , strlen(kick_t) , 0);
339 set_single_attribute(&new_obj, NPF_PWDLSET_T , pwdlset_t , strlen(pwdlset_t) , 0);
340 set_single_attribute(&new_obj, NPF_PWDLCHG_T , pwdlchg_t , strlen(pwdlchg_t) , 0);
341 set_single_attribute(&new_obj, NPF_PWDMCHG_T , pwdmchg_t , strlen(pwdmchg_t) , 0);
342 set_single_attribute(&new_obj, NPF_FULL_NAME , newpwd->full_name , strlen(newpwd->full_name) , 0);
343 set_single_attribute(&new_obj, NPF_HOME_DIR , newpwd->home_dir , strlen(newpwd->home_dir) , 0);
344 set_single_attribute(&new_obj, NPF_DIR_DRIVE , newpwd->dir_drive , strlen(newpwd->dir_drive) , 0);
345 set_single_attribute(&new_obj, NPF_LOGON_SCRIPT , newpwd->logon_script , strlen(newpwd->logon_script) , 0);
346 set_single_attribute(&new_obj, NPF_PROFILE_PATH , newpwd->profile_path , strlen(newpwd->profile_path) , 0);
347 set_single_attribute(&new_obj, NPF_ACCT_DESC , newpwd->acct_desc , strlen(newpwd->acct_desc) , 0);
348 set_single_attribute(&new_obj, NPF_WORKSTATIONS , newpwd->workstations , strlen(newpwd->workstations) , 0);
349 set_single_attribute(&new_obj, NPF_HOURS , newpwd->hours , newpwd->hours_len , 0);
354 addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
356 nis_freeresult(nis_user);
359 nis_freeresult(tblresult);
362 if (addresult->status != NIS_SUCCESS)
364 DEBUG(3, ( "add_nisppwd_entry: NIS+ table update failed: %s\n",
365 nisname, nis_sperrno(addresult->status)));
366 nis_freeresult(addresult);
367 nis_freeresult(result);
371 nis_freeresult(addresult);
372 nis_freeresult(result);
377 /************************************************************************
378 Routine to search the nisplus passwd file for an entry matching the username.
379 and then modify its password entry. We can't use the startnisppwent()/
380 getnisppwent()/endnisppwent() interfaces here as we depend on looking
381 in the actual file to decide how much room we have to write data.
382 override = False, normal
383 override = True, override XXXXXXXX'd out password or NO PASS
385 do not call this function directly. use passdb.c instead.
387 ************************************************************************/
388 static BOOL mod_nisp21pwd_entry(struct sam_passwd* pwd, BOOL override)
393 /************************************************************************
394 makes a struct sam_passwd from a NIS+ result.
395 ************************************************************************/
396 static BOOL make_sam_from_nisp(struct sam_passwd *pw_buf, nis_result *result)
399 static pstring user_name;
400 static unsigned char smbpwd[16];
401 static unsigned char smbntpwd[16];
405 if (pw_buf == NULL || result == NULL) return False;
407 pdb_init_sam(pw_buf);
409 if (result->status != NIS_SUCCESS)
411 DEBUG(0, ("make_smb_from_nisp: NIS+ lookup failure: %s\n",
412 nis_sperrno(result->status)));
416 /* User not found. */
417 if (NIS_RES_NUMOBJ(result) <= 0)
419 DEBUG(10, ("make_smb_from_nisp: user not found in NIS+\n"));
423 if (NIS_RES_NUMOBJ(result) > 1)
425 DEBUG(10, ("make_smb_from_nisp: WARNING: Multiple entries for user in NIS+ table!\n"));
428 /* Grab the first hit. */
429 obj = &NIS_RES_OBJECT(result)[0];
431 /* Check the lanman password column. */
432 p = (uchar *)ENTRY_VAL(obj, NPF_LMPWD);
433 if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbpwd))
435 DEBUG(0, ("make_smb_from_nisp: malformed LM pwd entry.\n"));
439 /* Check the NT password column. */
440 p = (uchar *)ENTRY_VAL(obj, NPF_NTPWD);
441 if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbntpwd))
443 DEBUG(0, ("make_smb_from_nisp: malformed NT pwd entry\n"));
447 strncpy(user_name, ENTRY_VAL(obj, NPF_NAME), sizeof(user_name));
448 uidval = atoi(ENTRY_VAL(obj, NPF_UID));
450 pw_buf->smb_name = user_name;
451 pw_buf->smb_userid = uidval;
452 pw_buf->smb_passwd = smbpwd;
453 pw_buf->smb_nt_passwd = smbntpwd;
458 /*************************************************************************
459 Routine to search the nisplus passwd file for an entry matching the username
460 *************************************************************************/
461 static struct sam_passwd *getnisp21pwnam(char *name)
463 /* Static buffers we will return. */
464 static struct sam_passwd pw_buf;
469 if (!*lp_smb_passwd_file())
471 DEBUG(0, ("No SMB password file set\n"));
475 DEBUG(10, ("getnisppwnam: search by name: %s\n", name));
476 DEBUG(10, ("getnisppwnam: using NIS+ table %s\n", lp_smb_passwd_file()));
478 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", name, lp_smb_passwd_file());
480 /* Search the table. */
482 signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
485 result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
488 signal(SIGALRM, SIGNAL_CAST SIG_DFL);
492 DEBUG(0,("getnisppwnam: NIS+ lookup time out\n"));
493 nis_freeresult(result);
497 ret = make_sam_from_nisp(&pw_buf, result);
498 nis_freeresult(result);
500 return ret ? &pw_buf : NULL;
503 /*************************************************************************
504 Routine to search the nisplus passwd file for an entry matching the username
505 *************************************************************************/
506 static struct sam_passwd *getnisp21pwrid(uint32 rid)
508 /* Static buffers we will return. */
509 static struct sam_passwd pw_buf;
514 if (!*lp_smb_passwd_file())
516 DEBUG(0, ("No SMB password file set\n"));
520 DEBUG(10, ("getnisp21pwrid: search by rid: %x\n", rid));
521 DEBUG(10, ("getnisp21pwrid: using NIS+ table %s\n", lp_smb_passwd_file()));
523 nisname = make_nisname_from_user_rid(rid, lp_smb_passwd_file());
525 /* Search the table. */
527 signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
530 result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
533 signal(SIGALRM, SIGNAL_CAST SIG_DFL);
537 DEBUG(0,("getnisp21pwrid: NIS+ lookup time out\n"));
538 nis_freeresult(result);
542 ret = make_sam_from_nisp(&pw_buf, result);
543 nis_freeresult(result);
545 return ret ? &pw_buf : NULL;
549 * Derived functions for NIS+.
552 static struct smb_passwd *getnisppwent(void *vp)
554 return pdb_sam_to_smb(getnisp21pwent(vp));
557 static BOOL add_nisppwd_entry(struct smb_passwd *newpwd)
559 return add_nisp21pwd_entry(pdb_smb_to_sam(newpwd));
562 static BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override)
564 return mod_nisp21pwd_entry(pdb_smb_to_sam(pwd), override);
567 static struct smb_passwd *getnisppwnam(char *name)
569 return pdb_sam_to_smb(getnisp21pwnam(name));
572 static struct sam_passwd *getnisp21pwuid(uid_t smb_userid)
574 return getnisp21pwrid(pdb_uid_to_user_rid(smb_userid));
577 static struct smb_passwd *getnisppwuid(uid_t smb_userid)
579 return pdb_sam_to_smb(getnisp21pwuid(smb_userid));
582 static struct sam_disp_info *getnispdispnam(char *name)
584 return pdb_sam_to_dispinfo(getnisp21pwnam(name));
587 static struct sam_disp_info *getnispdisprid(uint32 rid)
589 return pdb_sam_to_dispinfo(getnisp21pwrid(rid));
592 static struct sam_disp_info *getnispdispent(void *vp)
594 return pdb_sam_to_dispinfo(getnisp21pwent(vp));
597 static struct passdb_ops nispasswd_ops = {
618 struct passdb_ops *nisplus_initialize_password_db(void)
620 return &nispasswd_ops;
624 void nisplus_dummy_function(void) { } /* stop some compilers complaining */
625 #endif /* USE_NISPLUS_DB */
627 /* useful code i can't bring myself to delete */
629 /* checks user in unix password database. don't want to do that, here. */
630 nisname = make_nisname_from_name(newpwd->smb_name, "passwd.org_dir");
632 nis_user = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
634 if (nis_user->status != NIS_SUCCESS || NIS_RES_NUMOBJ(nis_user) <= 0)
636 DEBUG(3, ("add_nisppwd_entry: Unable to get NIS+ passwd entry for user: %s.\n",
637 nis_sperrno(nis_user->status)));
641 user_obj = NIS_RES_OBJECT(nis_user);
642 make_nisname_from_name(ENTRY_VAL(user_obj,0), pfile);