Makefile:
[ira/wip.git] / source3 / passdb / nispass.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  * 
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)
10  * any later version.
11  * 
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
15  * more details.
16  * 
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.
20  */
21
22 #ifdef USE_NISPLUS_DB
23
24 #include "includes.h"
25 #include <rpcsvc/nis.h>
26
27 extern int      DEBUGLEVEL;
28
29 static int gotalarm;
30
31 /***************************************************************
32  Signal function to tell us we timed out.
33 ****************************************************************/
34
35 static void gotalarm_sig(void)
36 {
37   gotalarm = 1;
38 }
39
40 /***************************************************************
41  Start to enumerate the nisplus passwd list. Returns a void pointer
42  to ensure no modification outside this module.
43
44  do not call this function directly.  use passdb.c instead.
45
46  ****************************************************************/
47 void *startnisppwent(BOOL update)
48 {
49         return NULL;
50 }
51
52 /***************************************************************
53  End enumeration of the nisplus passwd list.
54 ****************************************************************/
55 void endnisppwent(void *vp)
56 {
57 }
58
59 /*************************************************************************
60  Routine to return the next entry in the nisplus passwd list.
61  this function is a nice, messy combination of reading:
62  - the nisplus passwd file
63  - the unix password database
64  - nisp.conf options (not done at present).
65
66  do not call this function directly.  use passdb.c instead.
67
68  *************************************************************************/
69 struct sam_passwd *getnisp21pwent(void *vp)
70 {
71         return NULL;
72 }
73
74 /*************************************************************************
75  Routine to return the next entry in the nisplus passwd list.
76
77  do not call this function directly.  use passdb.c instead.
78
79  *************************************************************************/
80 struct smb_passwd *getnisppwent(void *vp)
81 {
82         DEBUG(5,("getnisppwent: end of file reached.\n"));
83         return NULL;
84 }
85
86 /*************************************************************************
87  Return the current position in the nisplus passwd list as an unsigned long.
88  This must be treated as an opaque token.
89
90  do not call this function directly.  use passdb.c instead.
91
92 *************************************************************************/
93 unsigned long getnisppwpos(void *vp)
94 {
95         return 0;
96 }
97
98 /*************************************************************************
99  Set the current position in the nisplus passwd list from unsigned long.
100  This must be treated as an opaque token.
101
102  do not call this function directly.  use passdb.c instead.
103
104 *************************************************************************/
105 BOOL setnisppwpos(void *vp, unsigned long tok)
106 {
107         return False;
108 }
109
110 /************************************************************************
111  Routine to add an entry to the nisplus passwd file.
112
113  do not call this function directly.  use passdb.c instead.
114
115 *************************************************************************/
116 BOOL add_nisp21pwd_entry(struct sam_passwd *newpwd)
117 {
118 }
119
120 /************************************************************************
121  Routine to add an entry to the nisplus passwd file.
122
123  do not call this function directly.  use passdb.c instead.
124
125 *************************************************************************/
126 BOOL add_nisppwd_entry(struct smb_passwd *newpwd)
127 {
128         /* Static buffers we will return. */
129         static pstring  user_name;
130
131         BOOL            add_user = True;
132         char           *pfile;
133         pstring nisname;
134         nis_result      *nis_user;
135         nis_result *result = NULL,
136         *tblresult = NULL, 
137         *addresult = NULL;
138         nis_object newobj, *obj, *user_obj;
139         char lmpwd[33], ntpwd[33];
140
141         pfile = lp_smb_passwd_file();
142
143         safe_strcpy(user_name, newpwd->smb_name, sizeof(user_name));
144
145         safe_strcpy(nisname, "[name=", sizeof(nisname));
146         safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) -1);
147         safe_strcat(nisname, "],passwd.org_dir", sizeof(nisname)-strlen(nisname)-1);
148
149         safe_strcpy(nisname, "[uid=", sizeof(nisname));
150         slprintf(nisname, sizeof(nisname), "%s%d", nisname, newpwd->smb_userid);
151         safe_strcat(nisname, "],passwd.org_dir", sizeof(nisname)-strlen(nisname)-1);
152
153         nis_user = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
154
155         if (nis_user->status != NIS_SUCCESS || NIS_RES_NUMOBJ(nis_user) <= 0)
156         {
157                 DEBUG(3, ("add_nisppwd_entry: Unable to get NIS+ passwd entry for user: %s.\n",
158                         nis_sperrno(nis_user->status)));
159                 return False;
160         }
161
162         /*
163         * Calculate the SMB (lanman) hash functions of both old and new passwords.
164         */
165
166         user_obj = NIS_RES_OBJECT(nis_user);
167
168         safe_strcpy(nisname, "[name=", sizeof(nisname));
169         safe_strcat(nisname, ENTRY_VAL(user_obj,0),sizeof(nisname)-strlen(nisname)-1);
170         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
171         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
172
173         result = nis_list(nisname, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP,NULL,NULL);
174         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
175         {
176                 DEBUG(3, ( "add_nisppwd_entry: nis_list failure: %s: %s\n",
177                             nisname,  nis_sperrno(result->status)));
178                 nis_freeresult(nis_user);
179                 nis_freeresult(result);
180                 return False;
181         }   
182
183         if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
184         {
185                 DEBUG(3, ("add_nisppwd_entry: User already exists in NIS+ password db: %s\n",
186                             pfile));
187                 nis_freeresult(result);
188                 nis_freeresult(nis_user);
189                 return False;
190         }
191
192         /* User not found. */
193
194         if (!add_user)
195         {
196                 DEBUG(3, ("add_nisppwd_entry: User not found in NIS+ password db: %s\n",
197                             pfile));
198                 nis_freeresult(result);
199                 nis_freeresult(nis_user);
200                 return False;
201         }
202
203         tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
204         if (tblresult->status != NIS_SUCCESS)
205         {
206                 nis_freeresult(result);
207                 nis_freeresult(nis_user);
208                 nis_freeresult(tblresult);
209                 DEBUG(3, ( "add_nisppwd_entry: nis_lookup failure: %s\n",
210                             nis_sperrno(tblresult->status)));
211                 return False;
212         }
213
214         newobj.zo_name   = NIS_RES_OBJECT(tblresult)->zo_name;
215         newobj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
216         newobj.zo_owner  = NIS_RES_OBJECT(nis_user)->zo_owner;
217         newobj.zo_group  = NIS_RES_OBJECT(tblresult)->zo_group;
218         newobj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
219         newobj.zo_ttl    = NIS_RES_OBJECT(tblresult)->zo_ttl;
220
221         newobj.zo_data.zo_type = ENTRY_OBJ;
222
223         newobj.zo_data.objdata_u.en_data.en_type = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_type;
224         newobj.zo_data.objdata_u.en_data.en_cols.en_cols_len = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_maxcol;
225         newobj.zo_data.objdata_u.en_data.en_cols.en_cols_val = calloc(newobj.zo_data.objdata_u.en_data.en_cols.en_cols_len, sizeof(entry_col));
226
227         ENTRY_VAL(&newobj, 0) = ENTRY_VAL(user_obj, 0);
228         ENTRY_LEN(&newobj, 0) = ENTRY_LEN(user_obj, 0);
229
230         ENTRY_VAL(&newobj, 1) = ENTRY_VAL(user_obj, 2);
231         ENTRY_LEN(&newobj, 1) = ENTRY_LEN(user_obj, 2);
232
233         ENTRY_VAL(&newobj, 2) = lmpwd;
234         ENTRY_LEN(&newobj, 2) = strlen(lmpwd);
235         newobj.EN_data.en_cols.en_cols_val[2].ec_flags = EN_CRYPT;
236
237         ENTRY_VAL(&newobj, 3) = ntpwd;
238         ENTRY_LEN(&newobj, 3) = strlen(ntpwd);
239         newobj.EN_data.en_cols.en_cols_val[3].ec_flags = EN_CRYPT;
240
241         ENTRY_VAL(&newobj, 4) = ENTRY_VAL(user_obj, 4);
242         ENTRY_LEN(&newobj, 4) = ENTRY_LEN(user_obj, 4);
243
244         ENTRY_VAL(&newobj, 5) = ENTRY_VAL(user_obj, 5);
245         ENTRY_LEN(&newobj, 5) = ENTRY_LEN(user_obj, 5);
246
247         ENTRY_VAL(&newobj, 6) = ENTRY_VAL(user_obj, 6);
248         ENTRY_LEN(&newobj, 6) = ENTRY_LEN(user_obj, 6);
249
250         obj = &newobj;
251
252         addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
253
254         nis_freeresult(nis_user);
255         if (tblresult)
256         {
257                 nis_freeresult(tblresult);
258         }
259
260         if (addresult->status != NIS_SUCCESS)
261         {
262                 DEBUG(3, ( "add_nisppwd_entry: NIS+ table update failed: %s\n",
263                             nisname, nis_sperrno(addresult->status)));
264                 nis_freeresult(addresult);
265                 nis_freeresult(result);
266                 return False;
267         }
268
269         nis_freeresult(addresult);
270         nis_freeresult(result);
271
272         return True;
273 }
274
275 /************************************************************************
276  Routine to search the nisplus passwd file for an entry matching the username.
277  and then modify its password entry. We can't use the startnisppwent()/
278  getnisppwent()/endnisppwent() interfaces here as we depend on looking
279  in the actual file to decide how much room we have to write data.
280  override = False, normal
281  override = True, override XXXXXXXX'd out password or NO PASS
282
283  do not call this function directly.  use passdb.c instead.
284
285 ************************************************************************/
286 BOOL mod_nisp21pwd_entry(struct sam_passwd* pwd, BOOL override)
287 {
288         return False;
289 }
290  
291 /************************************************************************
292  Routine to search the nisplus passwd file for an entry matching the username.
293  and then modify its password entry. We can't use the startnisppwent()/
294  getnisppwent()/endnisppwent() interfaces here as we depend on looking
295  in the actual file to decide how much room we have to write data.
296  override = False, normal
297  override = True, override XXXXXXXX'd out password or NO PASS
298
299  do not call this function directly.  use passdb.c instead.
300
301 ************************************************************************/
302 BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override)
303 {
304         return False;
305 }
306  
307 /************************************************************************
308  makes a struct smb_passwd from a NIS+ result.
309  ************************************************************************/
310 static BOOL make_smb_from_nisp(struct smb_passwd *pw_buf, nis_result *result)
311 {
312         int uidval;
313         static pstring  user_name;
314         static unsigned char smbpwd[16];
315         static unsigned char smbntpwd[16];
316         nis_object *obj;
317         uchar *p;
318
319         if (pw_buf == NULL || result == NULL) return False;
320
321         bzero(pw_buf, sizeof(*pw_buf));
322
323         if (result->status != NIS_SUCCESS)
324         {
325                 DEBUG(0, ("make_smb_from_nisp: NIS+ lookup failure: %s\n",
326                            nis_sperrno(result->status)));
327                 return False;
328         }
329
330         /* User not found. */
331         if (NIS_RES_NUMOBJ(result) <= 0)
332         {
333                 DEBUG(10, ("make_smb_from_nisp: user not found in NIS+\n"));
334                 return False;
335         }
336
337         if (NIS_RES_NUMOBJ(result) > 1)
338         {
339                 DEBUG(10, ("make_smb_from_nisp: WARNING: Multiple entries for user in NIS+ table!\n"));
340         }
341
342         /* Grab the first hit. */
343         obj = &NIS_RES_OBJECT(result)[0];
344
345         /* Check the lanman password column. */
346         p = (uchar *)ENTRY_VAL(obj, 2);
347         if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbpwd))
348         {
349                 DEBUG(0, ("make_smb_from_nisp: malformed LM pwd entry.\n"));
350                 return False;
351         }
352
353         /* Check the NT password column. */
354         p = (uchar *)ENTRY_VAL(obj, 3);
355         if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbntpwd))
356         {
357                 DEBUG(0, ("make_smb_from_nisp: malformed NT pwd entry\n"));
358                 return False;
359         }
360
361         strncpy(user_name, ENTRY_VAL(obj, 0), sizeof(user_name));
362         uidval = atoi(ENTRY_VAL(obj, 1));
363
364         pw_buf->smb_name      = user_name;
365         pw_buf->smb_userid    = uidval;         
366         pw_buf->smb_passwd    = smbpwd;
367         pw_buf->smb_nt_passwd = smbntpwd;
368
369         return True;
370 }
371
372 /*************************************************************************
373  Routine to search the nisplus passwd file for an entry matching the username
374  *************************************************************************/
375 struct smb_passwd *getnisppwnam(char *name)
376 {
377         /* Static buffers we will return. */
378         static struct smb_passwd pw_buf;
379         nis_result *result;
380         pstring nisname;
381         BOOL ret;
382
383         if (!*lp_smb_passwd_file())
384         {
385                 DEBUG(0, ("No SMB password file set\n"));
386                 return NULL;
387         }
388
389         DEBUG(10, ("getnisppwnam: search by name: %s\n", name));
390         DEBUG(10, ("getnisppwnam: using NIS+ table %s\n", lp_smb_passwd_file()));
391
392         slprintf(nisname, sizeof(nisname), "[name=%s],%s", name, lp_smb_passwd_file());
393
394         /* Search the table. */
395         gotalarm = 0;
396         signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
397         alarm(5);
398
399         result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
400
401         alarm(0);
402         signal(SIGALRM, SIGNAL_CAST SIG_DFL);
403
404         if (gotalarm)
405         {
406                 DEBUG(0,("getnisppwnam: NIS+ lookup time out\n"));
407                 nis_freeresult(result);
408                 return NULL;
409         }
410
411         ret = make_smb_from_nisp(&pw_buf, result);
412         nis_freeresult(result);
413
414         return ret ? &pw_buf : NULL;
415 }
416
417 /*************************************************************************
418  Routine to search the nisplus passwd file for an entry matching the username
419  *************************************************************************/
420 struct smb_passwd *getnisppwuid(int smb_userid)
421 {
422         /* Static buffers we will return. */
423         static struct smb_passwd pw_buf;
424         nis_result *result;
425         pstring nisname;
426         BOOL ret;
427
428         if (!*lp_smb_passwd_file())
429         {
430                 DEBUG(0, ("No SMB password file set\n"));
431                 return NULL;
432         }
433
434         DEBUG(10, ("getnisppwuid: search by uid: %d\n", smb_userid));
435         DEBUG(10, ("getnisppwuid: using NIS+ table %s\n", lp_smb_passwd_file()));
436
437         slprintf(nisname, sizeof(nisname), "[uid=%d],%s", smb_userid, lp_smb_passwd_file());
438
439         /* Search the table. */
440         gotalarm = 0;
441         signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
442         alarm(5);
443
444         result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
445
446         alarm(0);
447         signal(SIGALRM, SIGNAL_CAST SIG_DFL);
448
449         if (gotalarm)
450         {
451                 DEBUG(0,("getnisppwuid: NIS+ lookup time out\n"));
452                 nis_freeresult(result);
453                 return NULL;
454         }
455
456         ret = make_smb_from_nisp(&pw_buf, result);
457         nis_freeresult(result);
458
459         return ret ? &pw_buf : NULL;
460 }
461
462 #else
463 static void dummy_function(void) { } /* stop some compilers complaining */
464 #endif /* USE_NISPLUS_DB */