2 * Unix SMB/CIFS implementation.
3 * SMB parameters and setup
4 * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5 * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se>
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
7 * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
9 * This program is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, write to the Free Software Foundation, Inc., 675
21 * Mass Ave, Cambridge, MA 02139, USA.
26 #ifdef WITH_NISPLUS_SAM
28 #ifdef BROKEN_NISPLUS_INCLUDE_FILES
31 * The following lines are needed due to buggy include files
32 * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
33 * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
34 * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
35 * an enum in /usr/include/rpcsvc/nis.h.
42 #if defined(GROUP_OBJ)
48 #include <rpcsvc/nis.h>
50 extern int DEBUGLEVEL;
58 static struct nisp_enum_info global_nisp_ent;
59 static VOLATILE sig_atomic_t gotalarm;
61 /***************************************************************
63 the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
92 ****************************************************************/
96 #define NPF_USER_RID 2
97 #define NPF_SMB_GRPID 3
98 #define NPF_GROUP_RID 4
102 #define NPF_LOGON_T 8
103 #define NPF_LOGOFF_T 9
104 #define NPF_KICK_T 10
105 #define NPF_PWDLSET_T 11
106 #define NPF_PWDCCHG_T 12
107 #define NPF_PWDMCHG_T 13
108 #define NPF_FULL_NAME 14
109 #define NPF_HOME_DIR 15
110 #define NPF_DIR_DRIVE 16
111 #define NPF_LOGON_SCRIPT 17
112 #define NPF_PROFILE_PATH 18
113 #define NPF_ACCT_DESC 19
114 #define NPF_WORKSTATIONS 20
117 /***************************************************************
118 Signal function to tell us we timed out.
119 ****************************************************************/
120 static void gotalarm_sig(void)
125 /***************************************************************
126 make_nisname_from_user_rid
127 ****************************************************************/
128 static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
130 static pstring nisname;
132 safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
133 slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
134 safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
135 safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
140 /***************************************************************
141 make_nisname_from_uid
142 ****************************************************************/
143 static char *make_nisname_from_uid(int uid, char *pfile)
145 static pstring nisname;
147 safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
148 slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
149 safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
150 safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
155 /***************************************************************
156 make_nisname_from_name
157 ****************************************************************/
158 static char *make_nisname_from_name(const char *user_name, char *pfile)
160 static pstring nisname;
162 safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
163 safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
164 safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
165 safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
170 /*************************************************************************
171 gets a NIS+ attribute
172 *************************************************************************/
173 static void get_single_attribute(const nis_object *new_obj, int col,
178 if (new_obj == NULL || val == NULL) return;
180 entry_len = ENTRY_LEN(new_obj, col);
186 safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
189 /************************************************************************
190 makes a struct sam_passwd from a NIS+ object.
191 ************************************************************************/
192 static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, const nis_object *obj)
195 pstring full_name; /* this must be translated to dos code page */
196 pstring acct_desc; /* this must be translated to dos code page */
197 pstring home_dir; /* set default value from smb.conf for user */
198 pstring home_drive; /* set default value from smb.conf for user */
199 pstring logon_script; /* set default value from smb.conf for user */
200 pstring profile_path; /* set default value from smb.conf for user */
203 unsigned char smbpwd[16];
204 unsigned char smbntpwd[16];
208 * time values. note: this code assumes 32bit time_t!
211 /* Don't change these timestamp settings without a good reason. They are
212 important for NT member server compatibility. */
214 pdb_set_logon_time(pw_buf, (time_t)0);
215 ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGON_T);
216 if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
219 for(i = 0; i < 8; i++) {
220 if(ptr[i] == '\0' || !isxdigit(ptr[i]))
224 pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
228 pdb_set_logoff_time(pw_buf, get_time_t_max());
229 ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGOFF_T);
230 if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
233 for(i = 0; i < 8; i++) {
234 if(ptr[i] == '\0' || !isxdigit(ptr[i]))
238 pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
242 pdb_set_kickoff_time(pw_buf, get_time_t_max());
243 ptr = (uchar *)ENTRY_VAL(obj, NPF_KICK_T);
244 if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
247 for(i = 0; i < 8; i++) {
248 if(ptr[i] == '\0' || !isxdigit(ptr[i]))
252 pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
256 pdb_set_pass_last_set_time(pw_buf, (time_t)0);
257 ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDLSET_T);
258 if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
261 for(i = 0; i < 8; i++) {
262 if(ptr[i] == '\0' || !isxdigit(ptr[i]))
266 pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
270 pdb_set_pass_can_change_time(pw_buf, (time_t)0);
271 ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDCCHG_T);
272 if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
275 for(i = 0; i < 8; i++) {
276 if(ptr[i] == '\0' || !isxdigit(ptr[i]))
280 pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
284 pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* Password never expires. */
285 ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDMCHG_T);
286 if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
289 for(i = 0; i < 8; i++) {
290 if(ptr[i] == '\0' || !isxdigit(ptr[i]))
294 pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
299 pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
300 pdb_set_domain(pw_buf, lp_workgroup());
301 /* pdb_set_nt_username() -- cant set it here... */
303 get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
304 unix_to_dos(full_name, True);
305 pdb_set_fullname(pw_buf, full_name);
307 pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
310 get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
311 unix_to_dos(acct_desc, True);
312 pdb_set_acct_desc(pw_buf, acct_desc);
314 pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
315 pdb_set_munged_dial(pw_buf, NULL);
317 pdb_set_uid(pw_buf, atoi(ENTRY_VAL(obj, NPF_UID)));
318 pdb_set_gid(pw_buf, atoi(ENTRY_VAL(obj, NPF_SMB_GRPID)));
319 pdb_set_user_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_USER_RID)));
320 pdb_set_group_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_GROUP_RID)));
322 /* values, must exist for user */
323 if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
325 get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
326 if( !(home_dir && *home_dir) ) {
327 pstrcpy(home_dir, lp_logon_home());
328 pdb_set_homedir(pw_buf, home_dir, False);
331 pdb_set_homedir(pw_buf, home_dir, True);
333 get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
334 if( !(home_drive && *home_drive) ) {
335 pstrcpy(home_drive, lp_logon_drive());
336 pdb_set_dir_drive(pw_buf, home_drive, False);
339 pdb_set_dir_drive(pw_buf, home_drive, True);
341 get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
343 if( !(logon_script && *logon_script) ) {
344 pstrcpy(logon_script, lp_logon_script(), False);
347 pdb_set_logon_script(pw_buf, logon_script, True);
349 get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
350 if( !(profile_path && *profile_path) ) {
351 pstrcpy(profile_path, lp_logon_path());
352 pdb_set_profile_path(pw_buf, profile_path, False);
355 pdb_set_profile_path(pw_buf, profile_path, True);
360 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
361 pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS);
364 /* Check the lanman password column. */
365 ptr = (char *)ENTRY_VAL(obj, NPF_LMPWD);
366 if (!pdb_set_lanman_passwd(pw_buf, NULL))
369 if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
370 pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
372 if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
373 DEBUG(0, ("malformed LM pwd entry: %s.\n",
374 pdb_get_username(pw_buf)));
377 if (!pdb_set_lanman_passwd(pw_buf, smbpwd))
381 /* Check the NT password column. */
382 ptr = ENTRY_VAL(obj, NPF_NTPWD);
383 if (!pdb_set_nt_passwd(pw_buf, NULL))
386 if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
387 strncasecmp(ptr, "NO PASSWORD", 11)) {
388 if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
389 DEBUG(0, ("malformed NT pwd entry:\
391 pdb_get_uid(pw_buf)));
394 if (!pdb_set_nt_passwd(pw_buf, smbntpwd))
398 pdb_set_unknown_3(pw_buf, 0xffffff); /* don't know */
399 pdb_set_logon_divs(pw_buf, 168); /* hours per week */
401 if( (hours_len = ENTRY_LEN(obj, NPF_HOURS)) == 21 ) {
402 memcpy(hours, ENTRY_VAL(obj, NPF_HOURS), hours_len);
404 hours_len = 21; /* 21 times 8 bits = 168 */
405 /* available at all hours */
406 memset(hours, 0xff, hours_len);
408 pdb_set_hours_len(pw_buf, hours_len);
409 pdb_set_hours(pw_buf, hours);
411 pdb_set_unknown_5(pw_buf, 0x00020000); /* don't know */
412 pdb_set_unknown_6(pw_buf, 0x000004ec); /* don't know */
417 /************************************************************************
418 makes a struct sam_passwd from a NIS+ result.
419 ************************************************************************/
420 static BOOL make_sam_from_nisresult(SAM_ACCOUNT *pw_buf, const nis_result *result)
422 if (pw_buf == NULL || result == NULL) return False;
424 if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
426 DEBUG(0, ("NIS+ lookup failure: %s\n",
427 nis_sperrno(result->status)));
431 /* User not found. */
432 if (NIS_RES_NUMOBJ(result) <= 0)
434 DEBUG(10, ("user not found in NIS+\n"));
438 if (NIS_RES_NUMOBJ(result) > 1)
440 DEBUG(10, ("WARNING: Multiple entries for user in NIS+ table!\n"));
443 /* Grab the first hit. */
444 return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
447 /*************************************************************************
448 sets a NIS+ attribute
449 *************************************************************************/
450 static void set_single_attribute(nis_object *new_obj, int col,
451 const char *val, int len, int flags)
453 if (new_obj == NULL) return;
455 ENTRY_VAL(new_obj, col) = val;
456 ENTRY_LEN(new_obj, col) = len+1;
460 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
464 /***************************************************************
465 copy or modify nis object. this object is used to add or update
467 ****************************************************************/
468 static BOOL init_nisp_from_sam(nis_object *obj, const SAM_ACCOUNT *sampass,
472 * Fill nis_object for entry add or update.
473 * if we are updateing, we have to find out differences and set
474 * EN_MODIFIED flag. also set need_to_modify to trigger
475 * nis_modify_entry() call in pdb_update_sam_account().
479 * if (modify) get data from nis_object, compare and store if
480 * different + set EN_MODIFIED and need_to_modify
484 BOOL need_to_modify = False;
485 const char *name = pdb_get_username(sampass); /* from SAM */
486 /* these must be static or allocate and free entry columns! */
487 static fstring uid; /* from SAM */
488 static fstring user_rid; /* from SAM */
489 static fstring gid; /* from SAM */
490 static fstring group_rid; /* from SAM */
491 char *acb; /* from SAM */
492 static fstring smb_passwd; /* from SAM */
493 static fstring smb_nt_passwd; /* from SAM */
494 static fstring logon_t; /* from SAM */
495 static fstring logoff_t; /* from SAM */
496 static fstring kickoff_t; /* from SAM */
497 static fstring pwdlset_t; /* from SAM */
498 static fstring pwdlchg_t; /* from SAM */
499 static fstring pwdmchg_t; /* from SAM */
500 static fstring full_name; /* from SAM */
501 static fstring acct_desc; /* from SAM */
502 static char empty[1]; /* just an empty string */
504 slprintf(uid, sizeof(uid)-1, "%u", pdb_get_uid(sampass));
505 slprintf(user_rid, sizeof(user_rid)-1, "%u",
506 pdb_get_user_rid(sampass)? pdb_get_user_rid(sampass):
507 pdb_uid_to_user_rid(pdb_get_uid(sampass)));
508 slprintf(gid, sizeof(gid)-1, "%u", pdb_get_gid(sampass));
514 rid=pdb_get_group_rid(sampass);
517 if (get_group_map_from_gid(pdb_get_gid(sampass), &map, MAPPING_WITHOUT_PRIV)) {
518 sid_peek_rid(&map.sid, &rid);
520 rid=pdb_gid_to_group_rid(pdb_get_gid(sampass));
523 slprintf(group_rid, sizeof(group_rid)-1, "%u", rid);
526 acb = pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sampass),
527 NEW_PW_FORMAT_SPACE_PADDED_LEN);
528 pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd(sampass),
529 pdb_get_acct_ctrl(sampass));
530 pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd(sampass),
531 pdb_get_acct_ctrl(sampass));
532 slprintf(logon_t, 13, "LNT-%08X",
533 (uint32)pdb_get_logon_time(sampass));
534 slprintf(logoff_t, 13, "LOT-%08X",
535 (uint32)pdb_get_logoff_time(sampass));
536 slprintf(kickoff_t, 13, "KOT-%08X",
537 (uint32)pdb_get_kickoff_time(sampass));
538 slprintf(pwdlset_t, 13, "LCT-%08X",
539 (uint32)pdb_get_pass_last_set_time(sampass));
540 slprintf(pwdlchg_t, 13, "CCT-%08X",
541 (uint32)pdb_get_pass_can_change_time(sampass));
542 slprintf(pwdmchg_t, 13, "MCT-%08X",
543 (uint32)pdb_get_pass_must_change_time(sampass));
544 safe_strcpy(full_name, pdb_get_fullname(sampass), sizeof(full_name)-1);
545 dos_to_unix(full_name, True);
546 safe_strcpy(acct_desc, pdb_get_acct_desc(sampass), sizeof(acct_desc)-1);
547 dos_to_unix(acct_desc, True);
551 if(strcmp(ENTRY_VAL(old, NPF_NAME), name))
553 need_to_modify = True;
554 set_single_attribute(obj, NPF_NAME, name, strlen(name),
560 if(pdb_get_uid(sampass) != -1) {
561 if(!ENTRY_VAL(old, NPF_UID) || strcmp(ENTRY_VAL(old, NPF_UID), uid))
563 need_to_modify = True;
564 set_single_attribute(obj, NPF_UID, uid,
565 strlen(uid), EN_MODIFIED);
570 if (pdb_get_user_rid(sampass)) {
571 if(!ENTRY_VAL(old, NPF_USER_RID) ||
572 strcmp(ENTRY_VAL(old, NPF_USER_RID), user_rid) ) {
573 need_to_modify = True;
574 set_single_attribute(obj, NPF_USER_RID, user_rid,
575 strlen(user_rid), EN_MODIFIED);
580 if (pdb_get_gid(sampass) != -1) {
581 if(!ENTRY_VAL(old, NPF_SMB_GRPID) ||
582 strcmp(ENTRY_VAL(old, NPF_SMB_GRPID), gid) ) {
583 need_to_modify = True;
584 set_single_attribute(obj, NPF_SMB_GRPID, gid,
585 strlen(gid), EN_MODIFIED);
590 if (pdb_get_group_rid(sampass)) {
591 if(!ENTRY_VAL(old, NPF_GROUP_RID) ||
592 strcmp(ENTRY_VAL(old, NPF_GROUP_RID), group_rid) ) {
593 need_to_modify = True;
594 set_single_attribute(obj, NPF_GROUP_RID, group_rid,
595 strlen(group_rid), EN_MODIFIED);
600 if (!ENTRY_VAL(old, NPF_ACB) ||
601 strcmp(ENTRY_VAL(old, NPF_ACB), acb)) {
602 need_to_modify = True;
603 set_single_attribute(obj, NPF_ACB, acb, strlen(acb), EN_MODIFIED);
607 if(!ENTRY_VAL(old, NPF_LMPWD) ||
608 strcmp(ENTRY_VAL(old, NPF_LMPWD), smb_passwd) ) {
609 need_to_modify = True;
610 set_single_attribute(obj, NPF_LMPWD, smb_passwd,
611 strlen(smb_passwd), EN_CRYPT|EN_MODIFIED);
615 if(!ENTRY_VAL(old, NPF_NTPWD) ||
616 strcmp(ENTRY_VAL(old, NPF_NTPWD), smb_nt_passwd) ) {
617 need_to_modify = True;
618 set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
619 strlen(smb_nt_passwd), EN_CRYPT|EN_MODIFIED);
623 if( pdb_get_logon_time(sampass) &&
624 (!ENTRY_VAL(old, NPF_LOGON_T) ||
625 strcmp(ENTRY_VAL(old, NPF_LOGON_T), logon_t ))) {
626 need_to_modify = True;
627 set_single_attribute(obj, NPF_LOGON_T, logon_t,
628 strlen(logon_t), EN_MODIFIED);
632 if( pdb_get_logoff_time(sampass) &&
633 (!ENTRY_VAL(old, NPF_LOGOFF_T) ||
634 strcmp(ENTRY_VAL(old, NPF_LOGOFF_T), logoff_t))) {
635 need_to_modify = True;
636 set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
637 strlen(logoff_t), EN_MODIFIED);
641 if( pdb_get_kickoff_time(sampass) &&
642 (!ENTRY_VAL(old, NPF_KICK_T) ||
643 strcmp(ENTRY_VAL(old, NPF_KICK_T), kickoff_t))) {
644 need_to_modify = True;
645 set_single_attribute(obj, NPF_KICK_T, kickoff_t,
646 strlen(kickoff_t), EN_MODIFIED);
650 if( pdb_get_pass_last_set_time(sampass) &&
651 (!ENTRY_VAL(old, NPF_PWDLSET_T) ||
652 strcmp(ENTRY_VAL(old, NPF_PWDLSET_T), pwdlset_t))) {
653 need_to_modify = True;
654 set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
655 strlen(pwdlset_t), EN_MODIFIED);
659 if( pdb_get_pass_can_change_time(sampass) &&
660 (!ENTRY_VAL(old, NPF_PWDCCHG_T) ||
661 strcmp(ENTRY_VAL(old, NPF_PWDCCHG_T), pwdlchg_t))) {
662 need_to_modify = True;
663 set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
664 strlen(pwdlchg_t), EN_MODIFIED);
668 if( pdb_get_pass_must_change_time(sampass) &&
669 (!ENTRY_VAL(old, NPF_PWDMCHG_T) ||
670 strcmp(ENTRY_VAL(old, NPF_PWDMCHG_T), pwdmchg_t))) {
671 need_to_modify = True;
672 set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
673 strlen(pwdmchg_t), EN_MODIFIED);
677 /* must support set, unset and change */
678 if ( (pdb_get_fullname(sampass) &&
679 !ENTRY_VAL(old, NPF_FULL_NAME)) ||
680 (ENTRY_VAL(old, NPF_FULL_NAME) &&
681 !pdb_get_fullname(sampass)) ||
682 (ENTRY_VAL(old, NPF_FULL_NAME) &&
683 pdb_get_fullname(sampass) &&
684 strcmp( ENTRY_VAL(old, NPF_FULL_NAME), full_name ))) {
685 need_to_modify = True;
686 set_single_attribute(obj, NPF_FULL_NAME, full_name,
687 strlen(full_name), EN_MODIFIED);
691 /* must support set, unset and change */
692 if( (pdb_get_homedir(sampass) &&
693 !ENTRY_VAL(old, NPF_HOME_DIR)) ||
694 (ENTRY_VAL(old, NPF_HOME_DIR) &&
695 !pdb_get_homedir(sampass)) ||
696 (ENTRY_VAL(old, NPF_HOME_DIR) &&
697 pdb_get_homedir(sampass) &&
698 strcmp( ENTRY_VAL(old, NPF_HOME_DIR),
699 pdb_get_homedir(sampass)))) {
700 need_to_modify = True;
701 set_single_attribute(obj, NPF_HOME_DIR, pdb_get_homedir(sampass),
702 strlen(pdb_get_homedir(sampass)), EN_MODIFIED);
706 /* must support set, unset and change */
707 if( (pdb_get_dirdrive(sampass) &&
708 !ENTRY_VAL(old, NPF_DIR_DRIVE)) ||
709 (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
710 !pdb_get_dirdrive(sampass)) ||
711 (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
712 pdb_get_dirdrive(sampass) &&
713 strcmp( ENTRY_VAL(old, NPF_DIR_DRIVE),
714 pdb_get_dirdrive(sampass)))) {
715 need_to_modify = True;
716 set_single_attribute(obj, NPF_DIR_DRIVE, pdb_get_dirdrive(sampass),
717 strlen(pdb_get_dirdrive(sampass)), EN_MODIFIED);
721 /* must support set, unset and change */
722 if( (pdb_get_logon_script(sampass) &&
723 !ENTRY_VAL(old, NPF_LOGON_SCRIPT) ||
724 (ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
725 !pdb_get_logon_script(sampass)) ||
726 ( ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
727 pdb_get_logon_script(sampass) &&
728 strcmp( ENTRY_VAL(old, NPF_LOGON_SCRIPT),
729 pdb_get_logon_script(sampass))))) {
730 need_to_modify = True;
731 set_single_attribute(obj, NPF_LOGON_SCRIPT,
732 pdb_get_logon_script(sampass),
733 strlen(pdb_get_logon_script(sampass)),
738 /* must support set, unset and change */
739 if( (pdb_get_profile_path(sampass) &&
740 !ENTRY_VAL(old, NPF_PROFILE_PATH)) ||
741 (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
742 !pdb_get_profile_path(sampass)) ||
743 (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
744 pdb_get_profile_path(sampass) &&
745 strcmp( ENTRY_VAL(old, NPF_PROFILE_PATH),
746 pdb_get_profile_path(sampass) ) )) {
747 need_to_modify = True;
748 set_single_attribute(obj, NPF_PROFILE_PATH,
749 pdb_get_profile_path(sampass),
750 strlen(pdb_get_profile_path(sampass)),
755 /* must support set, unset and change */
756 if( (pdb_get_acct_desc(sampass) &&
757 !ENTRY_VAL(old, NPF_ACCT_DESC)) ||
758 (ENTRY_VAL(old, NPF_ACCT_DESC) &&
759 !pdb_get_acct_desc(sampass)) ||
760 (ENTRY_VAL(old, NPF_ACCT_DESC) &&
761 pdb_get_acct_desc(sampass) &&
762 strcmp( ENTRY_VAL(old, NPF_ACCT_DESC), acct_desc ) )) {
763 need_to_modify = True;
764 set_single_attribute(obj, NPF_ACCT_DESC, acct_desc,
765 strlen(acct_desc), EN_MODIFIED);
769 /* must support set, unset and change */
770 if ( (pdb_get_workstations(sampass) &&
771 !ENTRY_VAL(old, NPF_WORKSTATIONS) ) ||
772 (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
773 !pdb_get_workstations(sampass)) ||
774 (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
775 pdb_get_workstations(sampass)) &&
776 strcmp( ENTRY_VAL(old, NPF_WORKSTATIONS),
777 pdb_get_workstations(sampass))) {
778 need_to_modify = True;
779 set_single_attribute(obj, NPF_WORKSTATIONS,
780 pdb_get_workstations(sampass),
781 strlen(pdb_get_workstations(sampass)),
786 if ((pdb_get_hours_len(sampass) != ENTRY_LEN(old, NPF_HOURS)) ||
787 memcmp(pdb_get_hours(sampass), ENTRY_VAL(old, NPF_HOURS),
788 ENTRY_LEN(old, NPF_HOURS))) {
789 need_to_modify = True;
790 /* set_single_attribute will add 1 for len ... */
791 set_single_attribute(obj, NPF_HOURS, pdb_get_hours(sampass),
792 pdb_get_hours_len(sampass)-1, EN_MODIFIED);
795 const char *homedir, *dirdrive, *logon_script, *profile_path, *workstations;
797 *empty = '\0'; /* empty string */
799 set_single_attribute(obj, NPF_NAME, name, strlen(name), 0);
800 set_single_attribute(obj, NPF_UID, uid, strlen(uid), 0);
801 set_single_attribute(obj, NPF_USER_RID, user_rid,
802 strlen(user_rid), 0);
803 set_single_attribute(obj, NPF_SMB_GRPID, gid, strlen(gid), 0);
804 set_single_attribute(obj, NPF_GROUP_RID, group_rid,
805 strlen(group_rid), 0);
806 set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
807 set_single_attribute(obj, NPF_LMPWD, smb_passwd,
808 strlen(smb_passwd), EN_CRYPT);
809 set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
810 strlen(smb_nt_passwd), EN_CRYPT);
811 set_single_attribute(obj, NPF_LOGON_T, logon_t,
813 set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
814 strlen(logoff_t), 0);
815 set_single_attribute(obj, NPF_KICK_T, kickoff_t,
816 strlen(kickoff_t),0);
817 set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
818 strlen(pwdlset_t), 0);
819 set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
820 strlen(pwdlchg_t), 0);
821 set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
822 strlen(pwdmchg_t), 0);
823 set_single_attribute(obj, NPF_FULL_NAME ,
824 full_name, strlen(full_name), 0);
826 if(!(homedir = pdb_get_homedir(sampass)))
829 set_single_attribute(obj, NPF_HOME_DIR,
830 homedir, strlen(homedir), 0);
832 if(!(dirdrive = pdb_get_dirdrive(sampass)))
835 set_single_attribute(obj, NPF_DIR_DRIVE,
836 dirdrive, strlen(dirdrive), 0);
838 if(!(logon_script = pdb_get_logon_script(sampass)))
839 logon_script = empty;
841 set_single_attribute(obj, NPF_LOGON_SCRIPT,
842 logon_script, strlen(logon_script), 0);
844 if(!(profile_path = pdb_get_profile_path(sampass)))
845 profile_path = empty;
847 set_single_attribute(obj, NPF_PROFILE_PATH,
848 profile_path, strlen(profile_path), 0);
850 set_single_attribute(obj, NPF_ACCT_DESC,
851 acct_desc, strlen(acct_desc), 0);
853 if(!(workstations = pdb_get_workstations(sampass)))
854 workstations = empty;
856 set_single_attribute(obj, NPF_WORKSTATIONS,
857 workstations, strlen(workstations), 0);
859 /* set_single_attribute will add 1 for len ... */
860 set_single_attribute(obj, NPF_HOURS,
861 pdb_get_hours(sampass),
862 pdb_get_hours_len(sampass)-1, 0);
865 return need_to_modify;
868 /***************************************************************
869 calls nis_list, returns results.
870 ****************************************************************/
871 static nis_result *nisp_get_nis_list(const char *nis_name, uint_t flags)
877 flags = FOLLOW_LINKS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP;
879 for(i = 0; i<2;i++ ) {
880 alarm(60); /* hopefully ok for long searches */
881 result = nis_list(nis_name, flags,NULL,NULL);
884 CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
888 DEBUG(0,("NIS+ lookup time out\n"));
889 nis_freeresult(result);
892 if( !(flags & MASTER_ONLY) && NIS_RES_NUMOBJ(result) <= 0 ) {
893 /* nis replicas are not in sync perhaps?
894 * this can happen, if account was just added.
896 DEBUG(10,("will try master only\n"));
897 nis_freeresult(result);
898 flags |= MASTER_ONLY;
905 /***************************************************************
906 Start to enumerate the nisplus passwd list.
907 ****************************************************************/
908 BOOL pdb_setsampwent(BOOL update)
910 char *sp, * p = lp_smb_passwd_file();
913 if( (sp = strrchr( p, '/' )) )
914 safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
916 safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
917 safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
919 pdb_endsampwent(); /* just in case */
920 global_nisp_ent.result = nisp_get_nis_list( pfiletmp, 0 );
921 global_nisp_ent.enum_entry = 0;
922 return global_nisp_ent.result != NULL ? True : False;
925 /***************************************************************
926 End enumeration of the nisplus passwd list.
927 ****************************************************************/
928 void pdb_endsampwent(void)
930 if( global_nisp_ent.result )
931 nis_freeresult(global_nisp_ent.result);
932 global_nisp_ent.result = NULL;
933 global_nisp_ent.enum_entry = 0;
936 /*************************************************************************
937 Routine to return the next entry in the nisplus passwd list.
938 *************************************************************************/
939 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
941 int enum_entry = (int)(global_nisp_ent.enum_entry);
942 nis_result *result = global_nisp_ent.result;
945 DEBUG(0,("SAM_ACCOUNT is NULL.\n"));
949 if (result == NULL ||
950 enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ(result) - 1))
955 if(!make_sam_from_nisp_object(user, &NIS_RES_OBJECT(result)[enum_entry]) )
957 DEBUG(0,("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
960 (int)(global_nisp_ent.enum_entry)++;
964 /*************************************************************************
965 Routine to search the nisplus passwd file for an entry matching the username
966 *************************************************************************/
967 BOOL pdb_getsampwnam(SAM_ACCOUNT * user, const char *sname)
969 /* Static buffers we will return. */
970 nis_result *result = NULL;
973 char *pfile = lp_smb_passwd_file();
978 DEBUG(0, ("No SMB password file set\n"));
981 if( strrchr( pfile, '/') )
982 pfile = strrchr( pfile, '/') + 1;
984 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
985 DEBUG(10, ("search by nisname: %s\n", nisname));
987 /* Search the table. */
989 if(!(result = nisp_get_nis_list(nisname, 0)))
994 ret = make_sam_from_nisresult(user, result);
995 nis_freeresult(result);
1000 /*************************************************************************
1001 Routine to search the nisplus passwd file for an entry matching the username
1002 *************************************************************************/
1003 BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
1008 char *sp, *p = lp_smb_passwd_file();
1013 DEBUG(0, ("no SMB password file set\n"));
1017 if( (sp = strrchr( p, '/' )) )
1018 safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
1020 safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
1021 safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1023 nisname = make_nisname_from_user_rid(rid, pfiletmp);
1025 DEBUG(10, ("search by rid: %s\n", nisname));
1027 /* Search the table. */
1029 if(!(result = nisp_get_nis_list(nisname, 0)))
1034 ret = make_sam_from_nisresult(user, result);
1035 nis_freeresult(result);
1040 /*************************************************************************
1041 Routine to remove entry from the nisplus smbpasswd table
1042 *************************************************************************/
1043 BOOL pdb_delete_sam_account(SAM_ACCOUNT * user)
1046 char *pfile = lp_smb_passwd_file();
1048 nis_result *result, *delresult;
1053 DEBUG(0, ("no SAM_ACCOUNT specified!\n"));
1057 suser = pdb_get_username(user);
1061 DEBUG(0, ("no SMB password file set\n"));
1064 if( strrchr( pfile, '/') )
1065 pfile = strrchr( pfile, '/') + 1;
1067 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
1069 /* Search the table. */
1071 if( !(result = nisp_get_nis_list(nisname,
1072 MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
1073 EXPAND_NAME|HARD_LOOKUP))) {
1077 if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
1078 /* User not found. */
1079 DEBUG(0,("user not found in NIS+\n"));
1080 nis_freeresult(result);
1084 obj = NIS_RES_OBJECT(result);
1085 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s", sname, obj->zo_name,
1088 DEBUG(10, ("removing name: %s\n", nisname));
1089 delresult = nis_remove_entry(nisname, obj,
1090 MASTER_ONLY|REM_MULTIPLE|ALL_RESULTS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
1092 nis_freeresult(result);
1094 if(delresult->status != NIS_SUCCESS) {
1095 DEBUG(0, ("NIS+ table update failed: %s %s\n",
1096 nisname, nis_sperrno(delresult->status)));
1097 nis_freeresult(delresult);
1100 nis_freeresult(delresult);
1104 /************************************************************************
1105 Routine to add an entry to the nisplus passwd file.
1106 *************************************************************************/
1107 BOOL pdb_add_sam_account(SAM_ACCOUNT * newpwd)
1113 nis_result *result = NULL,
1120 * 1. find user domain.
1121 * a. try nis search in passwd.org_dir - if found use domain from result.
1122 * b. try getpwnam. this may be needed if user is defined
1123 * in /etc/passwd file (or elsewere) and not in passwd.org_dir.
1124 * if found, use host default domain.
1125 * c. exit with False - no such user.
1128 * a. find smbpasswd table
1129 * search pfile in user domain if not found, try host default
1131 * b. smbpasswd domain is found, fill data and add entry.
1133 * pfile should contain ONLY table name, org_dir will be concated.
1134 * so, at first we will clear path prefix from pfile, and
1135 * then we will use pfiletmp as playground to put together full
1137 * such approach will make it possible to specify samba private dir
1138 * AND still use NIS+ table. as all domain related data is normally
1139 * stored in org_dir.DOMAIN, this should be ok do do.
1142 pfile = lp_smb_passwd_file();
1143 if( strrchr( pfile, '/') )
1144 pfile = strrchr( pfile, '/') + 1;
1147 * Check if user is already there.
1149 safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1150 safe_strcat(pfiletmp, ".org_dir",
1151 sizeof(pfiletmp)-strlen(pfiletmp)-1);
1153 if(pdb_get_username(newpwd) != NULL) {
1154 nisname = make_nisname_from_name(pdb_get_username(newpwd),
1160 if(!(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
1161 FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
1164 if (result->status != NIS_SUCCESS &&
1165 result->status != NIS_NOTFOUND) {
1166 DEBUG(3, ( "nis_list failure: %s: %s\n",
1167 nisname, nis_sperrno(result->status)));
1168 nis_freeresult(result);
1172 if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
1174 DEBUG(3, ("User already exists in NIS+ password db: %s\n",
1176 nis_freeresult(result);
1180 nis_freeresult(result); /* no such user, free results */
1183 * check for user in unix password database. we need this to get
1184 * domain, where smbpasswd entry should be stored.
1187 nisname = make_nisname_from_name(pdb_get_username(newpwd),
1190 result = nisp_get_nis_list(nisname,
1191 MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
1192 EXPAND_NAME|HARD_LOOKUP);
1194 if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0)
1196 struct passwd *passwd;
1197 DEBUG(3, ("nis_list failure: %s: %s\n",
1198 nisname, nis_sperrno(result->status)));
1199 nis_freeresult(result);
1201 if (!passwd = getpwnam_alloc(pdb_get_username(newpwd))) {
1202 /* no such user in system! */
1205 passwd_free(&passwd);
1208 * user is defined, but not in passwd.org_dir.
1212 safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1213 safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1214 safe_strcat(pfiletmp, NIS_RES_OBJECT(result)->zo_domain,
1215 sizeof(pfiletmp)-strlen(pfiletmp)-1);
1216 nis_freeresult(result); /* not needed any more */
1218 tblresult = nisp_get_nis_list(pfiletmp,
1219 MASTER_ONLY|FOLLOW_LINKS|\
1220 FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
1223 if (local_user || tblresult->status != NIS_SUCCESS)
1227 * smbpasswd table not found in user domain, fallback to
1230 if (!local_user) /* free previous failed search result */
1231 nis_freeresult(tblresult);
1233 safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1234 safe_strcat(pfiletmp, ".org_dir",
1235 sizeof(pfiletmp)-strlen(pfiletmp)-1);
1236 tblresult = nis_lookup(pfiletmp, MASTER_ONLY|FOLLOW_LINKS|\
1237 FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
1238 if (tblresult->status != NIS_SUCCESS)
1240 /* still nothing. bail out */
1241 nis_freeresult(tblresult);
1242 DEBUG(3, ( "nis_lookup failure: %s\n",
1243 nis_sperrno(tblresult->status)));
1246 /* we need full name for nis_add_entry() */
1247 safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1248 safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1249 safe_strcat(pfiletmp, NIS_RES_OBJECT(tblresult)->zo_domain,
1250 sizeof(pfiletmp)-strlen(pfiletmp)-1);
1253 memset((char *)&new_obj, 0, sizeof (new_obj));
1254 /* fill entry headers */
1255 /* we do not free these. */
1256 new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
1257 new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
1258 new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
1259 new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
1261 new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
1262 new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
1264 new_obj.zo_data.zo_type = ENTRY_OBJ;
1265 new_obj.EN_data.en_type =
1266 NIS_RES_OBJECT(tblresult)->TA_data.ta_type;
1268 ta_maxcol = NIS_RES_OBJECT(tblresult)->TA_data.ta_maxcol;
1270 if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
1271 DEBUG(0, ("memory allocation failure\n"));
1272 nis_freeresult(tblresult);
1276 memset((char *)ecol, 0, ta_maxcol*sizeof (entry_col));
1277 new_obj.EN_data.en_cols.en_cols_val = ecol;
1278 new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
1280 init_nisp_from_sam(&new_obj, newpwd, NULL);
1282 DEBUG(10, ( "add NIS+ entry: %s\n", nisname));
1283 result = nis_add_entry(pfiletmp, &new_obj, 0);
1285 free(ecol); /* free allocated entry space */
1287 if (result->status != NIS_SUCCESS)
1289 DEBUG(3, ( "NIS+ table update failed: %s\n",
1290 nisname, nis_sperrno(result->status)));
1291 nis_freeresult(tblresult);
1292 nis_freeresult(result);
1296 nis_freeresult(tblresult);
1297 nis_freeresult(result);
1302 /************************************************************************
1303 Routine to modify the nisplus passwd entry.
1304 ************************************************************************/
1305 BOOL pdb_update_sam_account(SAM_ACCOUNT * newpwd)
1307 nis_result *result, *addresult;
1312 char *pfile = lp_smb_passwd_file();
1318 DEBUG(0, ("no SMB password file set\n"));
1321 if( strrchr( pfile, '/') )
1322 pfile = strrchr( pfile, '/') + 1;
1324 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir",
1325 pdb_get_username(newpwd), pfile);
1327 DEBUG(10, ("search by name: %s\n", nisname));
1329 /* Search the table. */
1331 if( !(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
1332 FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
1336 if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
1337 /* User not found. */
1338 DEBUG(0,("user not found in NIS+\n"));
1339 nis_freeresult(result);
1343 obj = NIS_RES_OBJECT(result);
1344 DEBUG(6,("entry found in %s\n", obj->zo_domain));
1346 /* we must create new stub object with EN_MODIFIED flag.
1347 this is because obj from result is going to be freed and
1348 we do not want to break it or cause memory leaks or corruption.
1351 memmove((char *)&new_obj, obj, sizeof (new_obj));
1352 ta_maxcol = obj->TA_data.ta_maxcol;
1354 if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
1355 DEBUG(0, ("memory allocation failure\n"));
1356 nis_freeresult(result);
1360 memmove((char *)ecol, obj->EN_data.en_cols.en_cols_val,
1361 ta_maxcol*sizeof (entry_col));
1362 new_obj.EN_data.en_cols.en_cols_val = ecol;
1363 new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
1365 if ( init_nisp_from_sam(&new_obj, newpwd, obj) == True ) {
1366 slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s",
1367 pdb_get_username(newpwd), pfile, obj->zo_domain);
1369 DEBUG(10, ("NIS+ table update: %s\n", nisname));
1371 nis_modify_entry(nisname, &new_obj,
1372 MOD_SAMEOBJ | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
1374 if(addresult->status != NIS_SUCCESS) {
1375 DEBUG(0, ("NIS+ table update failed: %s %s\n",
1376 nisname, nis_sperrno(addresult->status)));
1377 nis_freeresult(addresult);
1378 nis_freeresult(result);
1383 DEBUG(6,("password changed\n"));
1384 nis_freeresult(addresult);
1386 DEBUG(6,("nothing to change!\n"));
1390 nis_freeresult(result);
1396 void nisplus_dummy_function(void);
1397 void nisplus_dummy_function(void) { } /* stop some compilers complaining */
1398 #endif /* WITH_NISPLUSSAM */