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 gets a NIS+ attribute
142 *************************************************************************/
143 static void get_single_attribute(nis_object *new_obj, int col,
148 if (new_obj == NULL || val == NULL) return;
150 entry_len = ENTRY_LEN(new_obj, col);
153 DEBUG(10,("get_single_attribute: entry length truncated\n"));
157 safe_strcpy(val, len, ENTRY_VAL(new_obj, col));
160 /***************************************************************
161 calls nis_list, returns results.
162 ****************************************************************/
163 static nis_result *nisp_get_nis_list(char *nis_name)
166 result = nis_list(nis_name, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP,NULL,NULL);
169 signal(SIGALRM, SIGNAL_CAST SIG_DFL);
173 DEBUG(0,("nisp_get_nis_list: NIS+ lookup time out\n"));
174 nis_freeresult(result);
182 struct nisp_enum_info
188 /***************************************************************
189 Start to enumerate the nisplus passwd list. Returns a void pointer
190 to ensure no modification outside this module.
192 do not call this function directly. use passdb.c instead.
194 ****************************************************************/
195 static void *startnisppwent(BOOL update)
197 static struct nisp_enum_info res;
198 res.result = nisp_get_nis_list(lp_smb_passwd_file());
200 return res.result != NULL ? &res : NULL;
203 /***************************************************************
204 End enumeration of the nisplus passwd list.
205 ****************************************************************/
206 static void endnisppwent(void *vp)
210 /*************************************************************************
211 Routine to return the next entry in the nisplus passwd list.
212 this function is a nice, messy combination of reading:
213 - the nisplus passwd file
214 - the unix password database
215 - nisp.conf options (not done at present).
217 do not call this function directly. use passdb.c instead.
219 *************************************************************************/
220 static struct sam_passwd *getnisp21pwent(void *vp)
225 /*************************************************************************
226 Return the current position in the nisplus passwd list as an unsigned long.
227 This must be treated as an opaque token.
229 do not call this function directly. use passdb.c instead.
231 *************************************************************************/
232 static unsigned long getnisppwpos(void *vp)
237 /*************************************************************************
238 Set the current position in the nisplus passwd list from unsigned long.
239 This must be treated as an opaque token.
241 do not call this function directly. use passdb.c instead.
243 *************************************************************************/
244 static BOOL setnisppwpos(void *vp, unsigned long tok)
249 /*************************************************************************
250 sets a NIS+ attribute
251 *************************************************************************/
252 static void set_single_attribute(nis_object *new_obj, int col,
253 char *val, int len, int flags)
255 if (new_obj == NULL) return;
257 ENTRY_VAL(new_obj, col) = val;
258 ENTRY_LEN(new_obj, col) = len;
262 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
266 /************************************************************************
267 Routine to add an entry to the nisplus passwd file.
269 do not call this function directly. use passdb.c instead.
271 *************************************************************************/
272 static BOOL add_nisp21pwd_entry(struct sam_passwd *newpwd)
276 nis_result *nis_user;
277 nis_result *result = NULL,
280 nis_object new_obj, *obj;
289 fstring smb_nt_passwd;
298 bzero(logon_t , sizeof(logon_t ));
299 bzero(logoff_t , sizeof(logoff_t ));
300 bzero(kickoff_t, sizeof(kickoff_t));
301 bzero(pwdlset_t, sizeof(pwdlset_t));
302 bzero(pwdlchg_t, sizeof(pwdlchg_t));
303 bzero(pwdmchg_t, sizeof(pwdmchg_t));
305 pfile = lp_smb_passwd_file();
307 nisname = make_nisname_from_name(newpwd->smb_name, pfile);
308 result = nisp_get_nis_list(nisname);
309 if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
311 DEBUG(3, ( "add_nisppwd_entry: nis_list failure: %s: %s\n",
312 nisname, nis_sperrno(result->status)));
313 nis_freeresult(nis_user);
314 nis_freeresult(result);
318 if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
320 DEBUG(3, ("add_nisppwd_entry: User already exists in NIS+ password db: %s\n",
322 nis_freeresult(result);
323 nis_freeresult(nis_user);
328 /* User not found. */
331 DEBUG(3, ("add_nisppwd_entry: User not found in NIS+ password db: %s\n",
333 nis_freeresult(result);
334 nis_freeresult(nis_user);
340 tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
341 if (tblresult->status != NIS_SUCCESS)
343 nis_freeresult(result);
344 nis_freeresult(nis_user);
345 nis_freeresult(tblresult);
346 DEBUG(3, ( "add_nisppwd_entry: nis_lookup failure: %s\n",
347 nis_sperrno(tblresult->status)));
351 new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
352 new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
353 new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
354 new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
355 new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
356 new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
358 new_obj.zo_data.zo_type = ENTRY_OBJ;
360 new_obj.zo_data.objdata_u.en_data.en_type = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_type;
361 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;
362 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));
364 pdb_sethexpwd(smb_passwd , newpwd->smb_passwd , newpwd->acct_ctrl);
365 pdb_sethexpwd(smb_nt_passwd, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
367 pdb_set_logon_time (logon_t , sizeof(logon_t ), newpwd->logon_time );
368 pdb_set_logoff_time (logoff_t , sizeof(logoff_t ), newpwd->logoff_time );
369 pdb_set_kickoff_time (kickoff_t, sizeof(kickoff_t), newpwd->kickoff_time );
370 pdb_set_last_set_time (pwdlset_t, sizeof(pwdlset_t), newpwd->pass_last_set_time );
371 pdb_set_can_change_time (pwdlchg_t, sizeof(pwdlchg_t), newpwd->pass_can_change_time );
372 pdb_set_must_change_time(pwdmchg_t, sizeof(pwdmchg_t), newpwd->pass_must_change_time);
374 slprintf(uid, sizeof(uid), "%u", newpwd->smb_userid);
375 slprintf(user_rid, sizeof(user_rid), "0x%x", newpwd->user_rid);
376 slprintf(smb_grpid, sizeof(smb_grpid), "%u", newpwd->smb_grpid);
377 slprintf(group_rid, sizeof(group_rid), "0x%x", newpwd->group_rid);
379 safe_strcpy(acb, pdb_encode_acct_ctrl(newpwd->acct_ctrl), sizeof(acb));
381 set_single_attribute(&new_obj, NPF_NAME , newpwd->smb_name , strlen(newpwd->smb_name) , 0);
382 set_single_attribute(&new_obj, NPF_UID , uid , strlen(uid) , 0);
383 set_single_attribute(&new_obj, NPF_USER_RID , user_rid , strlen(user_rid) , 0);
384 set_single_attribute(&new_obj, NPF_SMB_GRPID , smb_grpid , strlen(smb_grpid) , 0);
385 set_single_attribute(&new_obj, NPF_GROUP_RID , group_rid , strlen(group_rid) , 0);
386 set_single_attribute(&new_obj, NPF_ACB , acb , strlen(acb) , 0);
387 set_single_attribute(&new_obj, NPF_LMPWD , smb_passwd , strlen(smb_passwd) , EN_CRYPT);
388 set_single_attribute(&new_obj, NPF_NTPWD , smb_nt_passwd , strlen(smb_nt_passwd) , EN_CRYPT);
389 set_single_attribute(&new_obj, NPF_LOGON_T , logon_t , strlen(logon_t) , 0);
390 set_single_attribute(&new_obj, NPF_LOGOFF_T , logoff_t , strlen(logoff_t) , 0);
391 set_single_attribute(&new_obj, NPF_KICK_T , kickoff_t , strlen(kickoff_t) , 0);
392 set_single_attribute(&new_obj, NPF_PWDLSET_T , pwdlset_t , strlen(pwdlset_t) , 0);
393 set_single_attribute(&new_obj, NPF_PWDLCHG_T , pwdlchg_t , strlen(pwdlchg_t) , 0);
394 set_single_attribute(&new_obj, NPF_PWDMCHG_T , pwdmchg_t , strlen(pwdmchg_t) , 0);
395 set_single_attribute(&new_obj, NPF_FULL_NAME , newpwd->full_name , strlen(newpwd->full_name) , 0);
396 set_single_attribute(&new_obj, NPF_HOME_DIR , newpwd->home_dir , strlen(newpwd->home_dir) , 0);
397 set_single_attribute(&new_obj, NPF_DIR_DRIVE , newpwd->dir_drive , strlen(newpwd->dir_drive) , 0);
398 set_single_attribute(&new_obj, NPF_LOGON_SCRIPT , newpwd->logon_script , strlen(newpwd->logon_script) , 0);
399 set_single_attribute(&new_obj, NPF_PROFILE_PATH , newpwd->profile_path , strlen(newpwd->profile_path) , 0);
400 set_single_attribute(&new_obj, NPF_ACCT_DESC , newpwd->acct_desc , strlen(newpwd->acct_desc) , 0);
401 set_single_attribute(&new_obj, NPF_WORKSTATIONS , newpwd->workstations , strlen(newpwd->workstations) , 0);
402 set_single_attribute(&new_obj, NPF_HOURS , newpwd->hours , newpwd->hours_len , 0);
406 addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
408 nis_freeresult(nis_user);
411 nis_freeresult(tblresult);
414 if (addresult->status != NIS_SUCCESS)
416 DEBUG(3, ( "add_nisppwd_entry: NIS+ table update failed: %s\n",
417 nisname, nis_sperrno(addresult->status)));
418 nis_freeresult(addresult);
419 nis_freeresult(result);
423 nis_freeresult(addresult);
424 nis_freeresult(result);
429 /************************************************************************
430 Routine to search the nisplus passwd file for an entry matching the username.
431 and then modify its password entry. We can't use the startnisppwent()/
432 getnisppwent()/endnisppwent() interfaces here as we depend on looking
433 in the actual file to decide how much room we have to write data.
434 override = False, normal
435 override = True, override XXXXXXXX'd out password or NO PASS
437 do not call this function directly. use passdb.c instead.
439 ************************************************************************/
440 static BOOL mod_nisp21pwd_entry(struct sam_passwd* pwd, BOOL override)
445 /************************************************************************
446 makes a struct sam_passwd from a NIS+ result.
447 ************************************************************************/
448 static BOOL make_sam_from_nisp(struct sam_passwd *pw_buf, nis_result *result)
451 static pstring user_name;
452 static unsigned char smbpwd[16];
453 static unsigned char smbntpwd[16];
457 if (pw_buf == NULL || result == NULL) return False;
459 pdb_init_sam(pw_buf);
461 if (result->status != NIS_SUCCESS)
463 DEBUG(0, ("make_smb_from_nisp: NIS+ lookup failure: %s\n",
464 nis_sperrno(result->status)));
468 /* User not found. */
469 if (NIS_RES_NUMOBJ(result) <= 0)
471 DEBUG(10, ("make_smb_from_nisp: user not found in NIS+\n"));
475 if (NIS_RES_NUMOBJ(result) > 1)
477 DEBUG(10, ("make_smb_from_nisp: WARNING: Multiple entries for user in NIS+ table!\n"));
480 /* Grab the first hit. */
481 obj = &NIS_RES_OBJECT(result)[0];
483 /* Check the lanman password column. */
484 p = (uchar *)ENTRY_VAL(obj, NPF_LMPWD);
485 if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbpwd))
487 DEBUG(0, ("make_smb_from_nisp: malformed LM pwd entry.\n"));
491 /* Check the NT password column. */
492 p = (uchar *)ENTRY_VAL(obj, NPF_NTPWD);
493 if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbntpwd))
495 DEBUG(0, ("make_smb_from_nisp: malformed NT pwd entry\n"));
499 strncpy(user_name, ENTRY_VAL(obj, NPF_NAME), sizeof(user_name));
500 uidval = atoi(ENTRY_VAL(obj, NPF_UID));
502 pw_buf->smb_name = user_name;
503 pw_buf->smb_userid = uidval;
504 pw_buf->smb_passwd = smbpwd;
505 pw_buf->smb_nt_passwd = smbntpwd;
510 /*************************************************************************
511 Routine to search the nisplus passwd file for an entry matching the username
512 *************************************************************************/
513 static struct sam_passwd *getnisp21pwnam(char *name)
515 /* Static buffers we will return. */
516 static struct sam_passwd pw_buf;
521 if (!*lp_smb_passwd_file())
523 DEBUG(0, ("No SMB password file set\n"));
527 DEBUG(10, ("getnisppwnam: search by name: %s\n", name));
528 DEBUG(10, ("getnisppwnam: using NIS+ table %s\n", lp_smb_passwd_file()));
530 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", name, lp_smb_passwd_file());
532 /* Search the table. */
534 signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
537 result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
540 signal(SIGALRM, SIGNAL_CAST SIG_DFL);
544 DEBUG(0,("getnisppwnam: NIS+ lookup time out\n"));
545 nis_freeresult(result);
549 ret = make_sam_from_nisp(&pw_buf, result);
550 nis_freeresult(result);
552 return ret ? &pw_buf : NULL;
555 /*************************************************************************
556 Routine to search the nisplus passwd file for an entry matching the username
557 *************************************************************************/
558 static struct sam_passwd *getnisp21pwrid(uint32 rid)
560 /* Static buffers we will return. */
561 static struct sam_passwd pw_buf;
566 if (!*lp_smb_passwd_file())
568 DEBUG(0, ("No SMB password file set\n"));
572 DEBUG(10, ("getnisp21pwrid: search by rid: %x\n", rid));
573 DEBUG(10, ("getnisp21pwrid: using NIS+ table %s\n", lp_smb_passwd_file()));
575 nisname = make_nisname_from_user_rid(rid, lp_smb_passwd_file());
577 /* Search the table. */
579 signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
582 result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
585 signal(SIGALRM, SIGNAL_CAST SIG_DFL);
589 DEBUG(0,("getnisp21pwrid: NIS+ lookup time out\n"));
590 nis_freeresult(result);
594 ret = make_sam_from_nisp(&pw_buf, result);
595 nis_freeresult(result);
597 return ret ? &pw_buf : NULL;
601 * Derived functions for NIS+.
604 static struct smb_passwd *getnisppwent(void *vp)
606 return pdb_sam_to_smb(getnisp21pwent(vp));
609 static BOOL add_nisppwd_entry(struct smb_passwd *newpwd)
611 return add_nisp21pwd_entry(pdb_smb_to_sam(newpwd));
614 static BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override)
616 return mod_nisp21pwd_entry(pdb_smb_to_sam(pwd), override);
619 static struct smb_passwd *getnisppwnam(char *name)
621 return pdb_sam_to_smb(getnisp21pwnam(name));
624 static struct sam_passwd *getnisp21pwuid(uid_t smb_userid)
626 return getnisp21pwrid(pdb_uid_to_user_rid(smb_userid));
629 static struct smb_passwd *getnisppwuid(uid_t smb_userid)
631 return pdb_sam_to_smb(getnisp21pwuid(smb_userid));
634 static struct sam_disp_info *getnispdispnam(char *name)
636 return pdb_sam_to_dispinfo(getnisp21pwnam(name));
639 static struct sam_disp_info *getnispdisprid(uint32 rid)
641 return pdb_sam_to_dispinfo(getnisp21pwrid(rid));
644 static struct sam_disp_info *getnispdispent(void *vp)
646 return pdb_sam_to_dispinfo(getnisp21pwent(vp));
649 static struct passdb_ops nispasswd_ops = {
670 struct passdb_ops *nisplus_initialize_password_db(void)
672 return &nispasswd_ops;
676 void nisplus_dummy_function(void) { } /* stop some compilers complaining */
677 #endif /* USE_NISPLUS_DB */
679 /* useful code i can't bring myself to delete */
681 /* checks user in unix password database. don't want to do that, here. */
682 nisname = make_nisname_from_name(newpwd->smb_name, "passwd.org_dir");
684 nis_user = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
686 if (nis_user->status != NIS_SUCCESS || NIS_RES_NUMOBJ(nis_user) <= 0)
688 DEBUG(3, ("add_nisppwd_entry: Unable to get NIS+ passwd entry for user: %s.\n",
689 nis_sperrno(nis_user->status)));
693 user_obj = NIS_RES_OBJECT(nis_user);
694 make_nisname_from_name(ENTRY_VAL(user_obj,0), pfile);