]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/uam.c
Tru64 patch (Burkhard Schmidt)
[netatalk.git] / etc / afpd / uam.c
1 /*
2  * $Id: uam.c,v 1.10 2001-06-25 15:18:01 rufustfirefly Exp $
3  *
4  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif /* HAVE_UNISTD_H */
18 #ifdef HAVE_FCNTL_H
19 #include <fcntl.h>
20 #endif /* HAVE_FCNTL_H */
21 #include <ctype.h>
22 #include <syslog.h>
23 #include <sys/param.h>
24 #include <sys/time.h>
25 #ifdef HAVE_DLFCN_H
26 #include <dlfcn.h>
27 #endif /* HAVE_DLFCN_H */
28
29 #ifdef SHADOWPW
30 #include <shadow.h>
31 #endif /* SHADOWPW */
32
33 #include <netatalk/endian.h>
34 #include <atalk/asp.h>
35 #include <atalk/dsi.h>
36 #include <atalk/afp.h>
37 #include <atalk/util.h>
38
39 #include "globals.h"
40 #include "afp_config.h"
41 #include "auth.h"
42 #include "uam_auth.h"
43
44 #ifdef TRU64
45 #include <netdb.h>
46 #include <arpa/inet.h>
47 #endif /* TRU64 */
48
49 /* --- server uam functions -- */
50
51 /* uam_load. uams must have a uam_setup function. */
52 struct uam_mod *uam_load(const char *path, const char *name)
53 {
54   char buf[MAXPATHLEN + 1], *p;
55   struct uam_mod *mod;
56   void *module;
57
58   if ((module = mod_open(path)) == NULL) {
59     syslog(LOG_ERR, "uam_load(%s): failed to load: %s", name, mod_error());
60     return NULL;
61   }
62
63   if ((mod = (struct uam_mod *) malloc(sizeof(struct uam_mod))) == NULL) {
64     syslog(LOG_ERR, "uam_load(%s): malloc failed", name);
65     goto uam_load_fail;
66   }
67
68   strncpy(buf, name, sizeof(buf));
69   if ((p = strchr(buf, '.')))
70     *p = '\0';
71   if ((mod->uam_fcn = mod_symbol(module, buf)) == NULL) {
72     syslog(LOG_ERR, "uam_load(%s): mod_symbol error for symbol %s",
73            name,
74            buf);
75     goto uam_load_err;
76   }
77
78   if (mod->uam_fcn->uam_type != UAM_MODULE_SERVER) {
79     syslog(LOG_ERR, "uam_load(%s): attempted to load a non-server module",
80            name);
81     goto uam_load_err;
82   }
83
84   /* version check would go here */
85
86   if (!mod->uam_fcn->uam_setup || 
87       ((*mod->uam_fcn->uam_setup)(name) < 0)) {
88     syslog(LOG_ERR, "uam_load(%s): uam_setup failed", name);
89     goto uam_load_err;
90   }
91
92   mod->uam_module = module;
93   return mod;
94
95 uam_load_err:
96   free(mod);
97 uam_load_fail:
98   mod_close(module);
99   return NULL;
100 }
101
102 /* unload the module. we check for a cleanup function, but we don't
103  * die if one doesn't exist. however, things are likely to leak without one.
104  */
105 void uam_unload(struct uam_mod *mod)
106 {
107   if (mod->uam_fcn->uam_cleanup)
108     (*mod->uam_fcn->uam_cleanup)();
109   mod_close(mod->uam_module);
110   free(mod);
111 }
112
113 /* -- client-side uam functions -- */
114
115 /* set up stuff for this uam. */
116 int uam_register(const int type, const char *path, const char *name, ...)
117 {
118   va_list ap;
119   struct uam_obj *uam;
120
121   if (!name)
122     return -1;
123
124   /* see if it already exists. */
125   if ((uam = auth_uamfind(type, name, strlen(name)))) {
126     if (strcmp(uam->uam_path, path)) {
127       /* it exists, but it's not the same module. */
128       syslog(LOG_ERR, "uam_register: \"%s\" already loaded by %s",
129              name, path);
130       return -1;
131     }
132     uam->uam_count++;
133     return 0;
134   }
135   
136   /* allocate space for uam */
137   if ((uam = calloc(1, sizeof(struct uam_obj))) == NULL)
138     return -1;
139
140   uam->uam_name = name;
141   uam->uam_path = strdup(path);
142   uam->uam_count++;
143
144   va_start(ap, name);
145   switch (type) {
146   case UAM_SERVER_LOGIN: /* expect three arguments */
147     uam->u.uam_login.login = va_arg(ap, void *);
148     uam->u.uam_login.logincont = va_arg(ap, void *);
149     uam->u.uam_login.logout = va_arg(ap, void *);
150     break;
151   case UAM_SERVER_CHANGEPW: /* one argument */
152     uam->u.uam_changepw = va_arg(ap, void *);
153     break;
154   case UAM_SERVER_PRINTAUTH: /* x arguments */
155   default:
156     break;
157   }
158   va_end(ap);
159
160   /* attach to other uams */
161   if (auth_register(type, uam) < 0) {
162     free(uam->uam_path);
163     free(uam);
164     return -1;
165   }
166
167   return 0;
168 }
169
170 void uam_unregister(const int type, const char *name)
171 {
172   struct uam_obj *uam;
173
174   if (!name)
175     return;
176
177   uam = auth_uamfind(type, name, strlen(name));
178   if (!uam || --uam->uam_count > 0)
179     return;
180
181   auth_unregister(uam);
182   free(uam->uam_path);
183   free(uam);
184 }
185
186 /* --- helper functions for plugin uams --- */
187
188 struct passwd *uam_getname(char *name, const int len)
189 {
190   struct passwd *pwent;
191   char *user;
192   int i;
193
194   if ((pwent = getpwnam(name)))
195     return pwent;
196
197 #ifndef NO_REAL_USER_NAME
198   for (i = 0; i < len; i++)
199     name[i] = tolower(name[i]);
200
201   setpwent();
202   while ((pwent = getpwent())) {
203     if ((user = strchr(pwent->pw_gecos, ',')))
204       *user = '\0';
205     user = pwent->pw_gecos;
206
207     /* check against both the gecos and the name fields. the user
208      * might have just used a different capitalization. */
209     if ((strncasecmp(user, name, len) == 0) ||
210         (strncasecmp(pwent->pw_name, name, len) == 0)) {
211       strncpy(name, pwent->pw_name, len);
212       break;
213     }
214   }
215   endpwent();
216 #endif /* ! NO_REAL_USER_NAME */
217
218   /* os x server doesn't keep anything useful if we do getpwent */
219   return pwent ? getpwnam(name) : NULL;
220 }
221
222 int uam_checkuser(const struct passwd *pwd)
223 {
224   char *p;
225
226   if (!pwd || !pwd->pw_shell || (*pwd->pw_shell == '\0')) 
227     return -1;
228
229   while ((p = getusershell())) {
230     if ( strcmp( p, pwd->pw_shell ) == 0 ) 
231       break;
232   }
233   endusershell();
234
235 #ifdef DISABLE_SHELLCHECK
236   if (!p) {
237     syslog( LOG_INFO, "illegal shell %s for %s", pwd->pw_shell, pwd->pw_name);
238     return -1;
239   }
240 #endif /* DISABLE_SHELLCHECK */
241
242   return 0;
243 }
244
245 /* afp-specific functions */
246 int uam_afpserver_option(void *private, const int what, void *option,
247                          int *len)
248 {
249   AFPObj *obj = private;
250   char **buf = (char **) option; /* most of the options are this */
251   int32_t result;
252   int fd;
253
254   if (!obj || !option)
255     return -1;
256
257   switch (what) {
258   case UAM_OPTION_USERNAME:
259     *buf = (void *) obj->username;
260     if (len) 
261       *len = sizeof(obj->username) - 1;
262     break;
263
264   case UAM_OPTION_GUEST:
265     *buf = (void *) obj->options.guest;
266     if (len) 
267       *len = strlen(obj->options.guest);
268     break;
269
270   case UAM_OPTION_PASSWDOPT:
271     if (!len)
272       return -1;
273
274     switch (*len) {
275     case UAM_PASSWD_FILENAME:
276       *buf = (void *) obj->options.passwdfile;
277       *len = strlen(obj->options.passwdfile);
278       break;
279
280     case UAM_PASSWD_MINLENGTH:
281       *((int *) option) = obj->options.passwdminlen;
282       *len = sizeof(obj->options.passwdminlen);
283       break;
284
285     case UAM_PASSWD_MAXFAIL: 
286       *((int *) option) = obj->options.loginmaxfail;
287       *len = sizeof(obj->options.loginmaxfail);
288       break;
289       
290     case UAM_PASSWD_EXPIRETIME: /* not implemented */
291     default:
292       return -1;
293     break;
294     }
295     break;
296
297   case UAM_OPTION_SIGNATURE:
298     *buf = (void *) (((AFPConfig *)obj->config)->signature);
299     if (len)
300       *len = 16;
301     break;
302
303   case UAM_OPTION_RANDNUM: /* returns a random number in 4-byte units. */
304     if (!len || (*len < 0) || (*len % sizeof(result)))
305       return -1;
306
307     /* construct a random number */
308     if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
309       struct timeval tv;
310       struct timezone tz;
311       char *randnum = (char *) option;
312       int i;
313     
314       if (gettimeofday(&tv, &tz) < 0)
315         return -1;
316       srandom(tv.tv_sec + (unsigned long) obj + (unsigned long) obj->handle);
317       for (i = 0; i < *len; i += sizeof(result)) {
318         result = random();
319         memcpy(randnum + i, &result, sizeof(result));
320       }
321     } else {
322       result = read(fd, option, *len);
323       close(fd);
324       if (result < 0)
325         return -1;
326     }
327     break;
328
329   case UAM_OPTION_HOSTNAME:
330     *buf = (void *) obj->options.hostname;
331     if (len) 
332       *len = strlen(obj->options.hostname);
333     break;
334
335   case UAM_OPTION_PROTOCOL:
336     *buf = (void *) obj->proto;
337     break;
338 #ifdef TRU64
339   case UAM_OPTION_CLIENTNAME:
340     {
341       struct DSI *dsi = obj->handle;
342       struct hostent *hp;
343
344       hp = gethostbyaddr( (char *) &dsi->client.sin_addr,
345                           sizeof( struct in_addr ),
346                           dsi->client.sin_family );
347       if( hp )
348           *buf = (void *) hp->h_name;
349       else
350           *buf = (void *) inet_ntoa( dsi->client.sin_addr );
351     }
352     break;
353 #endif /* TRU64 */
354   case UAM_OPTION_COOKIE: 
355     /* it's up to the uam to actually store something useful here.
356      * this just passes back a handle to the cookie. the uam side
357      * needs to do something like **buf = (void *) cookie to store
358      * the cookie. */
359     *buf = (void *) &obj->uam_cookie;
360     break;
361
362   default:
363     return -1;
364     break;
365   }
366
367   return 0;
368 }
369
370 /* if we need to maintain a connection, this is how we do it. 
371  * because an action pointer gets passed in, we can stream 
372  * DSI connections */
373 int uam_afp_read(void *handle, char *buf, int *buflen, 
374                  int (*action)(void *, void *, const int))
375 {
376   AFPObj *obj = handle;
377   int len;
378
379   if (!obj)
380     return AFPERR_PARAM;
381
382   switch (obj->proto) {
383     case AFPPROTO_ASP:
384       if ((len = asp_wrtcont(obj->handle, buf, buflen )) < 0) 
385         goto uam_afp_read_err;
386       return action(handle, buf, *buflen);
387       break;
388
389     case AFPPROTO_DSI:
390       len = dsi_writeinit(obj->handle, buf, *buflen);
391       if (!len || ((len = action(handle, buf, len)) < 0)) {
392         dsi_writeflush(obj->handle);
393         goto uam_afp_read_err;
394       }
395         
396       while ((len = (dsi_write(obj->handle, buf, *buflen)))) {
397         if ((len = action(handle, buf, len)) < 0) {
398           dsi_writeflush(obj->handle);
399           goto uam_afp_read_err;
400         }
401       }
402       break;
403   }
404   return 0;
405
406 uam_afp_read_err:
407   *buflen = 0;
408   return len;
409 }
410
411 #ifdef TRU64
412 void uam_afp_getcmdline( int *ac, char ***av )
413 {
414     afp_get_cmdline( ac, av );
415 }
416 #endif /* TRU64 */
417
418 /* --- papd-specific functions (just placeholders) --- */
419 void append(void *pf, char *data, int len)
420 {
421         return;
422 }