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