added mapping of primary gid to rid thru the group mapping code.
[amitay/samba.git] / source3 / passdb / pdb_nisplus.c
1 /*
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.
6  * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
7  * 
8  * This program is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  * 
18  * You should have received a copy of the GNU General Public License along with
19  * this program; if not, write to the Free Software Foundation, Inc., 675
20  * Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include "includes.h"
24
25 #ifdef WITH_NISPLUS_SAM
26
27 #ifdef BROKEN_NISPLUS_INCLUDE_FILES
28
29 /*
30  * The following lines are needed due to buggy include files
31  * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
32  * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
33  * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
34  * an enum in /usr/include/rpcsvc/nis.h.
35  */
36
37 #if defined(GROUP)
38 #undef GROUP
39 #endif
40
41 #if defined(GROUP_OBJ)
42 #undef GROUP_OBJ
43 #endif
44
45 #endif
46
47 #include <rpcsvc/nis.h>
48
49 extern int      DEBUGLEVEL;
50 extern pstring  samlogon_user;
51 extern BOOL     sam_logon_in_ssb;
52
53 struct nisp_enum_info
54 {
55         nis_result *result;
56         int enum_entry;
57 };
58
59 static struct nisp_enum_info global_nisp_ent;
60 static VOLATILE sig_atomic_t gotalarm;
61
62 /***************************************************************
63
64  the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
65
66         name=S,nogw=r 
67         uid=S,nogw=r 
68                 user_rid=S,nogw=r
69                 smb_grpid=,nw+r
70                 group_rid=,nw+r
71                 acb=,nw+r
72                           
73         lmpwd=C,nw=,g=r,o=rm 
74         ntpwd=C,nw=,g=r,o=rm 
75                                      
76                 logon_t=,nw+r 
77                 logoff_t=,nw+r 
78                 kick_t=,nw+r 
79                 pwdlset_t=,nw+r 
80                 pwdlchg_t=,nw+r 
81                 pwdmchg_t=,nw+r 
82                                 
83                 full_name=,nw+r 
84                 home_dir=,nw+r 
85                 dir_drive=,nw+r 
86                 logon_script=,nw+r 
87                 profile_path=,nw+r 
88                 acct_desc=,nw+r 
89                 workstations=,nw+r 
90                                    
91                 hours=,nw+r 
92
93 ****************************************************************/
94
95 #define NPF_NAME          0
96 #define NPF_UID           1
97 #define NPF_USER_RID      2
98 #define NPF_SMB_GRPID     3
99 #define NPF_GROUP_RID     4
100 #define NPF_ACB           5
101 #define NPF_LMPWD         6
102 #define NPF_NTPWD         7
103 #define NPF_LOGON_T       8
104 #define NPF_LOGOFF_T      9
105 #define NPF_KICK_T        10
106 #define NPF_PWDLSET_T     11
107 #define NPF_PWDCCHG_T     12
108 #define NPF_PWDMCHG_T     13
109 #define NPF_FULL_NAME     14
110 #define NPF_HOME_DIR      15
111 #define NPF_DIR_DRIVE     16
112 #define NPF_LOGON_SCRIPT  17
113 #define NPF_PROFILE_PATH  18
114 #define NPF_ACCT_DESC     19
115 #define NPF_WORKSTATIONS  20
116 #define NPF_HOURS         21
117
118 /***************************************************************
119  Signal function to tell us we timed out.
120 ****************************************************************/
121 static void gotalarm_sig(void)
122 {
123   gotalarm = 1;
124 }
125
126 /***************************************************************
127  make_nisname_from_user_rid
128  ****************************************************************/
129 static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
130 {
131         static pstring nisname;
132
133         safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
134         slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
135         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
136         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
137
138         return nisname;
139 }
140
141 /***************************************************************
142  make_nisname_from_uid
143  ****************************************************************/
144 static char *make_nisname_from_uid(int uid, char *pfile)
145 {
146         static pstring nisname;
147
148         safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
149         slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
150         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
151         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
152
153         return nisname;
154 }
155
156 /***************************************************************
157  make_nisname_from_name
158  ****************************************************************/
159 static char *make_nisname_from_name(const char *user_name, char *pfile)
160 {
161         static pstring nisname;
162
163         safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
164         safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
165         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
166         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
167
168         return nisname;
169 }
170
171 /*************************************************************************
172  gets a NIS+ attribute
173  *************************************************************************/
174 static void get_single_attribute(const nis_object *new_obj, int col,
175                                 char *val, int len)
176 {
177         int entry_len;
178
179         if (new_obj == NULL || val == NULL) return;
180         
181         entry_len = ENTRY_LEN(new_obj, col);
182         if (len > entry_len)
183         {
184                 len = entry_len;
185         }
186
187         safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
188 }
189
190 /************************************************************************
191  makes a struct sam_passwd from a NIS+ object.
192  ************************************************************************/
193 static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, const nis_object *obj)
194 {
195   char *ptr;
196   pstring full_name;    /* this must be translated to dos code page */
197   pstring acct_desc;    /* this must be translated to dos code page */
198   pstring home_dir;     /* set default value from smb.conf for user */
199   pstring home_drive;   /* set default value from smb.conf for user */
200   pstring logon_script; /* set default value from smb.conf for user */
201   pstring profile_path; /* set default value from smb.conf for user */
202   pstring hours;
203   int hours_len;
204   unsigned char smbpwd[16];
205   unsigned char smbntpwd[16];
206   
207
208   /*
209    * time values. note: this code assumes 32bit time_t!
210    */
211
212   /* Don't change these timestamp settings without a good reason.  They are
213      important for NT member server compatibility. */
214
215   pdb_set_logon_time(pw_buf, (time_t)0);
216   ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGON_T);
217   if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
218     int i;
219     ptr += 4;
220     for(i = 0; i < 8; i++) {
221       if(ptr[i] == '\0' || !isxdigit(ptr[i]))
222         break;
223     }
224     if(i == 8) {
225       pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
226     }
227   }
228
229   pdb_set_logoff_time(pw_buf, get_time_t_max());
230   ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGOFF_T);
231   if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
232     int i;
233     ptr += 4;
234     for(i = 0; i < 8; i++) {
235       if(ptr[i] == '\0' || !isxdigit(ptr[i]))
236         break;
237     }
238     if(i == 8) {
239       pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
240     }
241   }
242
243   pdb_set_kickoff_time(pw_buf, get_time_t_max());
244   ptr = (uchar *)ENTRY_VAL(obj, NPF_KICK_T);
245   if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
246     int i;
247     ptr += 4;
248     for(i = 0; i < 8; i++) {
249       if(ptr[i] == '\0' || !isxdigit(ptr[i]))
250         break;
251     }
252     if(i == 8) {
253       pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
254     }
255   }
256
257   pdb_set_pass_last_set_time(pw_buf, (time_t)0);
258   ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDLSET_T);
259   if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
260     int i;
261     ptr += 4;
262     for(i = 0; i < 8; i++) {
263       if(ptr[i] == '\0' || !isxdigit(ptr[i]))
264         break;
265     }
266     if(i == 8) {
267       pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
268     }
269   }
270   
271   pdb_set_pass_can_change_time(pw_buf, (time_t)0);
272   ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDCCHG_T);
273   if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
274     int i;
275     ptr += 4;
276     for(i = 0; i < 8; i++) {
277       if(ptr[i] == '\0' || !isxdigit(ptr[i]))
278         break;
279     }
280     if(i == 8) {
281       pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
282     }
283   }
284   
285   pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* Password never expires. */
286   ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDMCHG_T);
287   if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
288     int i;
289     ptr += 4;
290     for(i = 0; i < 8; i++) {
291       if(ptr[i] == '\0' || !isxdigit(ptr[i]))
292         break;
293     }
294     if(i == 8) {
295       pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
296     }
297   }
298
299   /* string values */
300   pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
301   pdb_set_domain(pw_buf, lp_workgroup());
302   /* pdb_set_nt_username() -- cant set it here... */
303
304   get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
305   unix_to_dos(full_name, True);
306   pdb_set_fullname(pw_buf, full_name);
307
308   pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
309                                                            NPF_ACB)));
310
311   get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
312   unix_to_dos(acct_desc, True);
313   pdb_set_acct_desc(pw_buf, acct_desc);
314
315   pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
316   pdb_set_munged_dial(pw_buf, NULL);
317
318   pdb_set_uid(pw_buf, &atoi(ENTRY_VAL(obj, NPF_UID)));
319   pdb_set_gid(pw_buf, &atoi(ENTRY_VAL(obj, NPF_SMB_GRPID)));
320   pdb_set_user_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_USER_RID)));
321   pdb_set_group_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_GROUP_RID)));
322
323   /* values, must exist for user */
324   if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
325     /* FIXME!!  This doesn't belong here. 
326        Should be set in net_sam_logon() 
327        --jerry */
328     pstrcpy(samlogon_user, pdb_get_username(pw_buf));
329     
330     get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
331     if( !(home_dir && *home_dir) )
332       pstrcpy(home_dir, lp_logon_home());
333     pdb_set_homedir(pw_buf, home_dir);
334
335     get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
336     if( !(home_drive && *home_drive) )
337       pstrcpy(home_drive, lp_logon_drive());
338     pdb_set_dir_drive(pw_buf, home_drive);
339
340     get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
341                          sizeof(pstring));
342     if( !(logon_script && *logon_script) )
343       pstrcpy(logon_script, lp_logon_script());
344     pdb_set_logon_script(pw_buf, logon_script);
345
346     get_single_attribute(obj, NPF_PROFILE_PATH, profile_path,
347                          sizeof(pstring));
348     if( !(profile_path && *profile_path) )
349       pstrcpy(profile_path, lp_logon_path());
350     pdb_set_profile_path(pw_buf, profile_path);
351   } else {
352     /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
353     pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS); 
354   }
355
356   /* Check the lanman password column. */
357   ptr = (char *)ENTRY_VAL(obj, NPF_LMPWD);
358   pdb_set_lanman_passwd(pw_buf, NULL);
359
360   if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
361     pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
362   } else {
363     if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
364       DEBUG(0, ("malformed LM pwd entry: %s.\n",
365                 pdb_get_username(pw_buf)));
366       return False;
367     } 
368     pdb_set_lanman_passwd(pw_buf, smbpwd);
369   }
370   
371   /* Check the NT password column. */
372   ptr = ENTRY_VAL(obj, NPF_NTPWD);
373   pdb_set_nt_passwd(pw_buf, NULL);
374   
375   if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
376       strncasecmp(ptr, "NO PASSWORD", 11)) {
377     if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
378       DEBUG(0, ("malformed NT pwd entry: uid = %d.\n",
379                 pdb_get_uid(pw_buf)));
380       return False;
381     }
382     pdb_set_nt_passwd(pw_buf, smbntpwd);
383   }
384   
385   pdb_set_unknown_3(pw_buf, 0xffffff); /* don't know */
386   pdb_set_logons_divs(pw_buf, 168);     /* hours per week */
387                       
388                       if( (hours_len = ENTRY_LEN(obj, NPF_HOURS)) == 21 ) {
389     memcpy(hours, ENTRY_VAL(obj, NPF_HOURS), hours_len);
390   } else {
391     hours_len = 21; /* 21 times 8 bits = 168 */
392     /* available at all hours */
393     memset(hours, 0xff, hours_len);
394   }
395   pdb_set_hours_len(pw_buf, hours_len);
396   pdb_set_hours(pw_buf, hours);
397
398   pdb_set_unknown_5(pw_buf, 0x00020000); /* don't know */
399   pdb_set_unknown_6(pw_buf, 0x000004ec); /* don't know */
400
401   return True;
402 }
403
404 /************************************************************************
405  makes a struct sam_passwd from a NIS+ result.
406  ************************************************************************/
407 static BOOL make_sam_from_nisresult(SAM_ACCOUNT *pw_buf, const nis_result *result)
408 {
409         if (pw_buf == NULL || result == NULL) return False;
410
411         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
412         {
413                 DEBUG(0, ("NIS+ lookup failure: %s\n",
414                            nis_sperrno(result->status)));
415                 return False;
416         }
417
418         /* User not found. */
419         if (NIS_RES_NUMOBJ(result) <= 0)
420         {
421                 DEBUG(10, ("user not found in NIS+\n"));
422                 return False;
423         }
424
425         if (NIS_RES_NUMOBJ(result) > 1)
426         {
427                 DEBUG(10, ("WARNING: Multiple entries for user in NIS+ table!\n"));
428         }
429
430         /* Grab the first hit. */
431         return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
432 }
433
434 /*************************************************************************
435  sets a NIS+ attribute
436  *************************************************************************/
437 static void set_single_attribute(nis_object *new_obj, int col,
438                                 const char *val, int len, int flags)
439 {
440         if (new_obj == NULL) return;
441
442         ENTRY_VAL(new_obj, col) = val;
443         ENTRY_LEN(new_obj, col) = len+1;
444
445         if (flags != 0)
446         {
447                 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
448         }
449 }
450
451 /***************************************************************
452  copy or modify nis object. this object is used to add or update
453  nisplus table entry.
454  ****************************************************************/
455 static BOOL init_nisp_from_sam(nis_object *obj, const SAM_ACCOUNT *sampass,
456                                nis_object *old)
457 {
458   /*
459    * Fill nis_object for entry add or update.
460    * if we are updateing, we have to find out differences and set
461    * EN_MODIFIED flag. also set need_to_modify to trigger
462    * nis_modify_entry() call in pdb_update_sam_account().
463    *
464    * TODO:
465    *   get data from SAM
466    *   if (modify) get data from nis_object, compare and store if
467    *               different + set EN_MODIFIED and need_to_modify
468    *   else
469    *               store
470    */
471   BOOL need_to_modify = False;
472   const char *name = pdb_get_username(sampass);       /* from SAM */
473   /* these must be static or allocate and free entry columns! */
474   static fstring uid;                     /* from SAM */
475   static fstring user_rid;                /* from SAM */
476   static fstring gid;                     /* from SAM */
477   static fstring group_rid;               /* from SAM */
478   char *acb;                       /* from SAM */
479   static fstring smb_passwd;              /* from SAM */
480   static fstring smb_nt_passwd;           /* from SAM */
481   static fstring logon_t;                 /* from SAM */
482   static fstring logoff_t;                /* from SAM */
483   static fstring kickoff_t;               /* from SAM */
484   static fstring pwdlset_t;               /* from SAM */
485   static fstring pwdlchg_t;               /* from SAM */
486   static fstring pwdmchg_t;               /* from SAM */
487   static fstring full_name;               /* from SAM */
488   static fstring acct_desc;               /* from SAM */
489   static char empty[1];                   /* just an empty string */
490
491   slprintf(uid, sizeof(uid)-1, "%u", pdb_get_uid(sampass));
492   slprintf(user_rid, sizeof(user_rid)-1, "%u",
493            pdb_get_user_rid(sampass)? pdb_get_user_rid(sampass):
494            pdb_uid_to_user_rid(pdb_get_uid(sampass))); 
495   slprintf(gid, sizeof(gid)-1, "%u", pdb_get_gid(sampass));
496
497         {
498                 uint32 rid;
499                 GROUP_MAP map;
500         
501                 rid=pdb_get_group_rid(sampass);
502
503                 if (rid==0) {
504                         if (get_group_map_from_gid(pdb_get_gid(sampass), &map)) {
505                                 free_privilege(&map.priv_set);
506                                 sid_peek_rid(&map.sid, &rid);
507                         } else 
508                                 rid=pdb_gid_to_group_rid(pdb_get_gid(sampass));
509                 }
510
511                 slprintf(group_rid, sizeof(group_rid)-1, "%u", rid);
512         }
513          
514   acb = pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sampass),
515                              NEW_PW_FORMAT_SPACE_PADDED_LEN);
516   pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd(sampass),
517                  pdb_get_acct_ctrl(sampass));
518   pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd(sampass),
519                  pdb_get_acct_ctrl(sampass));
520   slprintf(logon_t, 13, "LNT-%08X",
521            (uint32)pdb_get_logon_time(sampass));
522   slprintf(logoff_t, 13, "LOT-%08X",
523            (uint32)pdb_get_logoff_time(sampass));
524   slprintf(kickoff_t, 13, "KOT-%08X",
525            (uint32)pdb_get_kickoff_time(sampass));
526   slprintf(pwdlset_t, 13, "LCT-%08X",
527            (uint32)pdb_get_pass_last_set_time(sampass));
528   slprintf(pwdlchg_t, 13, "CCT-%08X",
529            (uint32)pdb_get_pass_can_change_time(sampass));
530   slprintf(pwdmchg_t, 13, "MCT-%08X",
531            (uint32)pdb_get_pass_must_change_time(sampass));
532   safe_strcpy(full_name, pdb_get_fullname(sampass), sizeof(full_name)-1);
533   dos_to_unix(full_name, True);
534   safe_strcpy(acct_desc, pdb_get_acct_desc(sampass), sizeof(acct_desc)-1);
535   dos_to_unix(acct_desc, True);
536   
537   if( old ) {
538     /* name */
539     if(strcmp(ENTRY_VAL(old, NPF_NAME), name))
540       {
541         need_to_modify = True;
542         set_single_attribute(obj, NPF_NAME, name, strlen(name),
543                              EN_MODIFIED);
544       }
545
546
547     /* uid */
548     if(pdb_get_uid(sampass) != -1) {
549       if(!ENTRY_VAL(old, NPF_UID) || strcmp(ENTRY_VAL(old, NPF_UID), uid)) 
550         {
551           need_to_modify = True;
552           set_single_attribute(obj, NPF_UID, uid,
553                                strlen(uid), EN_MODIFIED);
554         }
555     }
556       
557     /* user_rid */
558     if (pdb_get_user_rid(sampass)) {
559       if(!ENTRY_VAL(old, NPF_USER_RID) ||
560          strcmp(ENTRY_VAL(old, NPF_USER_RID), user_rid) ) {
561         need_to_modify = True;
562         set_single_attribute(obj, NPF_USER_RID, user_rid,
563                              strlen(user_rid), EN_MODIFIED);
564       }
565     }
566     
567     /* smb_grpid */
568     if (pdb_get_gid(sampass) != -1) {
569       if(!ENTRY_VAL(old, NPF_SMB_GRPID) ||
570          strcmp(ENTRY_VAL(old, NPF_SMB_GRPID), gid) ) {
571         need_to_modify = True;
572         set_single_attribute(obj, NPF_SMB_GRPID, gid,
573                              strlen(gid), EN_MODIFIED);
574       }
575     }
576
577     /* group_rid */
578     if (pdb_get_group_rid(sampass)) {
579       if(!ENTRY_VAL(old, NPF_GROUP_RID) ||
580          strcmp(ENTRY_VAL(old, NPF_GROUP_RID), group_rid) ) {
581         need_to_modify = True;
582         set_single_attribute(obj, NPF_GROUP_RID, group_rid,
583                              strlen(group_rid), EN_MODIFIED);
584       }
585     }
586
587     /* acb */
588     if (!ENTRY_VAL(old, NPF_ACB) || 
589         strcmp(ENTRY_VAL(old, NPF_ACB), acb)) {
590       need_to_modify = True;
591       set_single_attribute(obj, NPF_ACB, acb, strlen(acb), EN_MODIFIED);
592     }
593     
594     /* lmpwd */
595     if(!ENTRY_VAL(old, NPF_LMPWD) || 
596        strcmp(ENTRY_VAL(old, NPF_LMPWD), smb_passwd) ) {
597       need_to_modify = True;
598       set_single_attribute(obj, NPF_LMPWD, smb_passwd,
599                            strlen(smb_passwd), EN_CRYPT|EN_MODIFIED);
600     }
601
602     /* ntpwd */
603     if(!ENTRY_VAL(old, NPF_NTPWD) ||
604        strcmp(ENTRY_VAL(old, NPF_NTPWD), smb_nt_passwd) ) {
605       need_to_modify = True;
606       set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
607                            strlen(smb_nt_passwd), EN_CRYPT|EN_MODIFIED);
608     }
609
610     /* logon_t */
611     if( pdb_get_logon_time(sampass) && 
612         (!ENTRY_VAL(old, NPF_LOGON_T) ||
613          strcmp(ENTRY_VAL(old, NPF_LOGON_T), logon_t ))) {
614       need_to_modify = True;
615       set_single_attribute(obj, NPF_LOGON_T, logon_t,
616                            strlen(logon_t), EN_MODIFIED);
617     }
618
619     /* logoff_t */
620     if( pdb_get_logoff_time(sampass) && 
621         (!ENTRY_VAL(old, NPF_LOGOFF_T) ||
622          strcmp(ENTRY_VAL(old, NPF_LOGOFF_T), logoff_t))) {
623       need_to_modify = True;
624       set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
625                            strlen(logoff_t), EN_MODIFIED);
626     }
627
628     /* kick_t */
629     if( pdb_get_kickoff_time(sampass) &&
630         (!ENTRY_VAL(old, NPF_KICK_T) ||
631          strcmp(ENTRY_VAL(old, NPF_KICK_T), kickoff_t))) {
632       need_to_modify = True;
633       set_single_attribute(obj, NPF_KICK_T, kickoff_t,
634                            strlen(kickoff_t), EN_MODIFIED);
635     }
636     
637     /* pwdlset_t */
638     if( pdb_get_pass_last_set_time(sampass) &&
639         (!ENTRY_VAL(old, NPF_PWDLSET_T) ||
640          strcmp(ENTRY_VAL(old, NPF_PWDLSET_T), pwdlset_t))) {
641       need_to_modify = True;
642       set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
643                            strlen(pwdlset_t), EN_MODIFIED);
644     }
645
646     /* pwdlchg_t */
647     if( pdb_get_pass_can_change_time(sampass) &&
648         (!ENTRY_VAL(old, NPF_PWDCCHG_T) ||
649          strcmp(ENTRY_VAL(old, NPF_PWDCCHG_T), pwdlchg_t))) {
650       need_to_modify = True;
651       set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
652                            strlen(pwdlchg_t), EN_MODIFIED);
653     }
654
655     /* pwdmchg_t */
656     if( pdb_get_pass_must_change_time(sampass) &&
657         (!ENTRY_VAL(old, NPF_PWDMCHG_T) ||
658          strcmp(ENTRY_VAL(old, NPF_PWDMCHG_T), pwdmchg_t))) {
659       need_to_modify = True;
660       set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
661                            strlen(pwdmchg_t), EN_MODIFIED);
662     }
663     
664     /* full_name */
665     /* must support set, unset and change */
666     if ( (pdb_get_fullname(sampass) &&
667           !ENTRY_VAL(old, NPF_FULL_NAME)) ||
668          (ENTRY_VAL(old, NPF_FULL_NAME) &&
669           !pdb_get_fullname(sampass))  ||
670          (ENTRY_VAL(old, NPF_FULL_NAME) &&
671           pdb_get_fullname(sampass) && 
672           strcmp( ENTRY_VAL(old, NPF_FULL_NAME), full_name ))) {
673       need_to_modify = True;
674       set_single_attribute(obj, NPF_FULL_NAME, full_name,
675                            strlen(full_name), EN_MODIFIED);
676     }
677     
678     /* home_dir */
679     /* must support set, unset and change */
680     if( (pdb_get_homedir(sampass) && 
681          !ENTRY_VAL(old, NPF_HOME_DIR)) ||
682         (ENTRY_VAL(old, NPF_HOME_DIR) && 
683          !pdb_get_homedir(sampass)) ||
684         (ENTRY_VAL(old, NPF_HOME_DIR) && 
685          pdb_get_homedir(sampass) &&
686          strcmp( ENTRY_VAL(old, NPF_HOME_DIR),
687                  pdb_get_homedir(sampass)))) {
688       need_to_modify = True;
689       set_single_attribute(obj, NPF_HOME_DIR, pdb_get_homedir(sampass),
690                            strlen(pdb_get_homedir(sampass)), EN_MODIFIED);
691     }
692     
693     /* dir_drive */
694     /* must support set, unset and change */
695     if( (pdb_get_dirdrive(sampass) && 
696          !ENTRY_VAL(old, NPF_DIR_DRIVE)) ||
697         (ENTRY_VAL(old, NPF_DIR_DRIVE) && 
698          !pdb_get_dirdrive(sampass)) ||
699         (ENTRY_VAL(old, NPF_DIR_DRIVE) && 
700          pdb_get_dirdrive(sampass) &&
701          strcmp( ENTRY_VAL(old, NPF_DIR_DRIVE),
702                  pdb_get_dirdrive(sampass)))) {
703       need_to_modify = True;
704       set_single_attribute(obj, NPF_DIR_DRIVE, pdb_get_dirdrive(sampass),
705                            strlen(pdb_get_dirdrive(sampass)), EN_MODIFIED);
706     }
707     
708     /* logon_script */
709     /* must support set, unset and change */
710     if( (pdb_get_logon_script(sampass) && 
711          !ENTRY_VAL(old, NPF_LOGON_SCRIPT) ||
712          (ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
713           !pdb_get_logon_script(sampass)) ||
714          ( ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
715            pdb_get_logon_script(sampass) &&
716            strcmp( ENTRY_VAL(old, NPF_LOGON_SCRIPT),
717                    pdb_get_logon_script(sampass))))) {
718       need_to_modify = True;
719       set_single_attribute(obj, NPF_LOGON_SCRIPT,
720                            pdb_get_logon_script(sampass),
721                            strlen(pdb_get_logon_script(sampass)),
722                            EN_MODIFIED);
723     }
724     
725     /* profile_path */
726     /* must support set, unset and change */
727     if( (pdb_get_profile_path(sampass) && 
728          !ENTRY_VAL(old, NPF_PROFILE_PATH)) || 
729         (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
730          !pdb_get_profile_path(sampass)) ||
731         (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
732          pdb_get_profile_path(sampass) &&
733          strcmp( ENTRY_VAL(old, NPF_PROFILE_PATH),
734                  pdb_get_profile_path(sampass) ) )) {
735       need_to_modify = True;
736       set_single_attribute(obj, NPF_PROFILE_PATH,
737                            pdb_get_profile_path(sampass),
738                            strlen(pdb_get_profile_path(sampass)),
739                            EN_MODIFIED);
740     }
741     
742     /* acct_desc */
743     /* must support set, unset and change */
744     if( (pdb_get_acct_desc(sampass) &&
745          !ENTRY_VAL(old, NPF_ACCT_DESC)) || 
746         (ENTRY_VAL(old, NPF_ACCT_DESC) && 
747          !pdb_get_acct_desc(sampass)) ||
748         (ENTRY_VAL(old, NPF_ACCT_DESC) && 
749          pdb_get_acct_desc(sampass) &&
750          strcmp( ENTRY_VAL(old, NPF_ACCT_DESC), acct_desc ) )) {
751       need_to_modify = True;
752       set_single_attribute(obj, NPF_ACCT_DESC, acct_desc,
753                            strlen(acct_desc), EN_MODIFIED);
754     }
755
756     /* workstations */
757     /* must support set, unset and change */
758     if ( (pdb_get_workstations(sampass) &&
759           !ENTRY_VAL(old, NPF_WORKSTATIONS) ) ||
760          (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
761           !pdb_get_workstations(sampass)) ||
762          (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
763           pdb_get_workstations(sampass)) &&
764          strcmp( ENTRY_VAL(old, NPF_WORKSTATIONS), 
765                  pdb_get_workstations(sampass))) {
766       need_to_modify = True;
767       set_single_attribute(obj, NPF_WORKSTATIONS,
768                            pdb_get_workstations(sampass),
769                            strlen(pdb_get_workstations(sampass)),
770                            EN_MODIFIED);
771     }
772     
773     /* hours */
774     if ((pdb_get_hours_len(sampass) != ENTRY_LEN(old, NPF_HOURS)) ||
775         memcmp(pdb_get_hours(sampass), ENTRY_VAL(old, NPF_HOURS),
776                ENTRY_LEN(old, NPF_HOURS))) {
777       need_to_modify = True;
778       /* set_single_attribute will add 1 for len ... */
779       set_single_attribute(obj, NPF_HOURS, pdb_get_hours(sampass), 
780                            pdb_get_hours_len(sampass)-1, EN_MODIFIED);
781     }  
782   } else {
783     const char *homedir, *dirdrive, *logon_script, *profile_path, *workstations;
784
785     *empty = '\0'; /* empty string */
786
787     set_single_attribute(obj, NPF_NAME, name, strlen(name), 0);
788     set_single_attribute(obj, NPF_UID, uid, strlen(uid), 0);
789     set_single_attribute(obj, NPF_USER_RID, user_rid,
790                          strlen(user_rid), 0);
791     set_single_attribute(obj, NPF_SMB_GRPID, gid, strlen(gid), 0);
792     set_single_attribute(obj, NPF_GROUP_RID, group_rid,
793                          strlen(group_rid), 0);
794     set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
795     set_single_attribute(obj, NPF_LMPWD, smb_passwd,
796                          strlen(smb_passwd), EN_CRYPT);
797     set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
798                          strlen(smb_nt_passwd), EN_CRYPT);
799     set_single_attribute(obj, NPF_LOGON_T, logon_t,
800                          strlen(logon_t), 0);
801     set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
802                          strlen(logoff_t), 0);
803     set_single_attribute(obj, NPF_KICK_T, kickoff_t,
804                          strlen(kickoff_t),0);
805     set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t, 
806                          strlen(pwdlset_t), 0);
807     set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
808                          strlen(pwdlchg_t), 0);
809     set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
810                          strlen(pwdmchg_t), 0);
811     set_single_attribute(obj, NPF_FULL_NAME     , 
812                          full_name, strlen(full_name), 0);
813
814     if(!(homedir = pdb_get_homedir(sampass)))
815       homedir = empty;
816
817     set_single_attribute(obj, NPF_HOME_DIR,
818                          homedir, strlen(homedir), 0);
819     
820     if(!(dirdrive = pdb_get_dirdrive(sampass)))
821        dirdrive = empty;
822        
823     set_single_attribute(obj, NPF_DIR_DRIVE,
824                          dirdrive, strlen(dirdrive), 0);
825     
826     if(!(logon_script = pdb_get_logon_script(sampass)))
827        logon_script = empty;
828     
829     set_single_attribute(obj, NPF_LOGON_SCRIPT,
830                          logon_script, strlen(logon_script), 0);
831     
832     if(!(profile_path = pdb_get_profile_path(sampass)))
833       profile_path = empty;
834
835     set_single_attribute(obj, NPF_PROFILE_PATH,
836                          profile_path, strlen(profile_path), 0);
837     
838     set_single_attribute(obj, NPF_ACCT_DESC,
839                          acct_desc, strlen(acct_desc), 0);
840     
841     if(!(workstations = pdb_get_workstations(sampass)))
842       workstations = empty;
843     
844     set_single_attribute(obj, NPF_WORKSTATIONS, 
845                          workstations, strlen(workstations), 0);
846     
847     /* set_single_attribute will add 1 for len ... */
848     set_single_attribute(obj, NPF_HOURS,
849                          pdb_get_hours(sampass),
850                          pdb_get_hours_len(sampass)-1, 0);
851   }
852   
853   return need_to_modify;
854 }
855
856 /***************************************************************
857  calls nis_list, returns results.
858  ****************************************************************/
859 static nis_result *nisp_get_nis_list(const char *nis_name, uint_t flags)
860 {
861         nis_result *result;
862         int i;
863
864         if( ! flags)
865           flags = FOLLOW_LINKS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP;
866
867         for(i = 0; i<2;i++ ) {
868           alarm(60);            /* hopefully ok for long searches */
869           result = nis_list(nis_name, flags,NULL,NULL);
870
871           alarm(0);
872           CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
873
874           if (gotalarm)
875           {
876                 DEBUG(0,("NIS+ lookup time out\n"));
877                 nis_freeresult(result);
878                 return NULL;
879           }
880           if( !(flags & MASTER_ONLY) && NIS_RES_NUMOBJ(result) <= 0 ) {
881             /* nis replicas are not in sync perhaps?
882              * this can happen, if account was just added.
883              */
884             DEBUG(10,("will try master only\n"));
885             nis_freeresult(result);
886             flags |= MASTER_ONLY;
887           } else
888             break;
889         }
890         return result;
891 }
892
893 /***************************************************************
894  Start to enumerate the nisplus passwd list.
895  ****************************************************************/
896 BOOL pdb_setsampwent(BOOL update)
897 {
898         char *sp, * p = lp_smb_passwd_file();
899         pstring pfiletmp;
900
901         if( (sp = strrchr( p, '/' )) )
902           safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
903         else
904           safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
905         safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
906
907         pdb_endsampwent();      /* just in case */
908         global_nisp_ent.result = nisp_get_nis_list( pfiletmp, 0 );
909         global_nisp_ent.enum_entry = 0;
910         return global_nisp_ent.result != NULL ? True : False;
911 }
912
913 /***************************************************************
914  End enumeration of the nisplus passwd list.
915 ****************************************************************/
916 void pdb_endsampwent(void)
917 {
918   if( global_nisp_ent.result )
919     nis_freeresult(global_nisp_ent.result);
920   global_nisp_ent.result = NULL;
921   global_nisp_ent.enum_entry = 0;
922 }
923
924 /*************************************************************************
925  Routine to return the next entry in the nisplus passwd list.
926  *************************************************************************/
927 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
928 {
929   int enum_entry = (int)(global_nisp_ent.enum_entry);
930   nis_result *result = global_nisp_ent.result;
931   
932   if (user==NULL) {
933         DEBUG(0,("SAM_ACCOUNT is NULL.\n"));
934         return False;
935   }
936
937   if (result == NULL ||
938       enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ(result) - 1))
939   {
940         return False;
941   } 
942
943   if(!make_sam_from_nisp_object(user, &NIS_RES_OBJECT(result)[enum_entry]) )
944   {
945     DEBUG(0,("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
946         return False;
947   }
948   (int)(global_nisp_ent.enum_entry)++;
949   return True;
950 }
951
952 /*************************************************************************
953  Routine to search the nisplus passwd file for an entry matching the username
954  *************************************************************************/
955 BOOL pdb_getsampwnam(SAM_ACCOUNT * user, const char *sname)
956 {
957         /* Static buffers we will return. */
958         nis_result *result = NULL;
959         pstring nisname;
960         BOOL ret;
961         char *pfile = lp_smb_passwd_file();
962         int i;
963
964         if (!*pfile)
965         {
966                 DEBUG(0, ("No SMB password file set\n"));
967                 return False;
968         }
969         if( strrchr( pfile, '/') )
970                 pfile = strrchr( pfile, '/') + 1;
971
972         slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
973         DEBUG(10, ("search by nisname: %s\n", nisname));
974
975         /* Search the table. */
976
977         if(!(result = nisp_get_nis_list(nisname, 0)))
978         {
979                 return False;
980         }
981
982         ret = make_sam_from_nisresult(user, result);
983         nis_freeresult(result);
984
985         return ret;
986 }
987
988 /*************************************************************************
989  Routine to search the nisplus passwd file for an entry matching the username
990  *************************************************************************/
991 BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
992 {
993         nis_result *result;
994         char *nisname;
995         BOOL ret;
996         char *sp, *p = lp_smb_passwd_file();
997         pstring pfiletmp;
998
999         if (!*p)
1000         {
1001                 DEBUG(0, ("no SMB password file set\n"));
1002                 return False;
1003         }
1004
1005         if( (sp = strrchr( p, '/' )) )
1006           safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
1007         else
1008           safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
1009         safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1010
1011         nisname = make_nisname_from_user_rid(rid, pfiletmp);
1012
1013         DEBUG(10, ("search by rid: %s\n", nisname));
1014
1015         /* Search the table. */
1016
1017         if(!(result = nisp_get_nis_list(nisname, 0)))
1018         {
1019                 return False;
1020         }
1021
1022         ret = make_sam_from_nisresult(user, result);
1023         nis_freeresult(result);
1024
1025         return ret;
1026 }
1027
1028 /*************************************************************************
1029  Routine to search the nisplus passwd file for an entry matching the username
1030  *************************************************************************/
1031 BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
1032 {
1033         nis_result *result;
1034         char *nisname;
1035         BOOL ret;
1036         char *sp, *p = lp_smb_passwd_file();
1037         pstring pfiletmp;
1038
1039         if (!*p)
1040         {
1041                 DEBUG(0, ("no SMB password file set\n"));
1042                 return False;
1043         }
1044
1045         if( (sp = strrchr( p, '/' )) )
1046           safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
1047         else
1048           safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
1049         safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1050
1051         nisname = make_nisname_from_uid(uid, pfiletmp);
1052
1053         DEBUG(10, ("search by uid: %s\n", nisname));
1054
1055         /* Search the table. */
1056
1057         if(!(result = nisp_get_nis_list(nisname, 0)))
1058         {
1059                 return False;
1060         }
1061
1062         ret = make_sam_from_nisresult(user, result);
1063         nis_freeresult(result);
1064
1065         return ret;
1066 }
1067
1068 /*************************************************************************
1069  Routine to remove entry from the nisplus smbpasswd table
1070  *************************************************************************/
1071 BOOL pdb_delete_sam_account(const char *sname)
1072 {
1073   char *pfile = lp_smb_passwd_file();
1074   pstring nisname;
1075   nis_result *result, *delresult;
1076   nis_object *obj;
1077   int i;
1078   
1079   if (!*pfile)
1080     {
1081       DEBUG(0, ("no SMB password file set\n"));
1082       return False;
1083     }
1084   if( strrchr( pfile, '/') )
1085           pfile = strrchr( pfile, '/') + 1;
1086   
1087   slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
1088   
1089   /* Search the table. */
1090   
1091   if( !(result = nisp_get_nis_list(nisname,
1092                                    MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
1093                                    EXPAND_NAME|HARD_LOOKUP))) {
1094     return False;
1095   }
1096   
1097   if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
1098     /* User not found. */
1099     DEBUG(0,("user not found in NIS+\n"));
1100     nis_freeresult(result);
1101     return False;
1102   }
1103
1104   obj = NIS_RES_OBJECT(result);
1105   slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s", sname, obj->zo_name,
1106            obj->zo_domain);
1107
1108   DEBUG(10, ("removing name: %s\n", nisname));
1109   delresult = nis_remove_entry(nisname, obj, 
1110     MASTER_ONLY|REM_MULTIPLE|ALL_RESULTS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
1111   
1112   nis_freeresult(result);
1113
1114   if(delresult->status != NIS_SUCCESS) {
1115     DEBUG(0, ("NIS+ table update failed: %s %s\n",
1116           nisname, nis_sperrno(delresult->status)));
1117     nis_freeresult(delresult);
1118     return False;
1119   }
1120   nis_freeresult(delresult);
1121   return True;
1122 }
1123
1124 /************************************************************************
1125  Routine to add an entry to the nisplus passwd file.
1126 *************************************************************************/
1127 BOOL pdb_add_sam_account(const SAM_ACCOUNT * newpwd)
1128 {
1129   int local_user = 0;
1130   char           *pfile;
1131   pstring         pfiletmp;
1132   char           *nisname;
1133   nis_result     *result = NULL,
1134     *tblresult = NULL;
1135   nis_object new_obj;
1136   entry_col *ecol;
1137   int ta_maxcol;
1138   
1139   /*
1140    * 1. find user domain.
1141    *   a. try nis search in passwd.org_dir - if found use domain from result.
1142    *   b. try getpwnam. this may be needed if user is defined
1143    *      in /etc/passwd file (or elsewere) and not in passwd.org_dir.
1144    *      if found, use host default domain.
1145    *   c. exit with False - no such user.
1146    *
1147    * 2. add user
1148    *   a. find smbpasswd table
1149    *      search pfile in user domain if not found, try host default
1150    *      domain. 
1151    *   b. smbpasswd domain is found, fill data and add entry.
1152    *
1153    * pfile should contain ONLY table name, org_dir will be concated.
1154    * so, at first we will clear path prefix from pfile, and
1155    * then we will use pfiletmp as playground to put together full
1156    * nisname string.
1157    * such approach will make it possible to specify samba private dir
1158    * AND still use NIS+ table. as all domain related data is normally
1159    * stored in org_dir.DOMAIN, this should be ok do do.
1160    */
1161
1162   pfile = lp_smb_passwd_file();
1163   if( strrchr( pfile, '/') )
1164     pfile = strrchr( pfile, '/') + 1;
1165
1166   /*
1167    * Check if user is already there.
1168    */
1169   safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1170   safe_strcat(pfiletmp, ".org_dir",
1171               sizeof(pfiletmp)-strlen(pfiletmp)-1);
1172
1173   if(pdb_get_username(newpwd) != NULL) {
1174     nisname = make_nisname_from_name(pdb_get_username(newpwd),
1175                                      pfiletmp);
1176   } else {
1177     return False;
1178   }
1179
1180   if(!(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
1181                                   FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
1182     return False;
1183   }
1184   if (result->status != NIS_SUCCESS && 
1185       result->status != NIS_NOTFOUND) {
1186     DEBUG(3, ( "nis_list failure: %s: %s\n",
1187                nisname,  nis_sperrno(result->status)));
1188     nis_freeresult(result);
1189     return False;
1190   }   
1191
1192   if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
1193     {
1194       DEBUG(3, ("User already exists in NIS+ password db: %s\n",
1195                 pfile));
1196       nis_freeresult(result);
1197       return False;
1198     }
1199
1200   nis_freeresult(result); /* no such user, free results */
1201
1202   /*
1203    * check for user in unix password database. we need this to get
1204    * domain, where smbpasswd entry should be stored.
1205    */
1206
1207   nisname = make_nisname_from_name(pdb_get_username(newpwd),
1208                                      "passwd.org_dir");
1209   
1210   result = nisp_get_nis_list(nisname,
1211                              MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
1212                              EXPAND_NAME|HARD_LOOKUP);
1213   
1214   if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0)
1215     {
1216       DEBUG(3, ("nis_list failure: %s: %s\n", 
1217                 nisname,  nis_sperrno(result->status)));
1218       nis_freeresult(result);
1219
1220       if (!sys_getpwnam(pdb_get_username(newpwd))) {
1221         /* no such user in system! */
1222         return False;
1223       }
1224         /* 
1225          * user is defined, but not in passwd.org_dir.
1226          */
1227       local_user = 1;
1228     } else {
1229       safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1230       safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1231       safe_strcat(pfiletmp, NIS_RES_OBJECT(result)->zo_domain,
1232                   sizeof(pfiletmp)-strlen(pfiletmp)-1);
1233       nis_freeresult(result); /* not needed any more */
1234
1235       tblresult = nisp_get_nis_list(pfiletmp,
1236                                     MASTER_ONLY|FOLLOW_LINKS|\
1237                                     FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP); 
1238     }
1239
1240   if (local_user || tblresult->status != NIS_SUCCESS)
1241     {
1242       /*
1243        * no user domain or
1244        * smbpasswd table not found in user domain, fallback to
1245        * default domain.
1246        */
1247       if (!local_user) /* free previous failed search result */
1248         nis_freeresult(tblresult);
1249       
1250       safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1251       safe_strcat(pfiletmp, ".org_dir",
1252                   sizeof(pfiletmp)-strlen(pfiletmp)-1);
1253       tblresult = nis_lookup(pfiletmp, MASTER_ONLY|FOLLOW_LINKS|\
1254                              FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
1255       if (tblresult->status != NIS_SUCCESS)
1256         {
1257             /* still nothing. bail out */
1258           nis_freeresult(tblresult);
1259           DEBUG(3, ( "nis_lookup failure: %s\n",
1260                      nis_sperrno(tblresult->status)));
1261           return False;
1262         }
1263       /* we need full name for nis_add_entry() */
1264       safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
1265       safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
1266       safe_strcat(pfiletmp, NIS_RES_OBJECT(tblresult)->zo_domain,
1267                   sizeof(pfiletmp)-strlen(pfiletmp)-1);
1268     }
1269
1270   memset((char *)&new_obj, 0, sizeof (new_obj));
1271   /* fill entry headers */
1272   /* we do not free these. */
1273   new_obj.zo_name   = NIS_RES_OBJECT(tblresult)->zo_name;
1274   new_obj.zo_owner  = NIS_RES_OBJECT(tblresult)->zo_owner;
1275   new_obj.zo_group  = NIS_RES_OBJECT(tblresult)->zo_group;
1276   new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
1277   /* uints */
1278   new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
1279   new_obj.zo_ttl    = NIS_RES_OBJECT(tblresult)->zo_ttl;
1280
1281   new_obj.zo_data.zo_type = ENTRY_OBJ;
1282   new_obj.EN_data.en_type =
1283     NIS_RES_OBJECT(tblresult)->TA_data.ta_type;
1284
1285   ta_maxcol = NIS_RES_OBJECT(tblresult)->TA_data.ta_maxcol;
1286   
1287   if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
1288     DEBUG(0, ("memory allocation failure\n"));
1289     nis_freeresult(tblresult);
1290     return False;
1291   }
1292   
1293   memset((char *)ecol, 0, ta_maxcol*sizeof (entry_col));
1294   new_obj.EN_data.en_cols.en_cols_val = ecol;
1295   new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
1296   
1297   init_nisp_from_sam(&new_obj, newpwd, NULL);
1298   
1299   DEBUG(10, ( "add NIS+ entry: %s\n", nisname));
1300   result = nis_add_entry(pfiletmp, &new_obj, 0);
1301
1302   free(ecol); /* free allocated entry space */
1303   
1304   if (result->status != NIS_SUCCESS)
1305     {
1306       DEBUG(3, ( "NIS+ table update failed: %s\n",
1307                  nisname, nis_sperrno(result->status)));
1308       nis_freeresult(tblresult);
1309       nis_freeresult(result);
1310       return False;
1311     }
1312   
1313   nis_freeresult(tblresult);
1314   nis_freeresult(result);
1315   
1316   return True;
1317 }
1318
1319 /************************************************************************
1320  Routine to modify the nisplus passwd entry.
1321 ************************************************************************/
1322 BOOL pdb_update_sam_account(const SAM_ACCOUNT * newpwd, BOOL override)
1323 {
1324   nis_result *result, *addresult;
1325   nis_object *obj;
1326   nis_object new_obj;
1327   entry_col *ecol;
1328   int ta_maxcol;
1329   char *pfile = lp_smb_passwd_file();
1330   pstring nisname;
1331   int i;
1332
1333   if (!*pfile)
1334     {
1335       DEBUG(0, ("no SMB password file set\n"));
1336       return False;
1337     }
1338   if( strrchr( pfile, '/') )
1339           pfile = strrchr( pfile, '/') + 1;
1340   
1341   slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir",
1342            pdb_get_username(newpwd), pfile);
1343   
1344   DEBUG(10, ("search by name: %s\n", nisname));
1345   
1346   /* Search the table. */
1347   
1348   if( !(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
1349                                    FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
1350     return False;
1351   }
1352   
1353   if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
1354     /* User not found. */
1355     DEBUG(0,("user not found in NIS+\n"));
1356     nis_freeresult(result);
1357     return False;
1358   }
1359
1360   obj = NIS_RES_OBJECT(result);
1361   DEBUG(6,("entry found in %s\n", obj->zo_domain));
1362
1363   /* we must create new stub object with EN_MODIFIED flag.
1364      this is because obj from result is going to be freed and
1365      we do not want to break it or cause memory leaks or corruption.
1366   */
1367   
1368   memmove((char *)&new_obj, obj, sizeof (new_obj));
1369   ta_maxcol = obj->TA_data.ta_maxcol;
1370   
1371   if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
1372     DEBUG(0, ("memory allocation failure\n"));
1373     nis_freeresult(result);
1374     return False;
1375   }
1376
1377   memmove((char *)ecol, obj->EN_data.en_cols.en_cols_val,
1378           ta_maxcol*sizeof (entry_col));
1379   new_obj.EN_data.en_cols.en_cols_val = ecol;
1380   new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
1381
1382   if ( init_nisp_from_sam(&new_obj, newpwd, obj) == True ) {
1383     slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s",
1384            pdb_get_username(newpwd), pfile, obj->zo_domain);
1385
1386     DEBUG(10, ("NIS+ table update: %s\n", nisname));
1387     addresult =
1388       nis_modify_entry(nisname, &new_obj, 
1389                   MOD_SAMEOBJ | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
1390   
1391     if(addresult->status != NIS_SUCCESS) {
1392       DEBUG(0, ("NIS+ table update failed: %s %s\n",
1393                 nisname, nis_sperrno(addresult->status)));
1394       nis_freeresult(addresult);
1395       nis_freeresult(result);
1396       free(ecol);
1397       return False;
1398     }
1399     
1400     DEBUG(6,("password changed\n"));
1401     nis_freeresult(addresult);
1402   } else {
1403     DEBUG(6,("nothing to change!\n"));
1404   }
1405
1406   free(ecol);
1407   nis_freeresult(result);
1408   
1409   return True;
1410 }
1411  
1412 #else
1413  void nisplus_dummy_function(void);
1414  void nisplus_dummy_function(void) { } /* stop some compilers complaining */
1415 #endif /* WITH_NISPLUSSAM */
1416