2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: bsd-security.c,v 1.54 2006/03/09 16:51:41 martinea Exp $
29 * "BSD" security module
45 #define bsdprintf(x) dbprintf(x)
51 #undef DUMPER_SOCKET_BUFFERING
54 #ifdef BSD_SECURITY /* { */
57 * Change the following from #undef to #define to cause detailed logging
58 * of the security steps, e.g. into /tmp/amanda/amandad*debug.
60 #undef SHOW_SECURITY_DETAIL
62 #if defined(TEST) /* { */
63 #define SHOW_SECURITY_DETAIL
65 #define bsdprintf(p) printf p
69 * This is the private handle data
73 * This must be first. Instances of bsd_handle will be cast to
74 * security_handle_t's.
76 security_handle_t sech;
79 * protocol handle for this request. Each request gets its own
80 * handle, so we differentiate packets for them with a "handle" header
84 int event_id; /* unique event_id */
93 * The remote host we're transmitting to
96 struct sockaddr_in peer;
99 * Function to call when recvpkt detects new incoming data for this
102 void (*fn) P((void *, pkt_t *, security_status_t));
105 * Argument for previous function
110 * read (EV_WAIT) handle for a recv
112 event_handle_t *ev_read;
115 * Timeout handle for a recv
117 event_handle_t *ev_timeout;
119 struct bsd_handle *prev, *next;
122 struct bsd_handle *bh_first=NULL, *bh_last=NULL;
125 * This is the internal security_stream data
129 * This must be first, because instances of this will be cast
130 * to security_stream_t's outside of this module.
132 security_stream_t secstr;
135 * This is the file descriptor which we will do io on
140 * This is the file descriptor which we will listen for incoming
141 * connections on (for streams which receive connections)
146 * This is the local port this stream is bound to
151 * This is the read event handle for this data stream
153 event_handle_t *ev_read;
156 * This is the function and argument that is called when this stream
157 * is readable. It is passed a buffer of data read.
159 void (*fn) P((void *, void *, ssize_t));
163 * This is the buffer that we read data into that will be passed
164 * to the read callback.
166 char databuf[NETWORK_BLOCK_BYTES];
170 * Interface functions
172 static void bsd_connect P((const char *,
173 char *(*)(char *, void *),
174 void (*)(void *, security_handle_t *, security_status_t), void *));
175 static void bsd_accept P((int, int, void (*)(security_handle_t *, pkt_t *)));
176 static void bsd_close P((void *));
177 static int bsd_sendpkt P((void *, pkt_t *));
178 static void bsd_recvpkt P((void *,
179 void (*)(void *, pkt_t *, security_status_t), void *, int));
180 static void bsd_recvpkt_cancel P((void *));
182 static void *bsd_stream_server P((void *));
183 static int bsd_stream_accept P((void *));
184 static void *bsd_stream_client P((void *, int));
185 static void bsd_stream_close P((void *));
186 static int bsd_stream_auth P((void *));
187 static int bsd_stream_id P((void *));
188 static int bsd_stream_write P((void *, const void *, size_t));
189 static void bsd_stream_read P((void *, void (*)(void *, void *, ssize_t),
191 static void bsd_stream_read_cancel P((void *));
194 * This is our interface to the outside world
196 const security_driver_t bsd_security_driver = {
212 bsd_stream_read_cancel,
216 * This is data local to the datagram socket. We have one datagram
217 * per process, so it is global.
220 dgram_t dgram; /* datagram to read/write from */
221 struct sockaddr_in peer; /* who sent it to us */
222 pkt_t pkt; /* parsed form of dgram */
223 char *handle; /* handle from recvd packet */
224 int sequence; /* seq no of packet */
225 event_handle_t *ev_read; /* read event handle from dgram */
226 int refcnt; /* number of handles blocked for reading */
229 /* generate new handles from here */
230 static int newhandle = 0;
231 static int newevent = 0;
234 * We register one event handler for our network fd which takes
235 * care of all of our async requests. When all async requests
236 * have either been satisfied or cancelled, we unregister our
237 * network event handler.
239 #define netfd_addref() do { \
240 if (netfd.refcnt++ == 0) { \
241 assert(netfd.ev_read == NULL); \
242 netfd.ev_read = event_register(netfd.dgram.socket, EV_READFD, \
243 netfd_read_callback, NULL); \
245 assert(netfd.refcnt > 0); \
249 * If this is the last request to be removed, then remove the
250 * reader event from the netfd.
252 #define netfd_delref() do { \
253 assert(netfd.refcnt > 0); \
254 if (--netfd.refcnt == 0) { \
255 assert(netfd.ev_read != NULL); \
256 event_release(netfd.ev_read); \
257 netfd.ev_read = NULL; \
262 * This is the function and argument that is called when new requests
263 * arrive on the netfd.
265 static void (*accept_fn) P((security_handle_t *, pkt_t *));
268 * These are the internal helper functions
270 static char *check_user P((struct bsd_handle *, const char *));
271 static int inithandle P((struct bsd_handle *, struct hostent *,
273 static const char *pkthdr2str P((const struct bsd_handle *, const pkt_t *));
274 static int str2pkthdr P((void));
275 static void netfd_read_callback P((void *));
276 static void recvpkt_callback P((void *));
277 static void recvpkt_timeout P((void *));
278 static int recv_security_ok P((struct bsd_handle *));
279 static void stream_read_callback P((void *));
282 #if defined(SHOW_SECURITY_DETAIL) /* { */
284 * Display stat() information about a file.
286 void show_stat_info(a, b)
289 char *name = vstralloc(a, b, NULL);
291 struct passwd *pwptr;
296 if (stat(name, &sbuf) != 0) {
297 bsdprintf(("%s: cannot stat %s: %s\n",
298 debug_prefix_time(NULL), name, strerror(errno)));
302 if ((pwptr = getpwuid(sbuf.st_uid)) == NULL) {
303 owner = alloc(NUM_STR_SIZE + 1);
304 snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_uid);
306 owner = stralloc(pwptr->pw_name);
308 if ((grptr = getgrgid(sbuf.st_gid)) == NULL) {
309 group = alloc(NUM_STR_SIZE + 1);
310 snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid);
312 group = stralloc(grptr->gr_name);
314 bsdprintf(("%s: processing file: %s\n", debug_prefix(NULL), name));
315 bsdprintf(("%s: owner=%s group=%s mode=%03o\n",
316 debug_prefix(NULL), owner, group, (int) (sbuf.st_mode & 0777)));
324 * Setup and return a handle outgoing to a client
327 bsd_connect(hostname, conf_fn, fn, arg)
328 const char *hostname;
329 char *(*conf_fn) P((char *, void *));
330 void (*fn) P((void *, security_handle_t *, security_status_t));
333 struct bsd_handle *bh;
337 struct timeval sequence_time;
338 amanda_timezone dontcare;
342 assert(hostname != NULL);
344 bh = alloc(sizeof(*bh));
345 bh->proto_handle=NULL;
346 security_handleinit(&bh->sech, &bsd_security_driver);
349 * Only init the socket once
351 if (netfd.dgram.socket == 0) {
353 dgram_zero(&netfd.dgram);
357 dgram_bind(&netfd.dgram, &port);
360 * We must have a reserved port. Bomb if we didn't get one.
362 if (port >= IPPORT_RESERVED) {
363 security_seterror(&bh->sech,
364 "unable to bind to a reserved port (got port %d)",
366 (*fn)(arg, &bh->sech, S_ERROR);
371 if ((he = gethostbyname(hostname)) == NULL) {
372 security_seterror(&bh->sech,
373 "%s: could not resolve hostname", hostname);
374 (*fn)(arg, &bh->sech, S_ERROR);
377 if ((se = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL)
378 port = htons(AMANDA_SERVICE_DEFAULT);
381 amanda_gettimeofday(&sequence_time, &dontcare);
382 sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
384 snprintf(handle,14,"000-%08x", newhandle++);
385 if (inithandle(bh, he, port, handle, sequence) < 0)
386 (*fn)(arg, &bh->sech, S_ERROR);
388 (*fn)(arg, &bh->sech, S_OK);
392 * Setup to accept new incoming connections
395 bsd_accept(in, out, fn)
397 void (*fn) P((security_handle_t *, pkt_t *));
400 assert(in >= 0 && out >= 0);
404 * We assume in and out point to the same socket, and just use
407 dgram_socket(&netfd.dgram, in);
410 * Assign the function and return. When they call recvpkt later,
411 * the recvpkt callback will call this function when it discovers
412 * new incoming connections
420 * Given a hostname and a port, setup a bsd_handle
423 inithandle(bh, he, port, handle, sequence)
424 struct bsd_handle *bh;
436 * Save the hostname and port info
438 strncpy(bh->hostname, he->h_name, sizeof(bh->hostname) - 1);
439 bh->hostname[sizeof(bh->hostname) - 1] = '\0';
440 bh->peer.sin_addr = *(struct in_addr *)he->h_addr;
441 bh->peer.sin_port = port;
442 bh->peer.sin_family = AF_INET;
445 if(bh_last) {bh->prev->next = bh;}
446 if(!bh_first) {bh_first = bh;}
451 * Do a forward lookup of the hostname. This is unnecessary if we
452 * are initiating the connection, but is very serious if we are
453 * receiving. We want to make sure the hostname
454 * resolves back to the remote ip for security reasons.
456 if ((he = gethostbyname(bh->hostname)) == NULL) {
457 security_seterror(&bh->sech,
458 "%s: could not resolve hostname", bh->hostname);
462 * Make sure the hostname matches. This should always work.
464 if (strncasecmp(bh->hostname, he->h_name, strlen(bh->hostname)) != 0) {
465 security_seterror(&bh->sech,
466 "%s: did not resolve to %s", bh->hostname, bh->hostname);
471 * Now look for a matching ip address.
473 for (i = 0; he->h_addr_list[i] != NULL; i++) {
474 if (memcmp(&bh->peer.sin_addr, he->h_addr_list[i],
475 sizeof(struct in_addr)) == 0) {
481 * If we didn't find it, try the aliases. This is a workaround for
482 * Solaris if DNS goes over NIS.
484 if (he->h_addr_list[i] == NULL) {
485 const char *ipstr = inet_ntoa(bh->peer.sin_addr);
486 for (i = 0; he->h_aliases[i] != NULL; i++) {
487 if (strcmp(he->h_aliases[i], ipstr) == 0)
491 * No aliases either. Failure. Someone is fooling with us or
494 if (he->h_aliases[i] == NULL) {
495 security_seterror(&bh->sech,
496 "DNS check failed: no matching ip address for %s",
502 bh->sequence = sequence;
503 bh->event_id = newevent++;
504 bh->proto_handle = handle;
508 bh->ev_timeout = NULL;
510 bsdprintf(("%s: adding handle '%s'\n",
511 debug_prefix_time(NULL), bh->proto_handle));
517 * Frees a handle allocated by the above
523 struct bsd_handle *bh = cookie;
525 if(bh->proto_handle == NULL) {
529 bsdprintf(("%s: close handle '%s'\n",
530 debug_prefix_time(NULL), bh->proto_handle));
532 bsd_recvpkt_cancel(bh);
534 bh->next->prev = bh->prev;
540 bh->prev->next = bh->next;
550 * Transmit a packet. Add security information first.
553 bsd_sendpkt(cookie, pkt)
557 struct bsd_handle *bh = cookie;
564 * Initialize this datagram, and add the header
566 dgram_zero(&netfd.dgram);
567 dgram_cat(&netfd.dgram, pkthdr2str(bh, pkt));
570 * Add the security info. This depends on which kind of packet we're
576 * Requests get sent with our username in the body
578 if ((pwd = getpwuid(geteuid())) == NULL) {
579 security_seterror(&bh->sech,
580 "can't get login name for my uid %ld", (long)getuid());
583 dgram_cat(&netfd.dgram, "SECURITY USER %s\n", pwd->pw_name);
591 * Add the body, and send it
593 dgram_cat(&netfd.dgram, pkt->body);
594 if (dgram_send_addr(bh->peer, &netfd.dgram) != 0) {
595 security_seterror(&bh->sech,
596 "send %s to %s failed: %s", pkt_type2str(pkt->type),
597 bh->hostname, strerror(errno));
604 * Set up to receive a packet asynchronously, and call back when it has
608 bsd_recvpkt(cookie, fn, arg, timeout)
610 void (*fn) P((void *, pkt_t *, security_status_t));
613 struct bsd_handle *bh = cookie;
620 * Subsequent recvpkt calls override previous ones
622 if (bh->ev_read == NULL) {
624 bh->ev_read = event_register(bh->event_id, EV_WAIT,
625 recvpkt_callback, bh);
627 if (bh->ev_timeout != NULL)
628 event_release(bh->ev_timeout);
630 bh->ev_timeout = NULL;
632 bh->ev_timeout = event_register(timeout, EV_TIME, recvpkt_timeout, bh);
638 * Remove a async receive request on this handle from the queue.
639 * If it is the last one to be removed, then remove the event
640 * handler for our network fd
643 bsd_recvpkt_cancel(cookie)
646 struct bsd_handle *bh = cookie;
650 if (bh->ev_read != NULL) {
652 event_release(bh->ev_read);
656 if (bh->ev_timeout != NULL) {
657 event_release(bh->ev_timeout);
658 bh->ev_timeout = NULL;
663 * Callback for received packets. This is the function bsd_recvpkt
664 * registers with the event handler. It is called when the event handler
665 * realizes that data is waiting to be read on the network socket.
668 netfd_read_callback(cookie)
671 struct bsd_handle *bh;
675 assert(cookie == NULL);
679 * Receive the packet.
681 dgram_zero(&netfd.dgram);
682 if (dgram_recv(&netfd.dgram, 0, &netfd.peer) < 0)
684 #endif /* !TEST */ /* } */
689 if (str2pkthdr() < 0)
693 * If there are events waiting on this handle, we're done
696 while(bh != NULL && (strcmp(bh->proto_handle, netfd.handle) != 0 ||
697 bh->sequence != netfd.sequence ||
698 bh->peer.sin_addr.s_addr != netfd.peer.sin_addr.s_addr ||
699 bh->peer.sin_port != netfd.peer.sin_port)) {
702 if (bh && event_wakeup(bh->event_id) > 0)
706 * If we didn't find a handle, then check for a new incoming packet.
707 * If no accept handler was setup, then just return.
709 if (accept_fn == NULL)
712 he = gethostbyaddr((void *)&netfd.peer.sin_addr,
713 (int)sizeof(netfd.peer.sin_addr), AF_INET);
716 bh = alloc(sizeof(*bh));
717 bh->proto_handle=NULL;
718 security_handleinit(&bh->sech, &bsd_security_driver);
726 bh->next->prev = bh->prev;
732 bh->prev->next = bh->next;
738 bsdprintf(("%s: closeX handle '%s'\n",
739 debug_prefix_time(NULL), bh->proto_handle));
745 * Check the security of the packet. If it is bad, then pass NULL
746 * to the accept function instead of a packet.
748 if (recv_security_ok(bh) < 0)
749 (*accept_fn)(&bh->sech, NULL);
751 (*accept_fn)(&bh->sech, &netfd.pkt);
755 * This is called when a handle is woken up because data read off of the
759 recvpkt_callback(cookie)
762 struct bsd_handle *bh = cookie;
763 void (*fn) P((void *, pkt_t *, security_status_t));
767 bsdprintf(("%s: receive handle '%s' netfd '%s'\n",
768 debug_prefix_time(NULL), bh->proto_handle,netfd.handle));
770 if(strcmp(bh->proto_handle,netfd.handle) != 0) assert(1);
772 /* if it didn't come from the same host/port, forget it */
773 if (memcmp(&bh->peer.sin_addr, &netfd.peer.sin_addr,
774 sizeof(netfd.peer.sin_addr)) != 0 ||
775 bh->peer.sin_port != netfd.peer.sin_port) {
781 * We need to cancel the recvpkt request before calling the callback
782 * because the callback may reschedule us.
786 bsd_recvpkt_cancel(bh);
789 * Check the security of the packet. If it is bad, then pass NULL
790 * to the packet handling function instead of a packet.
792 if (recv_security_ok(bh) < 0)
793 (*fn)(arg, NULL, S_ERROR);
795 (*fn)(arg, &netfd.pkt, S_OK);
799 * This is called when a handle times out before receiving a packet.
802 recvpkt_timeout(cookie)
805 struct bsd_handle *bh = cookie;
806 void (*fn) P((void *, pkt_t *, security_status_t));
811 assert(bh->ev_timeout != NULL);
814 bsd_recvpkt_cancel(bh);
815 (*fn)(arg, NULL, S_TIMEOUT);
820 * Check the security of a received packet. Returns negative on security
821 * violation, or returns 0 if ok. Removes the security info from the pkt_t.
825 struct bsd_handle *bh;
827 char *tok, *security, *body, *result;
828 pkt_t *pkt = &netfd.pkt;
831 * Set this preempively before we mangle the body.
833 security_seterror(&bh->sech,
834 "bad SECURITY line: '%s'", pkt->body);
837 * Now, find the SECURITY line in the body, and parse it out
840 if (strncmp(pkt->body, "SECURITY", sizeof("SECURITY") - 1) == 0) {
841 tok = strtok(pkt->body, " ");
842 assert(strcmp(tok, "SECURITY") == 0);
843 /* security info goes until the newline */
844 security = strtok(NULL, "\n");
845 body = strtok(NULL, "");
847 * If the body is f-ked, then try to recover
850 if (security != NULL)
851 body = security + strlen(security) + 2;
861 * We need to do different things depending on which type of packet
867 * Request packets must come from a reserved port
869 if (ntohs(bh->peer.sin_port) >= IPPORT_RESERVED) {
870 security_seterror(&bh->sech,
871 "host %s: port %d not secure", bh->hostname,
872 ntohs(bh->peer.sin_port));
877 * Request packets contain a remote username. We need to check
878 * that we allow it in.
880 * They will look like:
881 * SECURITY USER [username]
884 /* there must be some security info */
885 if (security == NULL) {
886 security_seterror(&bh->sech,
887 "no bsd SECURITY for P_REQ");
891 /* second word must be USER */
892 if ((tok = strtok(security, " ")) == NULL)
893 return (-1); /* default errmsg */
894 if (strcmp(tok, "USER") != 0) {
895 security_seterror(&bh->sech,
896 "REQ SECURITY line parse error, expecting USER, got %s", tok);
900 /* the third word is the username */
901 if ((tok = strtok(NULL, "")) == NULL)
902 return (-1); /* default errmsg */
903 if ((result = check_user(bh, tok)) != NULL) {
904 security_seterror(&bh->sech, "%s", result);
909 /* we're good to go */
916 * If there is security info at the front of the packet, we need to
917 * shift the rest of the data up and nuke it.
919 if (body != pkt->body)
920 memmove(pkt->body, body, strlen(body) + 1);
925 check_user(bh, remoteuser)
926 struct bsd_handle *bh;
927 const char *remoteuser;
932 char *localuser = NULL;
934 /* lookup our local user name */
935 if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
936 return vstralloc("getpwnam(", CLIENT_LOGIN, ") fails", NULL);
940 * Make a copy of the user name in case getpw* is called by
941 * any of the lower level routines.
943 localuser = stralloc(pwd->pw_name);
945 #ifndef USE_AMANDAHOSTS
946 r = check_user_ruserok(bh->hostname, pwd, remoteuser);
948 r = check_user_amandahosts(bh->hostname, pwd, remoteuser);
951 result = vstralloc("access as ", localuser, " not allowed",
952 " from ", remoteuser, "@", bh->hostname,
962 * See if a remote user is allowed in. This version uses ruserok()
965 * Returns 0 on success, or negative on error.
968 check_user_ruserok(host, pwd, remoteuser)
971 const char *remoteuser;
982 char number[NUM_STR_SIZE];
983 uid_t myuid = getuid();
986 * note that some versions of ruserok (eg SunOS 3.2) look in
987 * "./.rhosts" rather than "~CLIENT_LOGIN/.rhosts", so we have to
988 * chdir ourselves. Sigh.
990 * And, believe it or not, some ruserok()'s try an initgroup just
991 * for the hell of it. Since we probably aren't root at this point
992 * it'll fail, and initgroup "helpfully" will blatt "Setgroups: Not owner"
993 * into our stderr output even though the initgroup failure is not a
994 * problem and is expected. Thanks a lot. Not.
997 return stralloc2("pipe() fails: ", strerror(errno));
999 if ((ruserok_pid = fork()) < 0) {
1000 return stralloc2("fork() fails: ", strerror(errno));
1001 } else if (ruserok_pid == 0) {
1005 fError = fdopen(fd[1], "w");
1006 /* pamper braindead ruserok's */
1007 if (chdir(pwd->pw_dir) != 0) {
1008 fprintf(fError, "chdir(%s) failed: %s",
1009 pwd->pw_dir, strerror(errno));
1014 #if defined(SHOW_SECURITY_DETAIL) /* { */
1016 char *dir = stralloc(pwd->pw_dir);
1018 bsdprintf(("%s: calling ruserok(%s, %d, %s, %s)\n",
1019 debug_prefix_time(NULL),
1020 host, myuid == 0, remoteuser, pwd->pw_name));
1022 bsdprintf(("%s: because you are running as root, ",
1023 debug_prefix(NULL)));
1024 bsdprintf(("/etc/hosts.equiv will not be used\n"));
1026 show_stat_info("/etc/hosts.equiv", NULL);
1028 show_stat_info(dir, "/.rhosts");
1033 saved_stderr = dup(2);
1035 if (open("/dev/null", O_RDWR) == -1) {
1036 dbprintf(("Could not open /dev/null: %s\n",
1040 ok = ruserok(host, myuid == 0, remoteuser, CLIENT_LOGIN);
1047 (void)dup2(saved_stderr,2);
1048 close(saved_stderr);
1052 fError = fdopen(fd[0], "r");
1055 while ((es = agets(fError)) != NULL) {
1056 if (result == NULL) {
1057 result = stralloc("");
1059 strappend(result, ": ");
1061 strappend(result, es);
1066 if ((pid = wait(&exitcode)) == (pid_t) -1) {
1067 if (errno == EINTR) {
1071 return stralloc2("ruserok wait failed: %s", strerror(errno));
1073 if (pid == ruserok_pid) {
1077 if (WIFSIGNALED(exitcode)) {
1079 snprintf(number, sizeof(number), "%d", WTERMSIG(exitcode));
1080 return stralloc2("ruserok child got signal ", number);
1082 if (WEXITSTATUS(exitcode) == 0) {
1084 } else if (result == NULL) {
1085 result = stralloc("ruserok failed");
1092 * Check to see if a user is allowed in. This version uses .amandahosts
1093 * Returns -1 on failure, or 0 on success.
1096 check_user_amandahosts(host, pwd, remoteuser)
1099 const char *remoteuser;
1103 const char *fileuser;
1105 char *result = NULL;
1109 char n1[NUM_STR_SIZE];
1110 char n2[NUM_STR_SIZE];
1114 char *localuser = NULL;
1117 * Save copies of what we need from the passwd structure in case
1118 * any other code calls getpw*.
1120 localuid = pwd->pw_uid;
1121 localuser = stralloc(pwd->pw_name);
1123 ptmp = stralloc2(pwd->pw_dir, "/.amandahosts");
1124 #if defined(SHOW_SECURITY_DETAIL) /* { */
1125 show_stat_info(ptmp, "");;
1127 if ((fp = fopen(ptmp, "r")) == NULL) {
1128 result = vstralloc("cannot open ", ptmp, ": ", strerror(errno), NULL);
1135 * Make sure the file is owned by the Amanda user and does not
1136 * have any group/other access allowed.
1138 if (fstat(fileno(fp), &sbuf) != 0) {
1139 result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
1142 if (sbuf.st_uid != localuid) {
1143 snprintf(n1, sizeof(n1), "%ld", (long)sbuf.st_uid);
1144 snprintf(n2, sizeof(n2), "%ld", (long)localuid);
1145 result = vstralloc(ptmp, ": ",
1151 if ((sbuf.st_mode & 077) != 0) {
1152 result = stralloc2(ptmp,
1153 ": incorrect permissions; file must be accessible only by its owner");
1158 * Now, scan the file for the host/user.
1161 while ((line = agets(fp)) != NULL) {
1162 #if defined(SHOW_SECURITY_DETAIL) /* { */
1163 bsdprintf(("%s: processing line: <%s>\n", debug_prefix(NULL), line));
1165 /* get the host out of the file */
1166 if ((filehost = strtok(line, " \t")) == NULL) {
1171 /* get the username. If no user specified, then use the local user */
1172 if ((fileuser = strtok(NULL, " \t")) == NULL) {
1173 fileuser = localuser;
1176 hostmatch = (strcasecmp(filehost, host) == 0);
1177 usermatch = (strcasecmp(fileuser, remoteuser) == 0);
1178 #if defined(SHOW_SECURITY_DETAIL) /* { */
1179 bsdprintf(("%s: comparing \"%s\" with\n", debug_prefix(NULL), filehost));
1180 bsdprintf(("%s: \"%s\" (%s)\n", host,
1181 debug_prefix(NULL), hostmatch ? "match" : "no match"));
1182 bsdprintf(("%s: and \"%s\" with\n", fileuser, debug_prefix(NULL)));
1183 bsdprintf(("%s: \"%s\" (%s)\n", remoteuser,
1184 debug_prefix(NULL), usermatch ? "match" : "no match"));
1188 if (hostmatch && usermatch) {
1195 result = vstralloc(ptmp, ": ",
1196 "\"", host, " ", remoteuser, "\"",
1211 /* return 1 on success, 0 on failure */
1213 check_security(addr, str, cksum, errstr)
1214 struct sockaddr_in *addr;
1216 unsigned long cksum;
1219 char *remotehost = NULL, *remoteuser = NULL;
1220 char *bad_bsd = NULL;
1222 struct passwd *pwptr;
1229 /* what host is making the request? */
1231 hp = gethostbyaddr((char *)&addr->sin_addr, sizeof(addr->sin_addr),
1234 /* XXX include remote address in message */
1235 *errstr = vstralloc("[",
1236 "addr ", inet_ntoa(addr->sin_addr), ": ",
1237 "hostname lookup failed",
1241 remotehost = stralloc(hp->h_name);
1243 /* Now let's get the hostent for that hostname */
1244 hp = gethostbyname( remotehost );
1246 /* XXX include remote hostname in message */
1247 *errstr = vstralloc("[",
1248 "host ", remotehost, ": ",
1249 "hostname lookup failed",
1255 /* Verify that the hostnames match -- they should theoretically */
1256 if( strncasecmp( remotehost, hp->h_name, strlen(remotehost)+1 ) != 0 ) {
1257 *errstr = vstralloc("[",
1258 "hostnames do not match: ",
1259 remotehost, " ", hp->h_name,
1265 /* Now let's verify that the ip which gave us this hostname
1266 * is really an ip for this hostname; or is someone trying to
1267 * break in? (THIS IS THE CRUCIAL STEP)
1269 for (i = 0; hp->h_addr_list[i]; i++) {
1270 if (memcmp(hp->h_addr_list[i],
1271 (char *) &addr->sin_addr, sizeof(addr->sin_addr)) == 0)
1272 break; /* name is good, keep it */
1275 /* If we did not find it, your DNS is messed up or someone is trying
1276 * to pull a fast one on you. :(
1279 /* Check even the aliases list. Work around for Solaris if dns goes over NIS */
1281 if( !hp->h_addr_list[i] ) {
1282 for (j = 0; hp->h_aliases[j] !=0 ; j++) {
1283 if ( strcmp(hp->h_aliases[j],inet_ntoa(addr->sin_addr)) == 0)
1284 break; /* name is good, keep it */
1286 if( !hp->h_aliases[j] ) {
1287 *errstr = vstralloc("[",
1288 "ip address ", inet_ntoa(addr->sin_addr),
1289 " is not in the ip list for ", remotehost,
1297 /* next, make sure the remote port is a "reserved" one */
1299 if(ntohs(addr->sin_port) >= IPPORT_RESERVED) {
1300 char number[NUM_STR_SIZE];
1302 snprintf(number, sizeof(number), "%d", ntohs(addr->sin_port));
1303 *errstr = vstralloc("[",
1304 "host ", remotehost, ": ",
1305 "port ", number, " not secure",
1311 /* extract the remote user name from the message */
1316 bad_bsd = vstralloc("[",
1317 "host ", remotehost, ": ",
1318 "bad bsd security line",
1322 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1332 skip_whitespace(s, ch);
1340 skip_non_whitespace(s, ch);
1342 remoteuser = stralloc(fp);
1346 /* lookup our local user name */
1349 if((pwptr = getpwuid(myuid)) == NULL)
1350 error("error [getpwuid(%d) fails]", myuid);
1352 dbprintf(("bsd security: remote host %s user %s local user %s\n",
1353 remotehost, remoteuser, pwptr->pw_name));
1355 #ifndef USE_AMANDAHOSTS
1356 s = check_user_ruserok(remotehost, pwptr, remoteuser);
1358 s = check_user_amandahosts(remotehost, pwptr, remoteuser);
1362 *errstr = vstralloc("[",
1363 "access as ", pwptr->pw_name, " not allowed",
1364 " from ", remoteuser, "@", remotehost,
1365 ": ", s, "]", NULL);
1370 return *errstr == NULL;
1375 * Create the server end of a stream. For bsd, this means setup a tcp
1376 * socket for receiving a connection.
1379 bsd_stream_server(h)
1382 struct bsd_stream *bs = NULL;
1383 #ifndef TEST /* { */
1384 struct bsd_handle *bh = h;
1388 bs = alloc(sizeof(*bs));
1389 security_streaminit(&bs->secstr, &bsd_security_driver);
1390 bs->socket = stream_server(&bs->port, STREAM_BUFSIZE, STREAM_BUFSIZE);
1391 if (bs->socket < 0) {
1392 security_seterror(&bh->sech,
1393 "can't create server stream: %s", strerror(errno));
1399 #endif /* !TEST */ /* } */
1404 * Accepts a new connection on unconnected streams. Assumes it is ok to
1408 bsd_stream_accept(s)
1411 #ifndef TEST /* { */
1412 struct bsd_stream *bs = s;
1415 assert(bs->socket != -1);
1418 bs->fd = stream_accept(bs->socket, 30, -1, -1);
1420 security_stream_seterror(&bs->secstr,
1421 "can't accept new stream connection: %s", strerror(errno));
1424 #endif /* !TEST */ /* } */
1429 * Return a connected stream
1432 bsd_stream_client(h, id)
1436 struct bsd_stream *bs = NULL;
1437 #ifndef TEST /* { */
1438 struct bsd_handle *bh = h;
1439 #ifdef DUMPER_SOCKET_BUFFERING
1440 int rcvbuf = sizeof(bs->databuf) * 2;
1446 security_seterror(&bh->sech,
1447 "%d: invalid security stream id", id);
1451 bs = alloc(sizeof(*bs));
1452 security_streaminit(&bs->secstr, &bsd_security_driver);
1453 bs->fd = stream_client(bh->hostname, id, STREAM_BUFSIZE, STREAM_BUFSIZE,
1456 security_seterror(&bh->sech,
1457 "can't connect stream to %s port %d: %s", bh->hostname,
1458 id, strerror(errno));
1462 bs->socket = -1; /* we're a client */
1464 #ifdef DUMPER_SOCKET_BUFFERING
1465 setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf, sizeof(rcvbuf));
1467 #endif /* !TEST */ /* } */
1472 * Close and unallocate resources for a stream
1478 struct bsd_stream *bs = s;
1484 if (bs->socket != -1)
1486 bsd_stream_read_cancel(bs);
1491 * Authenticate a stream. bsd streams have no authentication
1498 return (0); /* success */
1502 * Returns the stream id for this stream. This is just the local port.
1508 struct bsd_stream *bs = s;
1516 * Write a chunk of data to a stream. Blocks until completion.
1519 bsd_stream_write(s, buf, size)
1524 #ifndef TEST /* { */
1525 struct bsd_stream *bs = s;
1529 if (fullwrite(bs->fd, buf, size) < 0) {
1530 security_stream_seterror(&bs->secstr,
1531 "write error on stream %d: %s", bs->port, strerror(errno));
1534 #endif /* !TEST */ /* } */
1539 * Submit a request to read some data. Calls back with the given function
1540 * and arg when completed.
1543 bsd_stream_read(s, fn, arg)
1545 void (*fn) P((void *, void *, ssize_t));
1547 struct bsd_stream *bs = s;
1550 * Only one read request can be active per stream.
1552 if (bs->ev_read != NULL)
1553 event_release(bs->ev_read);
1555 bs->ev_read = event_register(bs->fd, EV_READFD, stream_read_callback, bs);
1561 * Cancel a previous stream read request. It's ok if we didn't
1562 * have a read scheduled.
1565 bsd_stream_read_cancel(s)
1568 struct bsd_stream *bs = s;
1572 if (bs->ev_read != NULL) {
1573 event_release(bs->ev_read);
1579 * Callback for bsd_stream_read
1582 stream_read_callback(arg)
1585 struct bsd_stream *bs = arg;
1591 * Remove the event first, in case they reschedule it in the callback.
1593 bsd_stream_read_cancel(bs);
1595 n = read(bs->fd, bs->databuf, sizeof(bs->databuf));
1596 } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
1598 security_stream_seterror(&bs->secstr, strerror(errno));
1599 (*bs->fn)(bs->arg, bs->databuf, n);
1603 * Convert a packet header into a string
1607 const struct bsd_handle *bh;
1610 static char retbuf[256];
1613 assert(pkt != NULL);
1615 snprintf(retbuf, sizeof(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",
1616 VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),
1617 bh->proto_handle, bh->sequence);
1619 bsdprintf(("%s: pkthdr2str handle '%s'\n",
1620 debug_prefix_time(NULL), bh->proto_handle));
1622 /* check for truncation. If only we had asprintf()... */
1623 assert(retbuf[strlen(retbuf) - 1] == '\n');
1629 * Parses out the header line in 'str' into the pkt and handle
1630 * Returns negative on parse error.
1641 assert(netfd.dgram.cur != NULL);
1642 str = stralloc(netfd.dgram.cur);
1644 /* "Amanda %d.%d <ACK,NAK,...> HANDLE %s SEQ %d\n" */
1646 /* Read in "Amanda" */
1647 if ((tok = strtok(str, " ")) == NULL || strcmp(tok, "Amanda") != 0)
1650 /* nothing is done with the major/minor numbers currently */
1651 if ((tok = strtok(NULL, " ")) == NULL || strchr(tok, '.') == NULL)
1654 /* Read in the packet type */
1655 if ((tok = strtok(NULL, " ")) == NULL)
1657 pkt_init(pkt, pkt_str2type(tok), "");
1658 if (pkt->type == (pktype_t)-1)
1661 /* Read in "HANDLE" */
1662 if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "HANDLE") != 0)
1665 /* parse the handle */
1666 if ((tok = strtok(NULL, " ")) == NULL)
1668 netfd.handle = stralloc(tok);
1671 if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0)
1674 /* parse the sequence number */
1675 if ((tok = strtok(NULL, "\n")) == NULL)
1677 netfd.sequence = atoi(tok);
1679 /* Save the body, if any */
1680 if ((tok = strtok(NULL, "")) != NULL)
1681 pkt_cat(pkt, "%s", tok);
1687 #if 0 /* XXX we have no way of passing this back up */
1688 security_seterror(&bh->sech,
1689 "parse error in packet header : '%s'", origstr);
1695 #endif /* BSD_SECURITY */ /* } */
1697 #if defined(TEST) /* { */
1700 * The following dummy bind_portrange function is so we do not need to
1701 * drag in util.o just for the test program.
1704 bind_portrange(s, addrp, first_port, last_port, proto)
1706 struct sockaddr_in *addrp;
1707 int first_port, last_port;
1714 * Construct a datestamp (YYYYMMDD) from a time_t.
1717 construct_datestamp(t)
1721 char datestamp[3*NUM_STR_SIZE];
1725 when = time((time_t *)NULL);
1729 tm = localtime(&when);
1730 snprintf(datestamp, sizeof(datestamp),
1731 "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
1732 return stralloc(datestamp);
1736 * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
1739 construct_timestamp(t)
1743 char timestamp[6*NUM_STR_SIZE];
1747 when = time((time_t *)NULL);
1751 tm = localtime(&when);
1752 snprintf(timestamp, sizeof(timestamp),
1753 "%04d%02d%02d%02d%02d%02d",
1754 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
1755 tm->tm_hour, tm->tm_min, tm->tm_sec);
1756 return stralloc(timestamp);
1760 * The following are so we can include security.o but not all the rest
1761 * of the security modules.
1763 const security_driver_t krb4_security_driver = {};
1764 const security_driver_t krb5_security_driver = {};
1765 const security_driver_t rsh_security_driver = {};
1768 * This function will be called to accept the connection and is used
1769 * to report success or failure.
1771 static void fake_accept_function(handle, pkt)
1772 security_handle_t *handle;
1776 fputs(handle->error, stdout);
1777 fputc('\n', stdout);
1779 fputs("access is allowed\n", stdout);
1789 struct bsd_handle *bh;
1791 struct passwd *pwent;
1793 /* Don't die when child closes pipe */
1794 signal(SIGPIPE, SIG_IGN);
1797 * The following is stolen from amandad to emulate what it would
1800 if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) {
1801 client_uid = pwent->pw_uid;
1802 client_gid = pwent->pw_gid;
1807 /* we'd rather not run as root */
1808 if (geteuid() == 0) {
1809 if(client_uid == (uid_t) -1) {
1810 error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN);
1812 initgroups(CLIENT_LOGIN, client_gid);
1814 setegid(client_gid);
1815 seteuid(client_uid);
1817 #endif /* FORCE_USERID */
1820 fputs("Remote user: ", stdout);
1823 if ((remoteuser = agets(stdin)) == NULL) {
1828 fputs("Remote host: ", stdout);
1831 if ((remotehost = agets(stdin)) == NULL) {
1835 set_pname("security");
1838 if ((hp = gethostbyname(remotehost)) == NULL) {
1839 fprintf(stderr, "cannot look up remote host %s\n", remotehost);
1842 memcpy((char *)&netfd.peer.sin_addr,
1844 sizeof(hp->h_addr));
1846 * Fake that it is coming from a reserved port.
1848 netfd.peer.sin_port = htons(IPPORT_RESERVED - 1);
1850 bh = alloc(sizeof(*bh));
1851 bh->proto_handle=NULL;
1852 netfd.pkt.type = P_REQ;
1853 dgram_zero(&netfd.dgram);
1854 save_cur = netfd.dgram.cur; /* cheating */
1855 dgram_cat(&netfd.dgram, "%s", pkthdr2str(bh, &netfd.pkt));
1856 dgram_cat(&netfd.dgram, "SECURITY USER %s\n", remoteuser);
1857 netfd.dgram.cur = save_cur; /* cheating */
1859 accept_fn = fake_accept_function;
1860 netfd_read_callback(NULL);